summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/graphics
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/graphics')
-rw-r--r--Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp77
-rw-r--r--Source/WebCore/platform/graphics/ANGLEWebKitBridge.h63
-rw-r--r--Source/WebCore/platform/graphics/BitmapImage.cpp433
-rw-r--r--Source/WebCore/platform/graphics/BitmapImage.h289
-rw-r--r--Source/WebCore/platform/graphics/Color.cpp402
-rw-r--r--Source/WebCore/platform/graphics/Color.h196
-rw-r--r--Source/WebCore/platform/graphics/ColorSpace.h39
-rw-r--r--Source/WebCore/platform/graphics/ContextShadow.cpp266
-rw-r--r--Source/WebCore/platform/graphics/ContextShadow.h143
-rw-r--r--Source/WebCore/platform/graphics/DashArray.h39
-rw-r--r--Source/WebCore/platform/graphics/Extensions3D.h100
-rw-r--r--Source/WebCore/platform/graphics/FloatPoint.cpp75
-rw-r--r--Source/WebCore/platform/graphics/FloatPoint.h207
-rw-r--r--Source/WebCore/platform/graphics/FloatPoint3D.cpp42
-rw-r--r--Source/WebCore/platform/graphics/FloatPoint3D.h187
-rw-r--r--Source/WebCore/platform/graphics/FloatQuad.cpp105
-rw-r--r--Source/WebCore/platform/graphics/FloatQuad.h152
-rw-r--r--Source/WebCore/platform/graphics/FloatRect.cpp201
-rw-r--r--Source/WebCore/platform/graphics/FloatRect.h228
-rw-r--r--Source/WebCore/platform/graphics/FloatSize.cpp50
-rw-r--r--Source/WebCore/platform/graphics/FloatSize.h153
-rw-r--r--Source/WebCore/platform/graphics/Font.cpp474
-rw-r--r--Source/WebCore/platform/graphics/Font.h287
-rw-r--r--Source/WebCore/platform/graphics/FontBaseline.h35
-rw-r--r--Source/WebCore/platform/graphics/FontCache.cpp475
-rw-r--r--Source/WebCore/platform/graphics/FontCache.h117
-rw-r--r--Source/WebCore/platform/graphics/FontData.cpp35
-rw-r--r--Source/WebCore/platform/graphics/FontData.h65
-rw-r--r--Source/WebCore/platform/graphics/FontDescription.cpp101
-rw-r--r--Source/WebCore/platform/graphics/FontDescription.h170
-rw-r--r--Source/WebCore/platform/graphics/FontFallbackList.cpp139
-rw-r--r--Source/WebCore/platform/graphics/FontFallbackList.h89
-rw-r--r--Source/WebCore/platform/graphics/FontFamily.cpp59
-rw-r--r--Source/WebCore/platform/graphics/FontFamily.h88
-rw-r--r--Source/WebCore/platform/graphics/FontFastPath.cpp486
-rw-r--r--Source/WebCore/platform/graphics/FontOrientation.h35
-rw-r--r--Source/WebCore/platform/graphics/FontRenderingMode.h37
-rw-r--r--Source/WebCore/platform/graphics/FontSelector.h47
-rw-r--r--Source/WebCore/platform/graphics/FontSmoothingMode.h35
-rw-r--r--Source/WebCore/platform/graphics/FontTraitsMask.h70
-rw-r--r--Source/WebCore/platform/graphics/GeneratedImage.cpp71
-rw-r--r--Source/WebCore/platform/graphics/GeneratedImage.h76
-rw-r--r--Source/WebCore/platform/graphics/Generator.h46
-rw-r--r--Source/WebCore/platform/graphics/GlyphBuffer.h201
-rw-r--r--Source/WebCore/platform/graphics/GlyphMetricsMap.h130
-rw-r--r--Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp437
-rw-r--r--Source/WebCore/platform/graphics/GlyphPageTreeNode.h239
-rw-r--r--Source/WebCore/platform/graphics/Gradient.cpp231
-rw-r--r--Source/WebCore/platform/graphics/Gradient.h181
-rw-r--r--Source/WebCore/platform/graphics/GraphicsContext.cpp685
-rw-r--r--Source/WebCore/platform/graphics/GraphicsContext.h564
-rw-r--r--Source/WebCore/platform/graphics/GraphicsContext3D.cpp1454
-rw-r--r--Source/WebCore/platform/graphics/GraphicsContext3D.h904
-rw-r--r--Source/WebCore/platform/graphics/GraphicsLayer.cpp546
-rw-r--r--Source/WebCore/platform/graphics/GraphicsLayer.h434
-rw-r--r--Source/WebCore/platform/graphics/GraphicsLayerClient.h74
-rw-r--r--Source/WebCore/platform/graphics/GraphicsTypes.cpp189
-rw-r--r--Source/WebCore/platform/graphics/GraphicsTypes.h88
-rw-r--r--Source/WebCore/platform/graphics/Icon.h89
-rw-r--r--Source/WebCore/platform/graphics/Image.cpp180
-rw-r--r--Source/WebCore/platform/graphics/Image.h184
-rw-r--r--Source/WebCore/platform/graphics/ImageBuffer.cpp72
-rw-r--r--Source/WebCore/platform/graphics/ImageBuffer.h132
-rw-r--r--Source/WebCore/platform/graphics/ImageObserver.h51
-rw-r--r--Source/WebCore/platform/graphics/ImageSource.cpp187
-rw-r--r--Source/WebCore/platform/graphics/ImageSource.h228
-rw-r--r--Source/WebCore/platform/graphics/IntPoint.h227
-rw-r--r--Source/WebCore/platform/graphics/IntPointHash.h48
-rw-r--r--Source/WebCore/platform/graphics/IntRect.cpp118
-rw-r--r--Source/WebCore/platform/graphics/IntRect.h250
-rw-r--r--Source/WebCore/platform/graphics/IntSize.h192
-rw-r--r--Source/WebCore/platform/graphics/IntSizeHash.h46
-rw-r--r--Source/WebCore/platform/graphics/MediaPlayer.cpp780
-rw-r--r--Source/WebCore/platform/graphics/MediaPlayer.h330
-rw-r--r--Source/WebCore/platform/graphics/MediaPlayerPrivate.h142
-rw-r--r--Source/WebCore/platform/graphics/Path.cpp191
-rw-r--r--Source/WebCore/platform/graphics/Path.h153
-rw-r--r--Source/WebCore/platform/graphics/PathTraversalState.cpp207
-rw-r--r--Source/WebCore/platform/graphics/PathTraversalState.h72
-rw-r--r--Source/WebCore/platform/graphics/Pattern.cpp66
-rw-r--r--Source/WebCore/platform/graphics/Pattern.h105
-rw-r--r--Source/WebCore/platform/graphics/Pen.cpp77
-rw-r--r--Source/WebCore/platform/graphics/Pen.h72
-rw-r--r--Source/WebCore/platform/graphics/SegmentedFontData.cpp98
-rw-r--r--Source/WebCore/platform/graphics/SegmentedFontData.h81
-rw-r--r--Source/WebCore/platform/graphics/SimpleFontData.cpp239
-rw-r--r--Source/WebCore/platform/graphics/SimpleFontData.h339
-rw-r--r--Source/WebCore/platform/graphics/StringTruncator.cpp198
-rw-r--r--Source/WebCore/platform/graphics/StringTruncator.h47
-rw-r--r--Source/WebCore/platform/graphics/StrokeStyleApplier.h38
-rw-r--r--Source/WebCore/platform/graphics/TextRenderingMode.h35
-rw-r--r--Source/WebCore/platform/graphics/TextRun.h143
-rw-r--r--Source/WebCore/platform/graphics/Tile.h78
-rw-r--r--Source/WebCore/platform/graphics/TiledBackingStore.cpp403
-rw-r--r--Source/WebCore/platform/graphics/TiledBackingStore.h127
-rw-r--r--Source/WebCore/platform/graphics/TiledBackingStoreClient.h42
-rw-r--r--Source/WebCore/platform/graphics/TypesettingFeatures.h38
-rw-r--r--Source/WebCore/platform/graphics/UnitBezier.h123
-rw-r--r--Source/WebCore/platform/graphics/WOFFFileFormat.cpp254
-rw-r--r--Source/WebCore/platform/graphics/WOFFFileFormat.h48
-rw-r--r--Source/WebCore/platform/graphics/WidthIterator.cpp294
-rw-r--r--Source/WebCore/platform/graphics/WidthIterator.h71
-rw-r--r--Source/WebCore/platform/graphics/brew/IconBrew.cpp51
-rw-r--r--Source/WebCore/platform/graphics/brew/ImageBrew.cpp56
-rw-r--r--Source/WebCore/platform/graphics/brew/IntPointBrew.cpp48
-rw-r--r--Source/WebCore/platform/graphics/brew/IntSizeBrew.cpp48
-rw-r--r--Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp2308
-rw-r--r--Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h401
-rw-r--r--Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h156
-rw-r--r--Source/WebCore/platform/graphics/ca/PlatformCALayer.h218
-rw-r--r--Source/WebCore/platform/graphics/ca/PlatformCALayerClient.h70
-rw-r--r--Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp69
-rw-r--r--Source/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm574
-rw-r--r--Source/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm726
-rw-r--r--Source/WebCore/platform/graphics/ca/win/PlatformCAAnimationWin.cpp538
-rw-r--r--Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp710
-rw-r--r--Source/WebCore/platform/graphics/ca/win/PlatformCALayerWinInternal.cpp464
-rw-r--r--Source/WebCore/platform/graphics/ca/win/PlatformCALayerWinInternal.h88
-rw-r--r--Source/WebCore/platform/graphics/cairo/CairoPath.h50
-rw-r--r--Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp158
-rw-r--r--Source/WebCore/platform/graphics/cairo/CairoUtilities.h51
-rw-r--r--Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp354
-rw-r--r--Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h99
-rw-r--r--Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp45
-rw-r--r--Source/WebCore/platform/graphics/cairo/FontCairo.cpp175
-rw-r--r--Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h54
-rw-r--r--Source/WebCore/platform/graphics/cairo/GradientCairo.cpp99
-rw-r--r--Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp1149
-rw-r--r--Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h113
-rw-r--r--Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp319
-rw-r--r--Source/WebCore/platform/graphics/cairo/ImageBufferData.h44
-rw-r--r--Source/WebCore/platform/graphics/cairo/ImageCairo.cpp208
-rw-r--r--Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp52
-rw-r--r--Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h43
-rw-r--r--Source/WebCore/platform/graphics/cairo/PathCairo.cpp342
-rw-r--r--Source/WebCore/platform/graphics/cairo/PatternCairo.cpp54
-rw-r--r--Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp106
-rw-r--r--Source/WebCore/platform/graphics/cairo/RefPtrCairo.h59
-rw-r--r--Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp66
-rw-r--r--Source/WebCore/platform/graphics/cairo/rgb24-hacks.txt32
-rw-r--r--Source/WebCore/platform/graphics/cairo/scale-removal.txt13
-rw-r--r--Source/WebCore/platform/graphics/cg/ColorCG.cpp149
-rw-r--r--Source/WebCore/platform/graphics/cg/FloatPointCG.cpp47
-rw-r--r--Source/WebCore/platform/graphics/cg/FloatRectCG.cpp47
-rw-r--r--Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp47
-rw-r--r--Source/WebCore/platform/graphics/cg/FontPlatformData.h105
-rw-r--r--Source/WebCore/platform/graphics/cg/GradientCG.cpp145
-rw-r--r--Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp257
-rw-r--r--Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp1260
-rw-r--r--Source/WebCore/platform/graphics/cg/GraphicsContextCG.h41
-rw-r--r--Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h86
-rw-r--r--Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp534
-rw-r--r--Source/WebCore/platform/graphics/cg/ImageBufferData.h57
-rw-r--r--Source/WebCore/platform/graphics/cg/ImageCG.cpp349
-rw-r--r--Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp339
-rw-r--r--Source/WebCore/platform/graphics/cg/ImageSourceCG.h44
-rw-r--r--Source/WebCore/platform/graphics/cg/ImageSourceCGMac.mm48
-rw-r--r--Source/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp84
-rw-r--r--Source/WebCore/platform/graphics/cg/IntPointCG.cpp46
-rw-r--r--Source/WebCore/platform/graphics/cg/IntRectCG.cpp51
-rw-r--r--Source/WebCore/platform/graphics/cg/IntSizeCG.cpp46
-rw-r--r--Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp191
-rw-r--r--Source/WebCore/platform/graphics/cg/PDFDocumentImage.h78
-rw-r--r--Source/WebCore/platform/graphics/cg/PathCG.cpp312
-rw-r--r--Source/WebCore/platform/graphics/cg/PatternCG.cpp78
-rw-r--r--Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp69
-rw-r--r--Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp112
-rw-r--r--Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h65
-rw-r--r--Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp126
-rw-r--r--Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h80
-rw-r--r--Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.cpp426
-rw-r--r--Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.h164
-rw-r--r--Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp368
-rw-r--r--Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h99
-rw-r--r--Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.h100
-rw-r--r--Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.mm210
-rw-r--r--Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp148
-rw-r--r--Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h77
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp607
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontCacheLinux.cpp159
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp541
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontLinux.cpp410
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontPlatformData.h40
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp163
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h137
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp235
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h167
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontRenderStyle.h74
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp438
-rw-r--r--Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h96
-rw-r--r--Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp286
-rw-r--r--Source/WebCore/platform/graphics/chromium/GLES2Canvas.h106
-rw-r--r--Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp239
-rw-r--r--Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp645
-rw-r--r--Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h146
-rw-r--r--Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp238
-rw-r--r--Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.h44
-rw-r--r--Source/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp54
-rw-r--r--Source/WebCore/platform/graphics/chromium/IconChromiumMac.cpp50
-rw-r--r--Source/WebCore/platform/graphics/chromium/IconChromiumWin.cpp65
-rw-r--r--Source/WebCore/platform/graphics/chromium/ImageBufferData.h50
-rw-r--r--Source/WebCore/platform/graphics/chromium/ImageChromium.cpp45
-rw-r--r--Source/WebCore/platform/graphics/chromium/ImageChromiumMac.mm58
-rw-r--r--Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp164
-rw-r--r--Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h66
-rw-r--r--Source/WebCore/platform/graphics/chromium/LayerChromium.cpp520
-rw-r--r--Source/WebCore/platform/graphics/chromium/LayerChromium.h307
-rw-r--r--Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp803
-rw-r--r--Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h221
-rw-r--r--Source/WebCore/platform/graphics/chromium/LayerTexture.cpp93
-rw-r--r--Source/WebCore/platform/graphics/chromium/LayerTexture.h69
-rw-r--r--Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp424
-rw-r--r--Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h123
-rw-r--r--Source/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h49
-rw-r--r--Source/WebCore/platform/graphics/chromium/PlatformIcon.h42
-rw-r--r--Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp133
-rw-r--r--Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h74
-rw-r--r--Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp157
-rw-r--r--Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h98
-rw-r--r--Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp207
-rw-r--r--Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp236
-rw-r--r--Source/WebCore/platform/graphics/chromium/TextureManager.cpp171
-rw-r--r--Source/WebCore/platform/graphics/chromium/TextureManager.h83
-rw-r--r--Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp513
-rw-r--r--Source/WebCore/platform/graphics/chromium/TransparencyWin.h261
-rw-r--r--Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp932
-rw-r--r--Source/WebCore/platform/graphics/chromium/UniscribeHelper.h414
-rw-r--r--Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp138
-rw-r--r--Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h96
-rw-r--r--Source/WebCore/platform/graphics/chromium/VDMXParser.cpp202
-rw-r--r--Source/WebCore/platform/graphics/chromium/VDMXParser.h40
-rw-r--r--Source/WebCore/platform/graphics/chromium/VideoFrameChromium.cpp47
-rw-r--r--Source/WebCore/platform/graphics/chromium/VideoFrameChromium.h82
-rw-r--r--Source/WebCore/platform/graphics/chromium/VideoFrameProvider.h57
-rw-r--r--Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp427
-rw-r--r--Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h124
-rw-r--r--Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp88
-rw-r--r--Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h60
-rw-r--r--Source/WebCore/platform/graphics/cocoa/FontPlatformData.h170
-rw-r--r--Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm186
-rw-r--r--Source/WebCore/platform/graphics/efl/FontEfl.cpp71
-rw-r--r--Source/WebCore/platform/graphics/efl/IconEfl.cpp66
-rw-r--r--Source/WebCore/platform/graphics/efl/ImageEfl.cpp69
-rw-r--r--Source/WebCore/platform/graphics/efl/IntPointEfl.cpp42
-rw-r--r--Source/WebCore/platform/graphics/efl/IntRectEfl.cpp40
-rw-r--r--Source/WebCore/platform/graphics/filters/DistantLightSource.h62
-rw-r--r--Source/WebCore/platform/graphics/filters/FEBlend.cpp175
-rw-r--r--Source/WebCore/platform/graphics/filters/FEBlend.h63
-rw-r--r--Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp241
-rw-r--r--Source/WebCore/platform/graphics/filters/FEColorMatrix.h67
-rw-r--r--Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp245
-rw-r--r--Source/WebCore/platform/graphics/filters/FEComponentTransfer.h100
-rw-r--r--Source/WebCore/platform/graphics/filters/FEComposite.cpp290
-rw-r--r--Source/WebCore/platform/graphics/filters/FEComposite.h83
-rw-r--r--Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp471
-rw-r--r--Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h120
-rw-r--r--Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp126
-rw-r--r--Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h68
-rw-r--r--Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp172
-rw-r--r--Source/WebCore/platform/graphics/filters/FEDisplacementMap.h72
-rw-r--r--Source/WebCore/platform/graphics/filters/FEFlood.cpp93
-rw-r--r--Source/WebCore/platform/graphics/filters/FEFlood.h60
-rw-r--r--Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp242
-rw-r--r--Source/WebCore/platform/graphics/filters/FEGaussianBlur.h61
-rw-r--r--Source/WebCore/platform/graphics/filters/FELighting.cpp359
-rw-r--r--Source/WebCore/platform/graphics/filters/FELighting.h98
-rw-r--r--Source/WebCore/platform/graphics/filters/FEMerge.cpp85
-rw-r--r--Source/WebCore/platform/graphics/filters/FEMerge.h49
-rw-r--r--Source/WebCore/platform/graphics/filters/FEMorphology.cpp199
-rw-r--r--Source/WebCore/platform/graphics/filters/FEMorphology.h68
-rw-r--r--Source/WebCore/platform/graphics/filters/FEOffset.cpp112
-rw-r--r--Source/WebCore/platform/graphics/filters/FEOffset.h59
-rw-r--r--Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp138
-rw-r--r--Source/WebCore/platform/graphics/filters/FESpecularLighting.h69
-rw-r--r--Source/WebCore/platform/graphics/filters/FETile.cpp108
-rw-r--r--Source/WebCore/platform/graphics/filters/FETile.h52
-rw-r--r--Source/WebCore/platform/graphics/filters/FETurbulence.cpp385
-rw-r--r--Source/WebCore/platform/graphics/filters/FETurbulence.h105
-rw-r--r--Source/WebCore/platform/graphics/filters/Filter.h68
-rw-r--r--Source/WebCore/platform/graphics/filters/FilterEffect.cpp251
-rw-r--r--Source/WebCore/platform/graphics/filters/FilterEffect.h154
-rw-r--r--Source/WebCore/platform/graphics/filters/LightSource.cpp170
-rw-r--r--Source/WebCore/platform/graphics/filters/LightSource.h85
-rw-r--r--Source/WebCore/platform/graphics/filters/PointLightSource.h59
-rw-r--r--Source/WebCore/platform/graphics/filters/SourceAlpha.cpp85
-rw-r--r--Source/WebCore/platform/graphics/filters/SourceAlpha.h57
-rw-r--r--Source/WebCore/platform/graphics/filters/SourceGraphic.cpp77
-rw-r--r--Source/WebCore/platform/graphics/filters/SourceGraphic.h58
-rw-r--r--Source/WebCore/platform/graphics/filters/SpotLightSource.h72
-rw-r--r--Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp206
-rw-r--r--Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp98
-rw-r--r--Source/WebCore/platform/graphics/freetype/FontPlatformData.h108
-rw-r--r--Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp288
-rw-r--r--Source/WebCore/platform/graphics/freetype/GlyphPageTreeNodeFreeType.cpp68
-rw-r--r--Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp154
-rw-r--r--Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp253
-rw-r--r--Source/WebCore/platform/graphics/gpu/DrawingBuffer.h124
-rw-r--r--Source/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp126
-rw-r--r--Source/WebCore/platform/graphics/gpu/LoopBlinnClassifier.h84
-rw-r--r--Source/WebCore/platform/graphics/gpu/LoopBlinnConstants.h40
-rw-r--r--Source/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp279
-rw-r--r--Source/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.h268
-rw-r--r--Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp568
-rw-r--r--Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h108
-rw-r--r--Source/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp175
-rw-r--r--Source/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.h82
-rw-r--r--Source/WebCore/platform/graphics/gpu/PODArena.h211
-rw-r--r--Source/WebCore/platform/graphics/gpu/PODInterval.h165
-rw-r--r--Source/WebCore/platform/graphics/gpu/PODIntervalTree.h224
-rw-r--r--Source/WebCore/platform/graphics/gpu/PODRedBlackTree.h757
-rw-r--r--Source/WebCore/platform/graphics/gpu/Shader.cpp116
-rw-r--r--Source/WebCore/platform/graphics/gpu/Shader.h58
-rw-r--r--Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp348
-rw-r--r--Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h139
-rw-r--r--Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp93
-rw-r--r--Source/WebCore/platform/graphics/gpu/SolidFillShader.h53
-rw-r--r--Source/WebCore/platform/graphics/gpu/TexShader.cpp100
-rw-r--r--Source/WebCore/platform/graphics/gpu/TexShader.h55
-rw-r--r--Source/WebCore/platform/graphics/gpu/Texture.cpp216
-rw-r--r--Source/WebCore/platform/graphics/gpu/Texture.h66
-rw-r--r--Source/WebCore/platform/graphics/gpu/TilingData.cpp227
-rw-r--r--Source/WebCore/platform/graphics/gpu/TilingData.h88
-rw-r--r--Source/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm119
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp35
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h35
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp226
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h66
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h67
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm61
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp68
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/ImageGStreamerQt.cpp67
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp1630
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h200
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h52
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp42
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp69
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h44
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp82
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp374
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h81
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp820
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h54
-rw-r--r--Source/WebCore/platform/graphics/gtk/ColorGtk.cpp55
-rw-r--r--Source/WebCore/platform/graphics/gtk/FontGtk.cpp439
-rw-r--r--Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.cpp39
-rw-r--r--Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.h31
-rw-r--r--Source/WebCore/platform/graphics/gtk/IconGtk.cpp127
-rw-r--r--Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp73
-rw-r--r--Source/WebCore/platform/graphics/gtk/ImageGtk.cpp158
-rw-r--r--Source/WebCore/platform/graphics/gtk/IntPointGtk.cpp41
-rw-r--r--Source/WebCore/platform/graphics/gtk/IntRectGtk.cpp41
-rw-r--r--Source/WebCore/platform/graphics/haiku/ColorHaiku.cpp54
-rw-r--r--Source/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp48
-rw-r--r--Source/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp49
-rw-r--r--Source/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp81
-rw-r--r--Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp50
-rw-r--r--Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h48
-rw-r--r--Source/WebCore/platform/graphics/haiku/FontHaiku.cpp120
-rw-r--r--Source/WebCore/platform/graphics/haiku/FontPlatformData.h81
-rw-r--r--Source/WebCore/platform/graphics/haiku/GlyphPageTreeNodeHaiku.cpp68
-rw-r--r--Source/WebCore/platform/graphics/haiku/GradientHaiku.cpp73
-rw-r--r--Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp536
-rw-r--r--Source/WebCore/platform/graphics/haiku/IconHaiku.cpp51
-rw-r--r--Source/WebCore/platform/graphics/haiku/ImageBufferData.h50
-rw-r--r--Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp375
-rw-r--r--Source/WebCore/platform/graphics/haiku/ImageHaiku.cpp195
-rw-r--r--Source/WebCore/platform/graphics/haiku/IntPointHaiku.cpp48
-rw-r--r--Source/WebCore/platform/graphics/haiku/IntRectHaiku.cpp48
-rw-r--r--Source/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp48
-rw-r--r--Source/WebCore/platform/graphics/haiku/PathHaiku.cpp164
-rw-r--r--Source/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp123
-rw-r--r--Source/WebCore/platform/graphics/haiku/StillImageHaiku.cpp78
-rw-r--r--Source/WebCore/platform/graphics/haiku/StillImageHaiku.h58
-rw-r--r--Source/WebCore/platform/graphics/mac/ColorMac.h54
-rw-r--r--Source/WebCore/platform/graphics/mac/ColorMac.mm112
-rw-r--r--Source/WebCore/platform/graphics/mac/ComplexTextController.cpp565
-rw-r--r--Source/WebCore/platform/graphics/mac/ComplexTextController.h193
-rw-r--r--Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp340
-rw-r--r--Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp173
-rw-r--r--Source/WebCore/platform/graphics/mac/FloatPointMac.mm45
-rw-r--r--Source/WebCore/platform/graphics/mac/FloatRectMac.mm45
-rw-r--r--Source/WebCore/platform/graphics/mac/FloatSizeMac.mm45
-rw-r--r--Source/WebCore/platform/graphics/mac/FontCacheMac.mm217
-rw-r--r--Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp127
-rw-r--r--Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp122
-rw-r--r--Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h60
-rw-r--r--Source/WebCore/platform/graphics/mac/FontMac.mm209
-rw-r--r--Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp162
-rw-r--r--Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm256
-rw-r--r--Source/WebCore/platform/graphics/mac/GraphicsContextMac.mm193
-rw-r--r--Source/WebCore/platform/graphics/mac/IconMac.mm90
-rw-r--r--Source/WebCore/platform/graphics/mac/ImageMac.mm124
-rw-r--r--Source/WebCore/platform/graphics/mac/IntPointMac.mm44
-rw-r--r--Source/WebCore/platform/graphics/mac/IntRectMac.mm49
-rw-r--r--Source/WebCore/platform/graphics/mac/IntSizeMac.mm44
-rw-r--r--Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h216
-rw-r--r--Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm1673
-rw-r--r--Source/WebCore/platform/graphics/mac/MediaPlayerProxy.h118
-rw-r--r--Source/WebCore/platform/graphics/mac/SimpleFontDataATSUI.mm77
-rw-r--r--Source/WebCore/platform/graphics/mac/SimpleFontDataCoreText.cpp77
-rw-r--r--Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm504
-rw-r--r--Source/WebCore/platform/graphics/mac/WebGLLayer.h52
-rw-r--r--Source/WebCore/platform/graphics/mac/WebGLLayer.mm167
-rw-r--r--Source/WebCore/platform/graphics/mac/WebLayer.h56
-rw-r--r--Source/WebCore/platform/graphics/mac/WebLayer.mm222
-rw-r--r--Source/WebCore/platform/graphics/mac/WebTiledLayer.h44
-rw-r--r--Source/WebCore/platform/graphics/mac/WebTiledLayer.mm91
-rw-r--r--Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp110
-rw-r--r--Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h59
-rw-r--r--Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp1476
-rw-r--r--Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp663
-rw-r--r--Source/WebCore/platform/graphics/opengl/TextureMapperGL.h91
-rw-r--r--Source/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp69
-rw-r--r--Source/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h57
-rw-r--r--Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp447
-rw-r--r--Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.h63
-rw-r--r--Source/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp455
-rw-r--r--Source/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h90
-rw-r--r--Source/WebCore/platform/graphics/openvg/EGLUtils.h71
-rw-r--r--Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp523
-rw-r--r--Source/WebCore/platform/graphics/openvg/ImageOpenVG.cpp199
-rw-r--r--Source/WebCore/platform/graphics/openvg/PainterOpenVG.cpp1242
-rw-r--r--Source/WebCore/platform/graphics/openvg/PainterOpenVG.h141
-rw-r--r--Source/WebCore/platform/graphics/openvg/PathOpenVG.cpp497
-rw-r--r--Source/WebCore/platform/graphics/openvg/PlatformPathOpenVG.h53
-rw-r--r--Source/WebCore/platform/graphics/openvg/SharedResourceOpenVG.cpp45
-rw-r--r--Source/WebCore/platform/graphics/openvg/SharedResourceOpenVG.h33
-rw-r--r--Source/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp271
-rw-r--r--Source/WebCore/platform/graphics/openvg/SurfaceOpenVG.h157
-rw-r--r--Source/WebCore/platform/graphics/openvg/TiledImageOpenVG.cpp177
-rw-r--r--Source/WebCore/platform/graphics/openvg/TiledImageOpenVG.h69
-rw-r--r--Source/WebCore/platform/graphics/openvg/VGUtils.cpp235
-rw-r--r--Source/WebCore/platform/graphics/openvg/VGUtils.h115
-rw-r--r--Source/WebCore/platform/graphics/pango/FontCachePango.cpp65
-rw-r--r--Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp54
-rw-r--r--Source/WebCore/platform/graphics/pango/FontPlatformData.h105
-rw-r--r--Source/WebCore/platform/graphics/pango/FontPlatformDataPango.cpp277
-rw-r--r--Source/WebCore/platform/graphics/pango/GlyphPageTreeNodePango.cpp98
-rw-r--r--Source/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp157
-rw-r--r--Source/WebCore/platform/graphics/qt/ColorQt.cpp51
-rw-r--r--Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp167
-rw-r--r--Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp61
-rw-r--r--Source/WebCore/platform/graphics/qt/Extensions3DQt.h50
-rw-r--r--Source/WebCore/platform/graphics/qt/FloatPointQt.cpp48
-rw-r--r--Source/WebCore/platform/graphics/qt/FloatRectQt.cpp64
-rw-r--r--Source/WebCore/platform/graphics/qt/FontCacheQt.cpp72
-rw-r--r--Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h50
-rw-r--r--Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp69
-rw-r--r--Source/WebCore/platform/graphics/qt/FontPlatformData.h175
-rw-r--r--Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp132
-rw-r--r--Source/WebCore/platform/graphics/qt/FontQt.cpp432
-rw-r--r--Source/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp36
-rw-r--r--Source/WebCore/platform/graphics/qt/GradientQt.cpp119
-rw-r--r--Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp1674
-rw-r--r--Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp1370
-rw-r--r--Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp1779
-rw-r--r--Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h95
-rw-r--r--Source/WebCore/platform/graphics/qt/IconQt.cpp69
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageBufferData.h52
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp412
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp258
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageDecoderQt.h80
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageQt.cpp256
-rw-r--r--Source/WebCore/platform/graphics/qt/IntPointQt.cpp48
-rw-r--r--Source/WebCore/platform/graphics/qt/IntRectQt.cpp48
-rw-r--r--Source/WebCore/platform/graphics/qt/IntSizeQt.cpp49
-rw-r--r--Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp547
-rw-r--r--Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h153
-rw-r--r--Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp674
-rw-r--r--Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h156
-rw-r--r--Source/WebCore/platform/graphics/qt/PathQt.cpp446
-rw-r--r--Source/WebCore/platform/graphics/qt/PatternQt.cpp47
-rw-r--r--Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp89
-rw-r--r--Source/WebCore/platform/graphics/qt/StillImageQt.cpp91
-rw-r--r--Source/WebCore/platform/graphics/qt/StillImageQt.h67
-rw-r--r--Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp214
-rw-r--r--Source/WebCore/platform/graphics/qt/TextureMapperQt.h76
-rw-r--r--Source/WebCore/platform/graphics/qt/TileQt.cpp179
-rw-r--r--Source/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp47
-rw-r--r--Source/WebCore/platform/graphics/qt/TransparencyLayer.h86
-rw-r--r--Source/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h87
-rw-r--r--Source/WebCore/platform/graphics/skia/FloatPointSkia.cpp51
-rw-r--r--Source/WebCore/platform/graphics/skia/FloatRectSkia.cpp50
-rw-r--r--Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp211
-rw-r--r--Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h82
-rw-r--r--Source/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp115
-rw-r--r--Source/WebCore/platform/graphics/skia/GradientSkia.cpp196
-rw-r--r--Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp90
-rw-r--r--Source/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h55
-rw-r--r--Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp1262
-rw-r--r--Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp339
-rw-r--r--Source/WebCore/platform/graphics/skia/ImageSkia.cpp540
-rw-r--r--Source/WebCore/platform/graphics/skia/IntPointSkia.cpp56
-rw-r--r--Source/WebCore/platform/graphics/skia/IntRectSkia.cpp57
-rw-r--r--Source/WebCore/platform/graphics/skia/NativeImageSkia.cpp140
-rw-r--r--Source/WebCore/platform/graphics/skia/NativeImageSkia.h113
-rw-r--r--Source/WebCore/platform/graphics/skia/PathSkia.cpp274
-rw-r--r--Source/WebCore/platform/graphics/skia/PatternSkia.cpp103
-rw-r--r--Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp890
-rw-r--r--Source/WebCore/platform/graphics/skia/PlatformContextSkia.h240
-rw-r--r--Source/WebCore/platform/graphics/skia/PlatformGraphics.h37
-rw-r--r--Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp358
-rw-r--r--Source/WebCore/platform/graphics/skia/SkiaFontWin.h94
-rw-r--r--Source/WebCore/platform/graphics/skia/SkiaUtils.cpp257
-rw-r--r--Source/WebCore/platform/graphics/skia/SkiaUtils.h82
-rw-r--r--Source/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp78
-rw-r--r--Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp387
-rw-r--r--Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h107
-rw-r--r--Source/WebCore/platform/graphics/texmap/TextureMapper.h135
-rw-r--r--Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp877
-rw-r--r--Source/WebCore/platform/graphics/texmap/TextureMapperNode.h252
-rw-r--r--Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h79
-rw-r--r--Source/WebCore/platform/graphics/transforms/AffineTransform.cpp388
-rw-r--r--Source/WebCore/platform/graphics/transforms/AffineTransform.h190
-rw-r--r--Source/WebCore/platform/graphics/transforms/IdentityTransformOperation.h67
-rw-r--r--Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp56
-rw-r--r--Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h74
-rw-r--r--Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp52
-rw-r--r--Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h101
-rw-r--r--Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp58
-rw-r--r--Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h73
-rw-r--r--Source/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp95
-rw-r--r--Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h90
-rw-r--r--Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp46
-rw-r--r--Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h87
-rw-r--r--Source/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp41
-rw-r--r--Source/WebCore/platform/graphics/transforms/SkewTransformOperation.h77
-rw-r--r--Source/WebCore/platform/graphics/transforms/TransformOperation.h86
-rw-r--r--Source/WebCore/platform/graphics/transforms/TransformOperations.cpp49
-rw-r--r--Source/WebCore/platform/graphics/transforms/TransformOperations.h77
-rw-r--r--Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp1132
-rw-r--r--Source/WebCore/platform/graphics/transforms/TransformationMatrix.h364
-rw-r--r--Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp44
-rw-r--r--Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h92
-rw-r--r--Source/WebCore/platform/graphics/win/FontCGWin.cpp392
-rw-r--r--Source/WebCore/platform/graphics/win/FontCacheWin.cpp603
-rw-r--r--Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp219
-rw-r--r--Source/WebCore/platform/graphics/win/FontCustomPlatformData.h58
-rw-r--r--Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp66
-rw-r--r--Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h54
-rw-r--r--Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp131
-rw-r--r--Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp143
-rw-r--r--Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp95
-rw-r--r--Source/WebCore/platform/graphics/win/FontWin.cpp142
-rw-r--r--Source/WebCore/platform/graphics/win/GDIExtras.cpp43
-rw-r--r--Source/WebCore/platform/graphics/win/GDIExtras.h65
-rw-r--r--Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp59
-rw-r--r--Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp72
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp261
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp169
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp200
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp757
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsLayerCACF.h139
-rw-r--r--Source/WebCore/platform/graphics/win/IconWin.cpp99
-rw-r--r--Source/WebCore/platform/graphics/win/ImageCGWin.cpp108
-rw-r--r--Source/WebCore/platform/graphics/win/ImageCairoWin.cpp114
-rw-r--r--Source/WebCore/platform/graphics/win/ImageWin.cpp58
-rw-r--r--Source/WebCore/platform/graphics/win/IntPointWin.cpp57
-rw-r--r--Source/WebCore/platform/graphics/win/IntRectWin.cpp45
-rw-r--r--Source/WebCore/platform/graphics/win/IntSizeWin.cpp45
-rw-r--r--Source/WebCore/platform/graphics/win/LocalWindowsContext.h61
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp183
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h82
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp1252
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h211
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp933
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h193
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp65
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h48
-rw-r--r--Source/WebCore/platform/graphics/win/QTCFDictionary.cpp61
-rw-r--r--Source/WebCore/platform/graphics/win/QTCFDictionary.h44
-rw-r--r--Source/WebCore/platform/graphics/win/QTDecompressionSession.cpp170
-rw-r--r--Source/WebCore/platform/graphics/win/QTDecompressionSession.h64
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovie.cpp942
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovie.h125
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp465
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieGWorld.h84
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieTask.cpp105
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieTask.h69
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieVisualContext.cpp223
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieVisualContext.h79
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieWinTimer.cpp137
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieWinTimer.h39
-rw-r--r--Source/WebCore/platform/graphics/win/QTPixelBuffer.cpp256
-rw-r--r--Source/WebCore/platform/graphics/win/QTPixelBuffer.h100
-rw-r--r--Source/WebCore/platform/graphics/win/QTTrack.cpp119
-rw-r--r--Source/WebCore/platform/graphics/win/QTTrack.h66
-rw-r--r--Source/WebCore/platform/graphics/win/RefCountedGDIHandle.h70
-rw-r--r--Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp161
-rw-r--r--Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp130
-rw-r--r--Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp259
-rw-r--r--Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp46
-rw-r--r--Source/WebCore/platform/graphics/win/UniscribeController.cpp465
-rw-r--r--Source/WebCore/platform/graphics/win/UniscribeController.h90
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp79
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFContextFlusher.h60
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFLayer.cpp572
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFLayer.h299
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp614
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h129
-rw-r--r--Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp104
-rw-r--r--Source/WebCore/platform/graphics/win/WKCAImageQueue.h92
-rw-r--r--Source/WebCore/platform/graphics/win/WebLayer.cpp143
-rw-r--r--Source/WebCore/platform/graphics/win/WebLayer.h62
-rw-r--r--Source/WebCore/platform/graphics/win/WebTiledLayer.cpp303
-rw-r--r--Source/WebCore/platform/graphics/win/WebTiledLayer.h85
-rw-r--r--Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h114
-rw-r--r--Source/WebCore/platform/graphics/wince/ColorWinCE.cpp38
-rw-r--r--Source/WebCore/platform/graphics/wince/FontCacheWinCE.cpp351
-rw-r--r--Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp91
-rw-r--r--Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h59
-rw-r--r--Source/WebCore/platform/graphics/wince/FontPlatformData.cpp534
-rw-r--r--Source/WebCore/platform/graphics/wince/FontPlatformData.h93
-rw-r--r--Source/WebCore/platform/graphics/wince/FontWinCE.cpp342
-rw-r--r--Source/WebCore/platform/graphics/wince/GlyphPageTreeNodeWinCE.cpp78
-rw-r--r--Source/WebCore/platform/graphics/wince/GradientWinCE.cpp52
-rw-r--r--Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp1890
-rw-r--r--Source/WebCore/platform/graphics/wince/ImageBufferData.h34
-rw-r--r--Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp255
-rw-r--r--Source/WebCore/platform/graphics/wince/ImageWinCE.cpp195
-rw-r--r--Source/WebCore/platform/graphics/wince/MediaPlayerPrivateWinCE.h125
-rw-r--r--Source/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp145
-rw-r--r--Source/WebCore/platform/graphics/wince/MediaPlayerProxy.h70
-rw-r--r--Source/WebCore/platform/graphics/wince/PathWinCE.cpp163
-rw-r--r--Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp772
-rw-r--r--Source/WebCore/platform/graphics/wince/PlatformPathWinCE.h182
-rw-r--r--Source/WebCore/platform/graphics/wince/SharedBitmap.cpp615
-rw-r--r--Source/WebCore/platform/graphics/wince/SharedBitmap.h145
-rw-r--r--Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp180
-rw-r--r--Source/WebCore/platform/graphics/wince/WinCEGraphicsExtras.h39
-rw-r--r--Source/WebCore/platform/graphics/wx/ColorWx.cpp44
-rw-r--r--Source/WebCore/platform/graphics/wx/FloatRectWx.cpp47
-rw-r--r--Source/WebCore/platform/graphics/wx/FontCacheWx.cpp106
-rw-r--r--Source/WebCore/platform/graphics/wx/FontCustomPlatformData.cpp49
-rw-r--r--Source/WebCore/platform/graphics/wx/FontCustomPlatformData.h48
-rw-r--r--Source/WebCore/platform/graphics/wx/FontPlatformData.h182
-rw-r--r--Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp180
-rw-r--r--Source/WebCore/platform/graphics/wx/FontPlatformDataWxMac.mm147
-rw-r--r--Source/WebCore/platform/graphics/wx/FontWx.cpp184
-rw-r--r--Source/WebCore/platform/graphics/wx/GlyphMapWx.cpp59
-rw-r--r--Source/WebCore/platform/graphics/wx/GradientWx.cpp50
-rw-r--r--Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp666
-rw-r--r--Source/WebCore/platform/graphics/wx/IconWx.cpp47
-rw-r--r--Source/WebCore/platform/graphics/wx/ImageBufferData.h43
-rw-r--r--Source/WebCore/platform/graphics/wx/ImageBufferWx.cpp120
-rw-r--r--Source/WebCore/platform/graphics/wx/ImageWx.cpp264
-rw-r--r--Source/WebCore/platform/graphics/wx/IntPointWx.cpp45
-rw-r--r--Source/WebCore/platform/graphics/wx/IntRectWx.cpp45
-rw-r--r--Source/WebCore/platform/graphics/wx/IntSizeWx.cpp45
-rw-r--r--Source/WebCore/platform/graphics/wx/PathWx.cpp249
-rw-r--r--Source/WebCore/platform/graphics/wx/PenWx.cpp77
-rw-r--r--Source/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp197
-rw-r--r--Source/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp60
653 files changed, 129109 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp
new file mode 100644
index 0000000..64f19c4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "ANGLEWebKitBridge.h"
+
+namespace WebCore {
+
+
+ANGLEWebKitBridge::ANGLEWebKitBridge() :
+ builtCompilers(false)
+{
+ ShInitialize();
+}
+
+ANGLEWebKitBridge::~ANGLEWebKitBridge()
+{
+ if (builtCompilers) {
+ ShDestruct(m_fragmentCompiler);
+ ShDestruct(m_vertexCompiler);
+ }
+}
+
+bool ANGLEWebKitBridge::validateShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog)
+{
+ if (!builtCompilers) {
+ m_fragmentCompiler = ShConstructCompiler(EShLangFragment, EShSpecWebGL, &m_resources);
+ m_vertexCompiler = ShConstructCompiler(EShLangVertex, EShSpecWebGL, &m_resources);
+
+ builtCompilers = true;
+ }
+
+ ShHandle compiler;
+
+ if (shaderType == SHADER_TYPE_VERTEX)
+ compiler = m_vertexCompiler;
+ else
+ compiler = m_fragmentCompiler;
+
+ const char* const shaderSourceStrings[] = { shaderSource };
+
+ bool validateSuccess = ShCompile(compiler, shaderSourceStrings, 1, EShOptNone, EDebugOpIntermediate);
+
+ translatedShaderSource = ShGetObjectCode(compiler);
+ shaderValidationLog = ShGetInfoLog(compiler);
+
+ return validateSuccess;
+}
+
+}
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h
new file mode 100644
index 0000000..d01de8f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ANGLEWebKitBridge_h
+#define ANGLEWebKitBridge_h
+
+#include "ANGLE/ShaderLang.h"
+#include "PlatformString.h"
+
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+enum ANGLEShaderType {
+ SHADER_TYPE_VERTEX = EShLangVertex,
+ SHADER_TYPE_FRAGMENT = EShLangFragment
+};
+
+class ANGLEWebKitBridge {
+public:
+
+ ANGLEWebKitBridge();
+ ~ANGLEWebKitBridge();
+
+ void setResources(TBuiltInResource resources) { m_resources = resources; }
+
+ bool validateShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog);
+
+private:
+
+ ShHandle m_fragmentCompiler;
+ ShHandle m_vertexCompiler;
+
+ bool builtCompilers;
+
+ TBuiltInResource m_resources;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/BitmapImage.cpp b/Source/WebCore/platform/graphics/BitmapImage.cpp
new file mode 100644
index 0000000..1148aa6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/BitmapImage.cpp
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "BitmapImage.h"
+
+#include "FloatRect.h"
+#include "ImageObserver.h"
+#include "IntRect.h"
+#include "MIMETypeRegistry.h"
+#include "PlatformString.h"
+#include "Timer.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+static int frameBytes(const IntSize& frameSize)
+{
+ return frameSize.width() * frameSize.height() * 4;
+}
+
+BitmapImage::BitmapImage(ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_desiredFrameStartTime(0)
+ , m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
+ , m_animationFinished(false)
+ , m_allDataReceived(false)
+ , m_haveSize(false)
+ , m_sizeAvailable(false)
+ , m_hasUniformFrameSize(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(false)
+ , m_frameCount(0)
+{
+ initPlatformData();
+}
+
+BitmapImage::~BitmapImage()
+{
+ invalidatePlatformData();
+ stopAnimation();
+}
+
+void BitmapImage::destroyDecodedData(bool destroyAll)
+{
+ int framesCleared = 0;
+ const size_t clearBeforeFrame = destroyAll ? m_frames.size() : m_currentFrame;
+ for (size_t i = 0; i < clearBeforeFrame; ++i) {
+ // The underlying frame isn't actually changing (we're just trying to
+ // save the memory for the framebuffer data), so we don't need to clear
+ // the metadata.
+ if (m_frames[i].clear(false))
+ ++framesCleared;
+ }
+
+ destroyMetadataAndNotify(framesCleared);
+
+ m_source.clear(destroyAll, clearBeforeFrame, data(), m_allDataReceived);
+ return;
+}
+
+void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll)
+{
+ // Animated images >5MB are considered large enough that we'll only hang on
+ // to one frame at a time.
+ static const unsigned cLargeAnimationCutoff = 5242880;
+ if (m_frames.size() * frameBytes(m_size) > cLargeAnimationCutoff)
+ destroyDecodedData(destroyAll);
+}
+
+void BitmapImage::destroyMetadataAndNotify(int framesCleared)
+{
+ m_isSolidColor = false;
+ invalidatePlatformData();
+
+ const int deltaBytes = framesCleared * -frameBytes(m_size);
+ m_decodedSize += deltaBytes;
+ if (deltaBytes && imageObserver())
+ imageObserver()->decodedSizeChanged(this, deltaBytes);
+}
+
+void BitmapImage::cacheFrame(size_t index)
+{
+ size_t numFrames = frameCount();
+ ASSERT(m_decodedSize == 0 || numFrames > 1);
+
+ if (m_frames.size() < numFrames)
+ m_frames.grow(numFrames);
+
+ m_frames[index].m_frame = m_source.createFrameAtIndex(index);
+ if (numFrames == 1 && m_frames[index].m_frame)
+ checkForSolidColor();
+
+ m_frames[index].m_haveMetadata = true;
+ m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index);
+ if (repetitionCount(false) != cAnimationNone)
+ m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
+ m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
+
+ const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size);
+ if (frameSize != m_size)
+ m_hasUniformFrameSize = false;
+ if (m_frames[index].m_frame) {
+ const int deltaBytes = frameBytes(frameSize);
+ m_decodedSize += deltaBytes;
+ if (imageObserver())
+ imageObserver()->decodedSizeChanged(this, deltaBytes);
+ }
+}
+
+IntSize BitmapImage::size() const
+{
+ if (m_sizeAvailable && !m_haveSize) {
+ m_size = m_source.size();
+ m_haveSize = true;
+ }
+ return m_size;
+}
+
+IntSize BitmapImage::currentFrameSize() const
+{
+ if (!m_currentFrame || m_hasUniformFrameSize)
+ return size();
+ return m_source.frameSizeAtIndex(m_currentFrame);
+}
+
+bool BitmapImage::getHotSpot(IntPoint& hotSpot) const
+{
+ return m_source.getHotSpot(hotSpot);
+}
+
+bool BitmapImage::dataChanged(bool allDataReceived)
+{
+ // Because we're modifying the current frame, clear its (now possibly
+ // inaccurate) metadata as well.
+ destroyMetadataAndNotify((!m_frames.isEmpty() && m_frames[m_frames.size() - 1].clear(true)) ? 1 : 0);
+
+ // Feed all the data we've seen so far to the image decoder.
+ m_allDataReceived = allDataReceived;
+ m_source.setData(data(), allDataReceived);
+
+ // Clear the frame count.
+ m_haveFrameCount = false;
+
+ m_hasUniformFrameSize = true;
+
+ // Image properties will not be available until the first frame of the file
+ // reaches kCGImageStatusIncomplete.
+ return isSizeAvailable();
+}
+
+String BitmapImage::filenameExtension() const
+{
+ return m_source.filenameExtension();
+}
+
+size_t BitmapImage::frameCount()
+{
+ if (!m_haveFrameCount) {
+ m_haveFrameCount = true;
+ m_frameCount = m_source.frameCount();
+ }
+ return m_frameCount;
+}
+
+bool BitmapImage::isSizeAvailable()
+{
+ if (m_sizeAvailable)
+ return true;
+
+ m_sizeAvailable = m_source.isSizeAvailable();
+
+ return m_sizeAvailable;
+}
+
+NativeImagePtr BitmapImage::frameAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ if (index >= m_frames.size() || !m_frames[index].m_frame)
+ cacheFrame(index);
+
+ return m_frames[index].m_frame;
+}
+
+bool BitmapImage::frameIsCompleteAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return true;
+
+ if (index >= m_frames.size() || !m_frames[index].m_haveMetadata)
+ cacheFrame(index);
+
+ return m_frames[index].m_isComplete;
+}
+
+float BitmapImage::frameDurationAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ if (index >= m_frames.size() || !m_frames[index].m_haveMetadata)
+ cacheFrame(index);
+
+ return m_frames[index].m_duration;
+}
+
+bool BitmapImage::frameHasAlphaAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return true;
+
+ if (index >= m_frames.size() || !m_frames[index].m_haveMetadata)
+ cacheFrame(index);
+
+ return m_frames[index].m_hasAlpha;
+}
+
+int BitmapImage::repetitionCount(bool imageKnownToBeComplete)
+{
+ if ((m_repetitionCountStatus == Unknown) || ((m_repetitionCountStatus == Uncertain) && imageKnownToBeComplete)) {
+ // Snag the repetition count. If |imageKnownToBeComplete| is false, the
+ // repetition count may not be accurate yet for GIFs; in this case the
+ // decoder will default to cAnimationLoopOnce, and we'll try and read
+ // the count again once the whole image is decoded.
+ m_repetitionCount = m_source.repetitionCount();
+ m_repetitionCountStatus = (imageKnownToBeComplete || m_repetitionCount == cAnimationNone) ? Certain : Uncertain;
+ }
+ return m_repetitionCount;
+}
+
+bool BitmapImage::shouldAnimate()
+{
+ return (repetitionCount(false) != cAnimationNone && !m_animationFinished && imageObserver());
+}
+
+void BitmapImage::startAnimation(bool catchUpIfNecessary)
+{
+ if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
+ return;
+
+ // If we aren't already animating, set now as the animation start time.
+ const double time = currentTime();
+ if (!m_desiredFrameStartTime)
+ m_desiredFrameStartTime = time;
+
+ // Don't advance the animation to an incomplete frame.
+ size_t nextFrame = (m_currentFrame + 1) % frameCount();
+ if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame))
+ return;
+
+ // Don't advance past the last frame if we haven't decoded the whole image
+ // yet and our repetition count is potentially unset. The repetition count
+ // in a GIF can potentially come after all the rest of the image data, so
+ // wait on it.
+ if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1))
+ return;
+
+ // Determine time for next frame to start. By ignoring paint and timer lag
+ // in this calculation, we make the animation appear to run at its desired
+ // rate regardless of how fast it's being repainted.
+ const double currentDuration = frameDurationAtIndex(m_currentFrame);
+ m_desiredFrameStartTime += currentDuration;
+
+ // When an animated image is more than five minutes out of date, the
+ // user probably doesn't care about resyncing and we could burn a lot of
+ // time looping through frames below. Just reset the timings.
+ const double cAnimationResyncCutoff = 5 * 60;
+ if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff)
+ m_desiredFrameStartTime = time + currentDuration;
+
+ // The image may load more slowly than it's supposed to animate, so that by
+ // the time we reach the end of the first repetition, we're well behind.
+ // Clamp the desired frame start time in this case, so that we don't skip
+ // frames (or whole iterations) trying to "catch up". This is a tradeoff:
+ // It guarantees users see the whole animation the second time through and
+ // don't miss any repetitions, and is closer to what other browsers do; on
+ // the other hand, it makes animations "less accurate" for pages that try to
+ // sync an image and some other resource (e.g. audio), especially if users
+ // switch tabs (and thus stop drawing the animation, which will pause it)
+ // during that initial loop, then switch back later.
+ if (nextFrame == 0 && m_repetitionsComplete == 0 && m_desiredFrameStartTime < time)
+ m_desiredFrameStartTime = time;
+
+ if (!catchUpIfNecessary || time < m_desiredFrameStartTime) {
+ // Haven't yet reached time for next frame to start; delay until then.
+ m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation);
+ m_frameTimer->startOneShot(std::max(m_desiredFrameStartTime - time, 0.));
+ } else {
+ // We've already reached or passed the time for the next frame to start.
+ // See if we've also passed the time for frames after that to start, in
+ // case we need to skip some frames entirely. Remember not to advance
+ // to an incomplete frame.
+ for (size_t frameAfterNext = (nextFrame + 1) % frameCount(); frameIsCompleteAtIndex(frameAfterNext); frameAfterNext = (nextFrame + 1) % frameCount()) {
+ // Should we skip the next frame?
+ double frameAfterNextStartTime = m_desiredFrameStartTime + frameDurationAtIndex(nextFrame);
+ if (time < frameAfterNextStartTime)
+ break;
+
+ // Yes; skip over it without notifying our observers.
+ if (!internalAdvanceAnimation(true))
+ return;
+ m_desiredFrameStartTime = frameAfterNextStartTime;
+ nextFrame = frameAfterNext;
+ }
+
+ // Draw the next frame immediately. Note that m_desiredFrameStartTime
+ // may be in the past, meaning the next time through this function we'll
+ // kick off the next advancement sooner than this frame's duration would
+ // suggest.
+ if (internalAdvanceAnimation(false)) {
+ // The image region has been marked dirty, but once we return to our
+ // caller, draw() will clear it, and nothing will cause the
+ // animation to advance again. We need to start the timer for the
+ // next frame running, or the animation can hang. (Compare this
+ // with when advanceAnimation() is called, and the region is dirtied
+ // while draw() is not in the callstack, meaning draw() gets called
+ // to update the region and thus startAnimation() is reached again.)
+ // NOTE: For large images with slow or heavily-loaded systems,
+ // throwing away data as we go (see destroyDecodedData()) means we
+ // can spend so much time re-decoding data above that by the time we
+ // reach here we're behind again. If we let startAnimation() run
+ // the catch-up code again, we can get long delays without painting
+ // as we race the timer, or even infinite recursion. In this
+ // situation the best we can do is to simply change frames as fast
+ // as possible, so force startAnimation() to set a zero-delay timer
+ // and bail out if we're not caught up.
+ startAnimation(false);
+ }
+ }
+}
+
+void BitmapImage::stopAnimation()
+{
+ // This timer is used to animate all occurrences of this image. Don't invalidate
+ // the timer unless all renderers have stopped drawing.
+ delete m_frameTimer;
+ m_frameTimer = 0;
+}
+
+void BitmapImage::resetAnimation()
+{
+ stopAnimation();
+ m_currentFrame = 0;
+ m_repetitionsComplete = 0;
+ m_desiredFrameStartTime = 0;
+ m_animationFinished = false;
+
+ // For extremely large animations, when the animation is reset, we just throw everything away.
+ destroyDecodedDataIfNecessary(true);
+}
+
+void BitmapImage::advanceAnimation(Timer<BitmapImage>*)
+{
+ internalAdvanceAnimation(false);
+ // At this point the image region has been marked dirty, and if it's
+ // onscreen, we'll soon make a call to draw(), which will call
+ // startAnimation() again to keep the animation moving.
+}
+
+bool BitmapImage::internalAdvanceAnimation(bool skippingFrames)
+{
+ // Stop the animation.
+ stopAnimation();
+
+ // See if anyone is still paying attention to this animation. If not, we don't
+ // advance and will remain suspended at the current frame until the animation is resumed.
+ if (!skippingFrames && imageObserver()->shouldPauseAnimation(this))
+ return false;
+
+ ++m_currentFrame;
+ bool advancedAnimation = true;
+ bool destroyAll = false;
+ if (m_currentFrame >= frameCount()) {
+ ++m_repetitionsComplete;
+
+ // Get the repetition count again. If we weren't able to get a
+ // repetition count before, we should have decoded the whole image by
+ // now, so it should now be available.
+ // Note that we don't need to special-case cAnimationLoopOnce here
+ // because it is 0 (see comments on its declaration in ImageSource.h).
+ if (repetitionCount(true) != cAnimationLoopInfinite && m_repetitionsComplete > m_repetitionCount) {
+ m_animationFinished = true;
+ m_desiredFrameStartTime = 0;
+ --m_currentFrame;
+ advancedAnimation = false;
+ } else {
+ m_currentFrame = 0;
+ destroyAll = true;
+ }
+ }
+ destroyDecodedDataIfNecessary(destroyAll);
+
+ // We need to draw this frame if we advanced to it while not skipping, or if
+ // while trying to skip frames we hit the last frame and thus had to stop.
+ if (skippingFrames != advancedAnimation)
+ imageObserver()->animationAdvanced(this);
+ return advancedAnimation;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/BitmapImage.h b/Source/WebCore/platform/graphics/BitmapImage.h
new file mode 100644
index 0000000..72f3092
--- /dev/null
+++ b/Source/WebCore/platform/graphics/BitmapImage.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008-2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 BitmapImage_h
+#define BitmapImage_h
+
+#include "Image.h"
+#include "Color.h"
+#include "IntSize.h"
+
+#if PLATFORM(MAC)
+#include <wtf/RetainPtr.h>
+#ifdef __OBJC__
+@class NSImage;
+#else
+class NSImage;
+#endif
+#endif
+
+#if PLATFORM(WIN)
+typedef struct HBITMAP__ *HBITMAP;
+#endif
+
+#if PLATFORM(HAIKU)
+class BBitmap;
+#endif
+
+namespace WebCore {
+ struct FrameData;
+}
+
+// This complicated-looking declaration tells the FrameData Vector that it should copy without
+// invoking our constructor or destructor. This allows us to have a vector even for a struct
+// that's not copyable.
+namespace WTF {
+ template<> struct VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits {};
+}
+
+namespace WebCore {
+
+template <typename T> class Timer;
+
+// ================================================
+// FrameData Class
+// ================================================
+
+struct FrameData : Noncopyable {
+ FrameData()
+ : m_frame(0)
+ , m_haveMetadata(false)
+ , m_isComplete(false)
+ , m_duration(0)
+ , m_hasAlpha(true)
+ {
+ }
+
+ ~FrameData()
+ {
+ clear(true);
+ }
+
+ // Clear the cached image data on the frame, and (optionally) the metadata.
+ // Returns whether there was cached image data to clear.
+ bool clear(bool clearMetadata);
+
+ NativeImagePtr m_frame;
+ bool m_haveMetadata;
+ bool m_isComplete;
+ float m_duration;
+ bool m_hasAlpha;
+};
+
+// =================================================
+// BitmapImage Class
+// =================================================
+
+class BitmapImage : public Image {
+ friend class GeneratedImage;
+ friend class GraphicsContext;
+public:
+ static PassRefPtr<BitmapImage> create(NativeImagePtr nativeImage, ImageObserver* observer = 0)
+ {
+ return adoptRef(new BitmapImage(nativeImage, observer));
+ }
+ static PassRefPtr<BitmapImage> create(ImageObserver* observer = 0)
+ {
+ return adoptRef(new BitmapImage(observer));
+ }
+ ~BitmapImage();
+
+ virtual bool isBitmapImage() const { return true; }
+
+ virtual bool hasSingleSecurityOrigin() const { return true; }
+
+ virtual IntSize size() const;
+ IntSize currentFrameSize() const;
+ virtual bool getHotSpot(IntPoint&) const;
+
+ virtual bool dataChanged(bool allDataReceived);
+ virtual String filenameExtension() const;
+
+ // It may look unusual that there is no start animation call as public API. This is because
+ // we start and stop animating lazily. Animation begins whenever someone draws the image. It will
+ // automatically pause once all observers no longer want to render the image anywhere.
+ virtual void stopAnimation();
+ virtual void resetAnimation();
+
+ virtual unsigned decodedSize() const { return m_decodedSize; }
+
+#if PLATFORM(MAC)
+ // Accessors for native image formats.
+ virtual NSImage* getNSImage();
+ virtual CFDataRef getTIFFRepresentation();
+#endif
+
+#if PLATFORM(CG)
+ virtual CGImageRef getCGImageRef();
+#endif
+
+#if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS))
+ static PassRefPtr<BitmapImage> create(HBITMAP);
+#endif
+#if PLATFORM(WIN)
+ virtual bool getHBITMAP(HBITMAP);
+ virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE);
+#endif
+
+#if PLATFORM(ANDROID)
+ virtual void setURL(const String& str);
+#endif
+
+#if PLATFORM(GTK)
+ virtual GdkPixbuf* getGdkPixbuf();
+#endif
+
+ virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); }
+
+protected:
+ enum RepetitionCountStatus {
+ Unknown, // We haven't checked the source's repetition count.
+ Uncertain, // We have a repetition count, but it might be wrong (some GIFs have a count after the image data, and will report "loop once" until all data has been decoded).
+ Certain, // The repetition count is known to be correct.
+ };
+
+ BitmapImage(NativeImagePtr, ImageObserver* = 0);
+ BitmapImage(ImageObserver* = 0);
+
+#if PLATFORM(WIN)
+ virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator);
+#endif
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
+
+#if (OS(WINCE) && !PLATFORM(QT))
+ virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect);
+#endif
+
+#if PLATFORM(HAIKU)
+ virtual BBitmap* getBBitmap() const;
+#endif
+
+ size_t currentFrame() const { return m_currentFrame; }
+ size_t frameCount();
+ NativeImagePtr frameAtIndex(size_t);
+ bool frameIsCompleteAtIndex(size_t);
+ float frameDurationAtIndex(size_t);
+ bool frameHasAlphaAtIndex(size_t);
+
+ // Decodes and caches a frame. Never accessed except internally.
+ void cacheFrame(size_t index);
+
+ // Called to invalidate cached data. When |destroyAll| is true, we wipe out
+ // the entire frame buffer cache and tell the image source to destroy
+ // everything; this is used when e.g. we want to free some room in the image
+ // cache. If |destroyAll| is false, we only delete frames up to the current
+ // one; this is used while animating large images to keep memory footprint
+ // low without redecoding the whole image on every frame.
+ virtual void destroyDecodedData(bool destroyAll = true);
+
+ // If the image is large enough, calls destroyDecodedData() and passes
+ // |destroyAll| along.
+ void destroyDecodedDataIfNecessary(bool destroyAll);
+
+ // Generally called by destroyDecodedData(), destroys whole-image metadata
+ // and notifies observers that the memory footprint has (hopefully)
+ // decreased by |framesCleared| times the size (in bytes) of a frame.
+ void destroyMetadataAndNotify(int framesCleared);
+
+ // Whether or not size is available yet.
+ bool isSizeAvailable();
+
+ // Animation.
+ int repetitionCount(bool imageKnownToBeComplete); // |imageKnownToBeComplete| should be set if the caller knows the entire image has been decoded.
+ bool shouldAnimate();
+ virtual void startAnimation(bool catchUpIfNecessary = true);
+ void advanceAnimation(Timer<BitmapImage>*);
+
+ // Function that does the real work of advancing the animation. When
+ // skippingFrames is true, we're in the middle of a loop trying to skip over
+ // a bunch of animation frames, so we should not do things like decode each
+ // one or notify our observers.
+ // Returns whether the animation was advanced.
+ bool internalAdvanceAnimation(bool skippingFrames);
+
+ // Handle platform-specific data
+ void initPlatformData();
+ void invalidatePlatformData();
+
+ // Checks to see if the image is a 1x1 solid color. We optimize these images and just do a fill rect instead.
+ // This check should happen regardless whether m_checkedForSolidColor is already set, as the frame may have
+ // changed.
+ void checkForSolidColor();
+
+ virtual bool mayFillWithSolidColor()
+ {
+ if (!m_checkedForSolidColor && frameCount() > 0) {
+ checkForSolidColor();
+ // WINCE PORT: checkForSolidColor() doesn't set m_checkedForSolidColor until
+ // it gets enough information to make final decision.
+#if !OS(WINCE)
+ ASSERT(m_checkedForSolidColor);
+#endif
+ }
+ return m_isSolidColor && m_currentFrame == 0;
+ }
+ virtual Color solidColor() const { return m_solidColor; }
+
+ ImageSource m_source;
+ mutable IntSize m_size; // The size to use for the overall image (will just be the size of the first image).
+
+ size_t m_currentFrame; // The index of the current frame of animation.
+ Vector<FrameData> m_frames; // An array of the cached frames of the animation. We have to ref frames to pin them in the cache.
+
+ Timer<BitmapImage>* m_frameTimer;
+ int m_repetitionCount; // How many total animation loops we should do. This will be cAnimationNone if this image type is incapable of animation.
+ RepetitionCountStatus m_repetitionCountStatus;
+ int m_repetitionsComplete; // How many repetitions we've finished.
+ double m_desiredFrameStartTime; // The system time at which we hope to see the next call to startAnimation().
+
+#if PLATFORM(MAC)
+ mutable RetainPtr<NSImage> m_nsImage; // A cached NSImage of frame 0. Only built lazily if someone actually queries for one.
+ mutable RetainPtr<CFDataRef> m_tiffRep; // Cached TIFF rep for frame 0. Only built lazily if someone queries for one.
+#endif
+
+ Color m_solidColor; // If we're a 1x1 solid color, this is the color to use to fill.
+ bool m_isSolidColor; // Whether or not we are a 1x1 solid image.
+ bool m_checkedForSolidColor; // Whether we've checked the frame for solid color.
+
+ bool m_animationFinished; // Whether or not we've completed the entire animation.
+
+ bool m_allDataReceived; // Whether or not we've received all our data.
+
+ mutable bool m_haveSize; // Whether or not our |m_size| member variable has the final overall image size yet.
+ bool m_sizeAvailable; // Whether or not we can obtain the size of the first image frame yet from ImageIO.
+ mutable bool m_hasUniformFrameSize;
+
+ unsigned m_decodedSize; // The current size of all decoded frames.
+
+ mutable bool m_haveFrameCount;
+ size_t m_frameCount;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/Color.cpp b/Source/WebCore/platform/graphics/Color.cpp
new file mode 100644
index 0000000..fa7346e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Color.cpp
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#include "HashTools.h"
+#include "PlatformString.h"
+#include <math.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+
+using namespace std;
+using namespace WTF;
+
+namespace WebCore {
+
+#if !COMPILER(MSVC)
+const RGBA32 Color::black;
+const RGBA32 Color::white;
+const RGBA32 Color::darkGray;
+const RGBA32 Color::gray;
+const RGBA32 Color::lightGray;
+const RGBA32 Color::transparent;
+#endif
+
+static const RGBA32 lightenedBlack = 0xFF545454;
+static const RGBA32 darkenedWhite = 0xFFABABAB;
+
+RGBA32 makeRGB(int r, int g, int b)
+{
+ return 0xFF000000 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
+}
+
+RGBA32 makeRGBA(int r, int g, int b, int a)
+{
+ return max(0, min(a, 255)) << 24 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
+}
+
+static int colorFloatToRGBAByte(float f)
+{
+ // We use lroundf and 255 instead of nextafterf(256, 0) to match CG's rounding
+ return max(0, min(static_cast<int>(lroundf(255.0f * f)), 255));
+}
+
+RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a)
+{
+ return colorFloatToRGBAByte(a) << 24 | colorFloatToRGBAByte(r) << 16 | colorFloatToRGBAByte(g) << 8 | colorFloatToRGBAByte(b);
+}
+
+RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha)
+{
+ RGBA32 rgbOnly = color & 0x00FFFFFF;
+ RGBA32 rgba = rgbOnly | colorFloatToRGBAByte(overrideAlpha) << 24;
+ return rgba;
+}
+
+static double calcHue(double temp1, double temp2, double hueVal)
+{
+ if (hueVal < 0.0)
+ hueVal++;
+ else if (hueVal > 1.0)
+ hueVal--;
+ if (hueVal * 6.0 < 1.0)
+ return temp1 + (temp2 - temp1) * hueVal * 6.0;
+ if (hueVal * 2.0 < 1.0)
+ return temp2;
+ if (hueVal * 3.0 < 2.0)
+ return temp1 + (temp2 - temp1) * (2.0 / 3.0 - hueVal) * 6.0;
+ return temp1;
+}
+
+// Explanation of this algorithm can be found in the CSS3 Color Module
+// specification at http://www.w3.org/TR/css3-color/#hsl-color with further
+// explanation available at http://en.wikipedia.org/wiki/HSL_color_space
+
+// all values are in the range of 0 to 1.0
+RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double alpha)
+{
+ const double scaleFactor = nextafter(256.0, 0.0);
+
+ if (!saturation) {
+ int greyValue = static_cast<int>(lightness * scaleFactor);
+ return makeRGBA(greyValue, greyValue, greyValue, static_cast<int>(alpha * scaleFactor));
+ }
+
+ double temp2 = lightness < 0.5 ? lightness * (1.0 + saturation) : lightness + saturation - lightness * saturation;
+ double temp1 = 2.0 * lightness - temp2;
+
+ return makeRGBA(static_cast<int>(calcHue(temp1, temp2, hue + 1.0 / 3.0) * scaleFactor),
+ static_cast<int>(calcHue(temp1, temp2, hue) * scaleFactor),
+ static_cast<int>(calcHue(temp1, temp2, hue - 1.0 / 3.0) * scaleFactor),
+ static_cast<int>(alpha * scaleFactor));
+}
+
+RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a)
+{
+ double colors = 1 - k;
+ int r = static_cast<int>(nextafter(256, 0) * (colors * (1 - c)));
+ int g = static_cast<int>(nextafter(256, 0) * (colors * (1 - m)));
+ int b = static_cast<int>(nextafter(256, 0) * (colors * (1 - y)));
+ return makeRGBA(r, g, b, static_cast<float>(nextafter(256, 0) * a));
+}
+
+// originally moved here from the CSS parser
+bool Color::parseHexColor(const UChar* name, unsigned length, RGBA32& rgb)
+{
+ if (length != 3 && length != 6)
+ return false;
+ unsigned value = 0;
+ for (unsigned i = 0; i < length; ++i) {
+ if (!isASCIIHexDigit(name[i]))
+ return false;
+ value <<= 4;
+ value |= toASCIIHexValue(name[i]);
+ }
+ if (length == 6) {
+ rgb = 0xFF000000 | value;
+ return true;
+ }
+ // #abc converts to #aabbcc
+ rgb = 0xFF000000
+ | (value & 0xF00) << 12 | (value & 0xF00) << 8
+ | (value & 0xF0) << 8 | (value & 0xF0) << 4
+ | (value & 0xF) << 4 | (value & 0xF);
+ return true;
+}
+
+bool Color::parseHexColor(const String& name, RGBA32& rgb)
+{
+ return parseHexColor(name.characters(), name.length(), rgb);
+}
+
+int differenceSquared(const Color& c1, const Color& c2)
+{
+ int dR = c1.red() - c2.red();
+ int dG = c1.green() - c2.green();
+ int dB = c1.blue() - c2.blue();
+ return dR * dR + dG * dG + dB * dB;
+}
+
+Color::Color(const String& name)
+{
+ if (name[0] == '#')
+ m_valid = parseHexColor(name.characters() + 1, name.length() - 1, m_color);
+ else
+ setNamedColor(name);
+}
+
+Color::Color(const char* name)
+{
+ if (name[0] == '#')
+ m_valid = parseHexColor(&name[1], m_color);
+ else {
+ const NamedColor* foundColor = findColor(name, strlen(name));
+ m_color = foundColor ? foundColor->ARGBValue : 0;
+ m_valid = foundColor;
+ }
+}
+
+String Color::serialized() const
+{
+ if (alpha() == 0xFF)
+ return String::format("#%02x%02x%02x", red(), green(), blue());
+
+ // Match Gecko ("0.0" for zero, 5 decimals for anything else)
+ if (!alpha())
+ return String::format("rgba(%u, %u, %u, 0.0)", red(), green(), blue());
+
+ return String::format("rgba(%u, %u, %u, %.5f)", red(), green(), blue(), alpha() / 255.0f);
+}
+
+String Color::name() const
+{
+ if (alpha() < 0xFF)
+ return String::format("#%02X%02X%02X%02X", red(), green(), blue(), alpha());
+ return String::format("#%02X%02X%02X", red(), green(), blue());
+}
+
+static inline const NamedColor* findNamedColor(const String& name)
+{
+ char buffer[64]; // easily big enough for the longest color name
+ unsigned length = name.length();
+ if (length > sizeof(buffer) - 1)
+ return 0;
+ for (unsigned i = 0; i < length; ++i) {
+ UChar c = name[i];
+ if (!c || c > 0x7F)
+ return 0;
+ buffer[i] = toASCIILower(static_cast<char>(c));
+ }
+ buffer[length] = '\0';
+ return findColor(buffer, length);
+}
+
+void Color::setNamedColor(const String& name)
+{
+ const NamedColor* foundColor = findNamedColor(name);
+ m_color = foundColor ? foundColor->ARGBValue : 0;
+ m_valid = foundColor;
+}
+
+Color Color::light() const
+{
+ // Hardcode this common case for speed.
+ if (m_color == black)
+ return lightenedBlack;
+
+ const float scaleFactor = nextafterf(256.0f, 0.0f);
+
+ float r, g, b, a;
+ getRGBA(r, g, b, a);
+
+ float v = max(r, max(g, b));
+
+ if (v == 0.0f)
+ // Lightened black with alpha.
+ return Color(0x54, 0x54, 0x54, alpha());
+
+ float multiplier = min(1.0f, v + 0.33f) / v;
+
+ return Color(static_cast<int>(multiplier * r * scaleFactor),
+ static_cast<int>(multiplier * g * scaleFactor),
+ static_cast<int>(multiplier * b * scaleFactor),
+ alpha());
+}
+
+Color Color::dark() const
+{
+ // Hardcode this common case for speed.
+ if (m_color == white)
+ return darkenedWhite;
+
+ const float scaleFactor = nextafterf(256.0f, 0.0f);
+
+ float r, g, b, a;
+ getRGBA(r, g, b, a);
+
+ float v = max(r, max(g, b));
+ float multiplier = max(0.0f, (v - 0.33f) / v);
+
+ return Color(static_cast<int>(multiplier * r * scaleFactor),
+ static_cast<int>(multiplier * g * scaleFactor),
+ static_cast<int>(multiplier * b * scaleFactor),
+ alpha());
+}
+
+static int blendComponent(int c, int a)
+{
+ // We use white.
+ float alpha = a / 255.0f;
+ int whiteBlend = 255 - a;
+ c -= whiteBlend;
+ return static_cast<int>(c / alpha);
+}
+
+const int cStartAlpha = 153; // 60%
+const int cEndAlpha = 204; // 80%;
+const int cAlphaIncrement = 17; // Increments in between.
+
+Color Color::blend(const Color& source) const
+{
+ if (!alpha() || !source.hasAlpha())
+ return source;
+
+ if (!source.alpha())
+ return *this;
+
+ int d = 255 * (alpha() + source.alpha()) - alpha() * source.alpha();
+ int a = d / 255;
+ int r = (red() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.red()) / d;
+ int g = (green() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.green()) / d;
+ int b = (blue() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.blue()) / d;
+ return Color(r, g, b, a);
+}
+
+Color Color::blendWithWhite() const
+{
+ // If the color contains alpha already, we leave it alone.
+ if (hasAlpha())
+ return *this;
+
+ Color newColor;
+ for (int alpha = cStartAlpha; alpha <= cEndAlpha; alpha += cAlphaIncrement) {
+ // We have a solid color. Convert to an equivalent color that looks the same when blended with white
+ // at the current alpha. Try using less transparency if the numbers end up being negative.
+ int r = blendComponent(red(), alpha);
+ int g = blendComponent(green(), alpha);
+ int b = blendComponent(blue(), alpha);
+
+ newColor = Color(r, g, b, alpha);
+
+ if (r >= 0 && g >= 0 && b >= 0)
+ break;
+ }
+ return newColor;
+}
+
+void Color::getRGBA(float& r, float& g, float& b, float& a) const
+{
+ r = red() / 255.0f;
+ g = green() / 255.0f;
+ b = blue() / 255.0f;
+ a = alpha() / 255.0f;
+}
+
+void Color::getRGBA(double& r, double& g, double& b, double& a) const
+{
+ r = red() / 255.0;
+ g = green() / 255.0;
+ b = blue() / 255.0;
+ a = alpha() / 255.0;
+}
+
+void Color::getHSL(double& hue, double& saturation, double& lightness) const
+{
+ // http://en.wikipedia.org/wiki/HSL_color_space. This is a direct copy of
+ // the algorithm therein, although it's 360^o based and we end up wanting
+ // [0...1) based. It's clearer if we stick to 360^o until the end.
+ double r = static_cast<double>(red()) / 255.0;
+ double g = static_cast<double>(green()) / 255.0;
+ double b = static_cast<double>(blue()) / 255.0;
+ double max = std::max(std::max(r, g), b);
+ double min = std::min(std::min(r, g), b);
+
+ if (max == min)
+ hue = 0.0;
+ else if (max == r)
+ hue = (60.0 * ((g - b) / (max - min))) + 360.0;
+ else if (max == g)
+ hue = (60.0 * ((b - r) / (max - min))) + 120.0;
+ else
+ hue = (60.0 * ((r - g) / (max - min))) + 240.0;
+
+ if (hue >= 360.0)
+ hue -= 360.0;
+
+ // makeRGBAFromHSLA assumes that hue is in [0...1).
+ hue /= 360.0;
+
+ lightness = 0.5 * (max + min);
+ if (max == min)
+ saturation = 0.0;
+ else if (lightness <= 0.5)
+ saturation = ((max - min) / (max + min));
+ else
+ saturation = ((max - min) / (2.0 - (max + min)));
+}
+
+Color colorFromPremultipliedARGB(unsigned pixelColor)
+{
+ RGBA32 rgba;
+
+ if (unsigned alpha = (pixelColor & 0xFF000000) >> 24) {
+ rgba = makeRGBA(((pixelColor & 0x00FF0000) >> 16) * 255 / alpha,
+ ((pixelColor & 0x0000FF00) >> 8) * 255 / alpha,
+ (pixelColor & 0x000000FF) * 255 / alpha,
+ alpha);
+ } else
+ rgba = pixelColor;
+
+ return Color(rgba);
+}
+
+unsigned premultipliedARGBFromColor(const Color& color)
+{
+ unsigned pixelColor;
+
+ if (unsigned alpha = color.alpha()) {
+ pixelColor = alpha << 24 |
+ ((color.red() * alpha + 254) / 255) << 16 |
+ ((color.green() * alpha + 254) / 255) << 8 |
+ ((color.blue() * alpha + 254) / 255);
+ } else
+ pixelColor = color.rgb();
+
+ return pixelColor;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/Color.h b/Source/WebCore/platform/graphics/Color.h
new file mode 100644
index 0000000..fa37d32
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Color.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 Color_h
+#define Color_h
+
+#include <wtf/FastAllocBase.h>
+#include <wtf/Forward.h>
+#include <wtf/unicode/Unicode.h>
+
+#if PLATFORM(CG)
+#include "ColorSpace.h"
+typedef struct CGColor* CGColorRef;
+#endif
+
+#if PLATFORM(QT)
+#include <qglobal.h>
+QT_BEGIN_NAMESPACE
+class QColor;
+QT_END_NAMESPACE
+#endif
+
+#if PLATFORM(GTK)
+typedef struct _GdkColor GdkColor;
+#ifndef GTK_API_VERSION_2
+typedef struct _GdkRGBA GdkRGBA;
+#endif
+#endif
+
+#if PLATFORM(WX)
+class wxColour;
+#endif
+
+#if PLATFORM(HAIKU)
+struct rgb_color;
+#endif
+
+namespace WebCore {
+
+class Color;
+
+typedef unsigned RGBA32; // RGBA quadruplet
+
+RGBA32 makeRGB(int r, int g, int b);
+RGBA32 makeRGBA(int r, int g, int b, int a);
+
+RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha);
+RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a);
+RGBA32 makeRGBAFromHSLA(double h, double s, double l, double a);
+RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a);
+
+int differenceSquared(const Color&, const Color&);
+
+inline int redChannel(RGBA32 color) { return (color >> 16) & 0xFF; }
+inline int greenChannel(RGBA32 color) { return (color >> 8) & 0xFF; }
+inline int blueChannel(RGBA32 color) { return color & 0xFF; }
+inline int alphaChannel(RGBA32 color) { return (color >> 24) & 0xFF; }
+
+class Color : public FastAllocBase {
+public:
+ Color() : m_color(0), m_valid(false) { }
+ Color(RGBA32 col) : m_color(col), m_valid(true) { }
+ Color(int r, int g, int b) : m_color(makeRGB(r, g, b)), m_valid(true) { }
+ Color(int r, int g, int b, int a) : m_color(makeRGBA(r, g, b, a)), m_valid(true) { }
+ // Color is currently limited to 32bit RGBA, perhaps some day we'll support better colors
+ Color(float r, float g, float b, float a) : m_color(makeRGBA32FromFloats(r, g, b, a)), m_valid(true) { }
+ // Creates a new color from the specific CMYK and alpha values.
+ Color(float c, float m, float y, float k, float a) : m_color(makeRGBAFromCMYKA(c, m, y, k, a)), m_valid(true) { }
+ explicit Color(const String&);
+ explicit Color(const char*);
+
+ // Returns the color serialized according to HTML5
+ // - http://www.whatwg.org/specs/web-apps/current-work/#serialization-of-a-color
+ String serialized() const;
+
+ String name() const;
+ void setNamedColor(const String&);
+
+ bool isValid() const { return m_valid; }
+
+ bool hasAlpha() const { return alpha() < 255; }
+
+ int red() const { return redChannel(m_color); }
+ int green() const { return greenChannel(m_color); }
+ int blue() const { return blueChannel(m_color); }
+ int alpha() const { return alphaChannel(m_color); }
+
+ RGBA32 rgb() const { return m_color; } // Preserve the alpha.
+ void setRGB(int r, int g, int b) { m_color = makeRGB(r, g, b); m_valid = true; }
+ void setRGB(RGBA32 rgb) { m_color = rgb; m_valid = true; }
+ void getRGBA(float& r, float& g, float& b, float& a) const;
+ void getRGBA(double& r, double& g, double& b, double& a) const;
+ void getHSL(double& h, double& s, double& l) const;
+
+ Color light() const;
+ Color dark() const;
+
+ Color blend(const Color&) const;
+ Color blendWithWhite() const;
+
+#if PLATFORM(QT)
+ Color(const QColor&);
+ operator QColor() const;
+#endif
+
+#if PLATFORM(GTK)
+ Color(const GdkColor&);
+ // We can't sensibly go back to GdkColor without losing the alpha value
+#ifndef GTK_API_VERSION_2
+ Color(const GdkRGBA&);
+ operator GdkRGBA() const;
+#endif
+#endif
+
+#if PLATFORM(WX)
+ Color(const wxColour&);
+ operator wxColour() const;
+#endif
+
+#if PLATFORM(CG)
+ Color(CGColorRef);
+#endif
+
+#if PLATFORM(HAIKU)
+ Color(const rgb_color&);
+ operator rgb_color() const;
+#endif
+
+ static bool parseHexColor(const String& name, RGBA32& rgb);
+ static bool parseHexColor(const UChar* name, unsigned length, RGBA32& rgb);
+
+ static const RGBA32 black = 0xFF000000;
+ static const RGBA32 white = 0xFFFFFFFF;
+ static const RGBA32 darkGray = 0xFF808080;
+ static const RGBA32 gray = 0xFFA0A0A0;
+ static const RGBA32 lightGray = 0xFFC0C0C0;
+ static const RGBA32 transparent = 0x00000000;
+
+#ifdef ANDROID_CSS_RING
+ static const RGBA32 ringFill = 0x666699FF;
+ static const RGBA32 ringPressedInner = 0x006699FF;
+ static const RGBA32 ringPressedOuter = 0x336699FF;
+ static const RGBA32 ringSelectedInner = 0xAA6699FF;
+ static const RGBA32 ringSelectedOuter = 0x336699FF;
+#endif
+#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
+ static const RGBA32 tap = 0x4D1A1A1A;
+#endif
+
+private:
+ RGBA32 m_color;
+ bool m_valid;
+};
+
+inline bool operator==(const Color& a, const Color& b)
+{
+ return a.rgb() == b.rgb() && a.isValid() == b.isValid();
+}
+
+inline bool operator!=(const Color& a, const Color& b)
+{
+ return !(a == b);
+}
+
+Color colorFromPremultipliedARGB(unsigned);
+unsigned premultipliedARGBFromColor(const Color&);
+
+#if PLATFORM(CG)
+CGColorRef cachedCGColor(const Color&, ColorSpace);
+#endif
+
+} // namespace WebCore
+
+#endif // Color_h
diff --git a/Source/WebCore/platform/graphics/ColorSpace.h b/Source/WebCore/platform/graphics/ColorSpace.h
new file mode 100644
index 0000000..7622c47
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ColorSpace.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 ColorSpace_h
+#define ColorSpace_h
+
+namespace WebCore {
+
+enum ColorSpace {
+ ColorSpaceDeviceRGB,
+ ColorSpaceSRGB,
+ ColorSpaceLinearRGB
+};
+
+} // namespace WebCore
+
+#endif // ColorSpace_h
diff --git a/Source/WebCore/platform/graphics/ContextShadow.cpp b/Source/WebCore/platform/graphics/ContextShadow.cpp
new file mode 100644
index 0000000..7becda7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ContextShadow.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2010 Sencha, Inc.
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ContextShadow.h"
+
+#include "AffineTransform.h"
+#include "FloatQuad.h"
+#include "GraphicsContext.h"
+#include <cmath>
+#include <wtf/MathExtras.h>
+#include <wtf/Noncopyable.h>
+
+using WTF::min;
+using WTF::max;
+
+namespace WebCore {
+
+ContextShadow::ContextShadow()
+ : m_type(NoShadow)
+ , m_blurDistance(0)
+ , m_layerContext(0)
+ , m_shadowsIgnoreTransforms(false)
+{
+}
+
+ContextShadow::ContextShadow(const Color& color, float radius, const FloatSize& offset)
+ : m_color(color)
+ , m_blurDistance(round(radius))
+ , m_offset(offset)
+ , m_layerContext(0)
+ , m_shadowsIgnoreTransforms(false)
+{
+ // See comments in http://webkit.org/b/40793, it seems sensible
+ // to follow Skia's limit of 128 pixels of blur radius
+ m_blurDistance = min(m_blurDistance, 128);
+
+ // The type of shadow is decided by the blur radius, shadow offset, and shadow color.
+ if (!m_color.isValid() || !color.alpha()) {
+ // Can't paint the shadow with invalid or invisible color.
+ m_type = NoShadow;
+ } else if (radius > 0) {
+ // Shadow is always blurred, even the offset is zero.
+ m_type = BlurShadow;
+ } else if (!m_offset.width() && !m_offset.height()) {
+ // Without blur and zero offset means the shadow is fully hidden.
+ m_type = NoShadow;
+ } else {
+ m_type = SolidShadow;
+ }
+}
+
+void ContextShadow::clear()
+{
+ m_type = NoShadow;
+ m_color = Color();
+ m_blurDistance = 0;
+ m_offset = FloatSize();
+}
+
+bool ContextShadow::mustUseContextShadow(GraphicsContext* context)
+{
+ // We can't avoid ContextShadow, since the shadow has blur.
+ if (m_type == ContextShadow::BlurShadow)
+ return true;
+ // We can avoid ContextShadow and optimize, since we're not drawing on a
+ // canvas and box shadows are affected by the transformation matrix.
+ if (!shadowsIgnoreTransforms())
+ return false;
+ // We can avoid ContextShadow, since there are no transformations to apply to the canvas.
+ if (context->getCTM().isIdentity())
+ return false;
+ // Otherwise, no chance avoiding ContextShadow.
+ return true;
+}
+
+// Instead of integer division, we use 17.15 for fixed-point division.
+static const int BlurSumShift = 15;
+
+// Check http://www.w3.org/TR/SVG/filters.html#feGaussianBlur.
+// As noted in the SVG filter specification, running box blur 3x
+// approximates a real gaussian blur nicely.
+
+void ContextShadow::blurLayerImage(unsigned char* imageData, const IntSize& size, int rowStride)
+{
+#if CPU(BIG_ENDIAN)
+ int channels[4] = { 0, 3, 2, 0 };
+#elif CPU(MIDDLE_ENDIAN)
+ int channels[4] = { 1, 2, 3, 1 };
+#else
+ int channels[4] = { 3, 0, 1, 3 };
+#endif
+
+ int d = max(2, static_cast<int>(floorf((2 / 3.f) * m_blurDistance)));
+ int dmax = d >> 1;
+ int dmin = dmax - 1 + (d & 1);
+ if (dmin < 0)
+ dmin = 0;
+
+ // Two stages: horizontal and vertical
+ for (int k = 0; k < 2; ++k) {
+
+ unsigned char* pixels = imageData;
+ int stride = (!k) ? 4 : rowStride;
+ int delta = (!k) ? rowStride : 4;
+ int jfinal = (!k) ? size.height() : size.width();
+ int dim = (!k) ? size.width() : size.height();
+
+ for (int j = 0; j < jfinal; ++j, pixels += delta) {
+
+ // For each step, we blur the alpha in a channel and store the result
+ // in another channel for the subsequent step.
+ // We use sliding window algorithm to accumulate the alpha values.
+ // This is much more efficient than computing the sum of each pixels
+ // covered by the box kernel size for each x.
+
+ for (int step = 0; step < 3; ++step) {
+ int side1 = (!step) ? dmin : dmax;
+ int side2 = (step == 1) ? dmin : dmax;
+ int pixelCount = side1 + 1 + side2;
+ int invCount = ((1 << BlurSumShift) + pixelCount - 1) / pixelCount;
+ int ofs = 1 + side2;
+ int alpha1 = pixels[channels[step]];
+ int alpha2 = pixels[(dim - 1) * stride + channels[step]];
+ unsigned char* ptr = pixels + channels[step + 1];
+ unsigned char* prev = pixels + stride + channels[step];
+ unsigned char* next = pixels + ofs * stride + channels[step];
+
+ int i;
+ int sum = side1 * alpha1 + alpha1;
+ int limit = (dim < side2 + 1) ? dim : side2 + 1;
+ for (i = 1; i < limit; ++i, prev += stride)
+ sum += *prev;
+ if (limit <= side2)
+ sum += (side2 - limit + 1) * alpha2;
+
+ limit = (side1 < dim) ? side1 : dim;
+ for (i = 0; i < limit; ptr += stride, next += stride, ++i, ++ofs) {
+ *ptr = (sum * invCount) >> BlurSumShift;
+ sum += ((ofs < dim) ? *next : alpha2) - alpha1;
+ }
+ prev = pixels + channels[step];
+ for (; ofs < dim; ptr += stride, prev += stride, next += stride, ++i, ++ofs) {
+ *ptr = (sum * invCount) >> BlurSumShift;
+ sum += (*next) - (*prev);
+ }
+ for (; i < dim; ptr += stride, prev += stride, ++i) {
+ *ptr = (sum * invCount) >> BlurSumShift;
+ sum += alpha2 - (*prev);
+ }
+ }
+ }
+ }
+}
+
+void ContextShadow::adjustBlurDistance(GraphicsContext* context)
+{
+ const AffineTransform transform = context->getCTM();
+
+ // Adjust blur if we're scaling, since the radius must not be affected by transformations.
+ if (transform.isIdentity())
+ return;
+
+ // Calculate transformed unit vectors.
+ const FloatQuad unitQuad(FloatPoint(0, 0), FloatPoint(1, 0),
+ FloatPoint(0, 1), FloatPoint(1, 1));
+ const FloatQuad transformedUnitQuad = transform.mapQuad(unitQuad);
+
+ // Calculate X axis scale factor.
+ const FloatSize xUnitChange = transformedUnitQuad.p2() - transformedUnitQuad.p1();
+ const float xAxisScale = sqrtf(xUnitChange.width() * xUnitChange.width()
+ + xUnitChange.height() * xUnitChange.height());
+
+ // Calculate Y axis scale factor.
+ const FloatSize yUnitChange = transformedUnitQuad.p3() - transformedUnitQuad.p1();
+ const float yAxisScale = sqrtf(yUnitChange.width() * yUnitChange.width()
+ + yUnitChange.height() * yUnitChange.height());
+
+ // blurLayerImage() does not support per-axis blurring, so calculate a balanced scaling.
+ const float scale = sqrtf(xAxisScale * yAxisScale);
+ m_blurDistance = roundf(static_cast<float>(m_blurDistance) / scale);
+}
+
+IntRect ContextShadow::calculateLayerBoundingRect(GraphicsContext* context, const FloatRect& layerArea, const IntRect& clipRect)
+{
+ // Calculate the destination of the blurred and/or transformed layer.
+ FloatRect layerFloatRect;
+ float inflation = 0;
+
+ const AffineTransform transform = context->getCTM();
+ if (m_shadowsIgnoreTransforms && !transform.isIdentity()) {
+ FloatQuad transformedPolygon = transform.mapQuad(FloatQuad(layerArea));
+ transformedPolygon.move(m_offset);
+ layerFloatRect = transform.inverse().mapQuad(transformedPolygon).boundingBox();
+ } else {
+ layerFloatRect = layerArea;
+ layerFloatRect.move(m_offset);
+ }
+
+ // We expand the area by the blur radius to give extra space for the blur transition.
+ if (m_type == BlurShadow) {
+ layerFloatRect.inflate(m_blurDistance);
+ inflation += m_blurDistance;
+ }
+
+ FloatRect unclippedLayerRect = layerFloatRect;
+
+ if (!clipRect.contains(enclosingIntRect(layerFloatRect))) {
+ // No need to have the buffer larger than the clip.
+ layerFloatRect.intersect(clipRect);
+
+ // If we are totally outside the clip region, we aren't painting at all.
+ if (layerFloatRect.isEmpty())
+ return IntRect(0, 0, 0, 0);
+
+ // We adjust again because the pixels at the borders are still
+ // potentially affected by the pixels outside the buffer.
+ if (m_type == BlurShadow) {
+ layerFloatRect.inflate(m_blurDistance);
+ unclippedLayerRect.inflate(m_blurDistance);
+ inflation += m_blurDistance;
+ }
+ }
+
+ const int frameSize = inflation * 2;
+ m_sourceRect = IntRect(0, 0, layerArea.width() + frameSize, layerArea.height() + frameSize);
+ m_layerOrigin = FloatPoint(layerFloatRect.x(), layerFloatRect.y());
+
+ const FloatPoint m_unclippedLayerOrigin = FloatPoint(unclippedLayerRect.x(), unclippedLayerRect.y());
+ const FloatSize clippedOut = m_unclippedLayerOrigin - m_layerOrigin;
+
+ // Set the origin as the top left corner of the scratch image, or, in case there's a clipped
+ // out region, set the origin accordingly to the full bounding rect's top-left corner.
+ const float translationX = -layerArea.x() + inflation - fabsf(clippedOut.width());
+ const float translationY = -layerArea.y() + inflation - fabsf(clippedOut.height());
+ m_layerContextTranslation = FloatPoint(translationX, translationY);
+
+ return enclosingIntRect(layerFloatRect);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/ContextShadow.h b/Source/WebCore/platform/graphics/ContextShadow.h
new file mode 100644
index 0000000..a1fba5c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ContextShadow.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2010 Sencha, Inc.
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ContextShadow_h
+#define ContextShadow_h
+
+#include "Color.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "RefCounted.h"
+
+#if PLATFORM(CAIRO)
+typedef struct _cairo cairo_t;
+typedef struct _cairo_surface cairo_surface_t;
+#elif PLATFORM(QT)
+#include <QImage>
+QT_BEGIN_NAMESPACE
+class QPainter;
+QT_END_NAMESPACE
+#endif
+
+namespace WebCore {
+
+class AffineTransform;
+class GraphicsContext;
+
+#if PLATFORM(CAIRO)
+typedef cairo_surface_t* PlatformImage;
+typedef cairo_t* PlatformContext;
+#elif PLATFORM(QT)
+typedef QImage PlatformImage;
+typedef QPainter* PlatformContext;
+#else
+typedef void* PlatformImage;
+typedef void* PlatformContext;
+#endif
+
+// This is to track and keep the shadow state. We use this rather than
+// using GraphicsContextState to allow possible optimizations (right now
+// only to determine the shadow type, but in future it might covers things
+// like cached scratch image, persistent shader, etc).
+
+// This class should be copyable since GraphicsContextQt keeps a stack of
+// the shadow state for savePlatformState and restorePlatformState.
+
+class ContextShadow {
+public:
+ enum {
+ NoShadow,
+ SolidShadow,
+ BlurShadow
+ } m_type;
+
+ Color m_color;
+ int m_blurDistance;
+ FloatSize m_offset;
+
+ ContextShadow();
+ ContextShadow(const Color&, float radius, const FloatSize& offset);
+
+ bool mustUseContextShadow(GraphicsContext*);
+ void clear();
+
+ // The pair beginShadowLayer and endShadowLayer creates a temporary image
+ // where the caller can draw onto, using the returned context. This context
+ // must be used only to draw between the call to beginShadowLayer and
+ // endShadowLayer.
+ //
+ // Note: multiple/nested shadow layers are NOT allowed.
+ //
+ // The current clip region will be used to optimize the size of the
+ // temporary image. Thus, the original context should not change any
+ // clipping until endShadowLayer. If the shadow will be completely outside
+ // the clipping region, beginShadowLayer will return 0.
+ //
+ // The returned context will have the transformation matrix and clipping
+ // properly initialized to start doing the painting (no need to account for
+ // the shadow offset), however it will not have the same render hints, pen,
+ // brush, etc as the passed context. This is intentional, usually shadows
+ // have different properties than the shapes which cast them.
+ //
+ // Once endShadowLayer is called, the temporary image will be drawn with the
+ // original context. If blur radius is specified, the shadow will be
+ // filtered first.
+
+ PlatformContext beginShadowLayer(GraphicsContext*, const FloatRect& layerArea);
+ void endShadowLayer(GraphicsContext*);
+ static void purgeScratchBuffer();
+
+ void setShadowsIgnoreTransforms(bool enable) { m_shadowsIgnoreTransforms = enable; }
+ bool shadowsIgnoreTransforms() const { return m_shadowsIgnoreTransforms; }
+#if PLATFORM(CAIRO)
+ void drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius = IntSize(), const IntSize& topRightRadius = IntSize(), const IntSize& bottomLeftRadius = IntSize(), const IntSize& bottomRightRadius = IntSize());
+#endif
+#if PLATFORM(QT)
+ QPointF offset() const { return QPointF(m_offset.width(), m_offset.height()); }
+#endif
+
+private:
+ PlatformImage m_layerImage; // Buffer to where the temporary shadow will be drawn to.
+ PlatformContext m_layerContext; // Context used to paint the shadow to the layer image.
+ FloatRect m_sourceRect; // Sub-rect of m_layerImage that contains the shadow pixels.
+ FloatPoint m_layerOrigin; // Top-left corner of the (possibly clipped) bounding rect to draw the shadow to.
+ FloatPoint m_layerContextTranslation; // Translation to apply to m_layerContext for the shadow to be correctly clipped.
+ bool m_shadowsIgnoreTransforms;
+
+ void adjustBlurDistance(GraphicsContext*);
+ void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride);
+ IntRect calculateLayerBoundingRect(GraphicsContext*, const FloatRect& layerArea, const IntRect& clipRect);
+
+#if PLATFORM(CAIRO)
+ void drawRectShadowWithoutTiling(GraphicsContext*, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha);
+#endif
+};
+
+} // namespace WebCore
+
+#endif // ContextShadow_h
diff --git a/Source/WebCore/platform/graphics/DashArray.h b/Source/WebCore/platform/graphics/DashArray.h
new file mode 100644
index 0000000..46b84a4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/DashArray.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 DashArray_h
+#define DashArray_h
+
+#include <wtf/Vector.h>
+
+#if PLATFORM(CG)
+typedef Vector<CGFloat> DashArray;
+#elif PLATFORM(CAIRO)
+typedef Vector<double> DashArray;
+#else
+typedef Vector<float> DashArray;
+#endif
+
+#endif // DashArray_h
diff --git a/Source/WebCore/platform/graphics/Extensions3D.h b/Source/WebCore/platform/graphics/Extensions3D.h
new file mode 100644
index 0000000..0363a48
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Extensions3D.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 Extensions3D_h
+#define Extensions3D_h
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+// This is a base class containing only pure virtual functions.
+// Implementations must provide a subclass.
+//
+// The supported extensions are defined below and in subclasses,
+// possibly platform-specific ones.
+//
+// Calling any extension function not supported by the current context
+// must be a no-op; in particular, it may not have side effects. In
+// this situation, if the function has a return value, 0 is returned.
+class Extensions3D {
+public:
+ virtual ~Extensions3D() {}
+
+ // Supported extensions:
+ // GL_EXT_texture_format_BGRA8888
+ // GL_EXT_read_format_bgra
+ // GL_ARB_robustness
+ // GL_ARB_texture_non_power_of_two / GL_OES_texture_npot
+ // GL_EXT_packed_depth_stencil / GL_OES_packed_depth_stencil
+ // GL_ANGLE_framebuffer_blit / GL_ANGLE_framebuffer_multisample
+ // GL_OES_texture_float
+
+ // Takes full name of extension; for example,
+ // "GL_EXT_texture_format_BGRA8888".
+ virtual bool supports(const String&) = 0;
+
+ // Certain OpenGL and WebGL implementations may support enabling
+ // extensions lazily. This method may only be called with
+ // extension names for which supports returns true.
+ virtual void ensureEnabled(const String&) = 0;
+
+ enum ExtensionsEnumType {
+ // GL_EXT_texture_format_BGRA8888 enums
+ BGRA_EXT = 0x80E1,
+
+ // GL_ARB_robustness enums
+ GUILTY_CONTEXT_RESET_ARB = 0x8253,
+ INNOCENT_CONTEXT_RESET_ARB = 0x8254,
+ UNKNOWN_CONTEXT_RESET_ARB = 0x8255,
+
+ // GL_EXT/OES_packed_depth_stencil enums
+ DEPTH24_STENCIL8 = 0x88F0,
+
+ // GL_ANGLE_framebuffer_blit names
+ READ_FRAMEBUFFER = 0x8CA8,
+ DRAW_FRAMEBUFFER = 0x8CA9,
+ DRAW_FRAMEBUFFER_BINDING = 0x8CA6,
+ READ_FRAMEBUFFER_BINDING = 0x8CAA,
+
+ // GL_ANGLE_framebuffer_multisample names
+ RENDERBUFFER_SAMPLES = 0x8CAB,
+ FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 0x8D56,
+ MAX_SAMPLES = 0x8D57
+ };
+
+ // GL_ARB_robustness
+ virtual int getGraphicsResetStatusARB() = 0;
+
+ // GL_ANGLE_framebuffer_blit
+ virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter) = 0;
+
+ // GL_ANGLE_framebuffer_multisample
+ virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height) = 0;
+};
+
+} // namespace WebCore
+
+#endif // Extensions3D_h
diff --git a/Source/WebCore/platform/graphics/FloatPoint.cpp b/Source/WebCore/platform/graphics/FloatPoint.cpp
new file mode 100644
index 0000000..7e85b52
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatPoint.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatPoint.h"
+
+#include "TransformationMatrix.h"
+#include "FloatConversion.h"
+#include "IntPoint.h"
+#include <math.h>
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const IntPoint& p) : m_x(p.x()), m_y(p.y())
+{
+}
+
+void FloatPoint::normalize()
+{
+ float tempLength = length();
+
+ if (tempLength) {
+ m_x /= tempLength;
+ m_y /= tempLength;
+ }
+}
+
+float FloatPoint::length() const
+{
+ return sqrtf(lengthSquared());
+}
+
+FloatPoint FloatPoint::matrixTransform(const AffineTransform& transform) const
+{
+ double newX, newY;
+ transform.map(static_cast<double>(m_x), static_cast<double>(m_y), newX, newY);
+ return narrowPrecision(newX, newY);
+}
+
+FloatPoint FloatPoint::matrixTransform(const TransformationMatrix& transform) const
+{
+ double newX, newY;
+ transform.map(static_cast<double>(m_x), static_cast<double>(m_y), newX, newY);
+ return narrowPrecision(newX, newY);
+}
+
+FloatPoint FloatPoint::narrowPrecision(double x, double y)
+{
+ return FloatPoint(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y));
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/FloatPoint.h b/Source/WebCore/platform/graphics/FloatPoint.h
new file mode 100644
index 0000000..73a1bac
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatPoint.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 FloatPoint_h
+#define FloatPoint_h
+
+#include "FloatSize.h"
+#include "IntPoint.h"
+#include <wtf/MathExtras.h>
+
+#if PLATFORM(CG)
+typedef struct CGPoint CGPoint;
+#endif
+
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGPoint NSPoint;
+#else
+typedef struct _NSPoint NSPoint;
+#endif
+#endif
+
+#if PLATFORM(QT)
+#include "qglobal.h"
+QT_BEGIN_NAMESPACE
+class QPointF;
+QT_END_NAMESPACE
+#endif
+
+#if PLATFORM(HAIKU)
+class BPoint;
+#endif
+
+#if PLATFORM(SKIA)
+struct SkPoint;
+#endif
+
+namespace WebCore {
+
+class AffineTransform;
+class TransformationMatrix;
+class IntPoint;
+
+class FloatPoint {
+public:
+ FloatPoint() : m_x(0), m_y(0) { }
+ FloatPoint(float x, float y) : m_x(x), m_y(y) { }
+ FloatPoint(const IntPoint&);
+
+
+ static FloatPoint zero() { return FloatPoint(); }
+
+ static FloatPoint narrowPrecision(double x, double y);
+
+ float x() const { return m_x; }
+ float y() const { return m_y; }
+
+ void setX(float x) { m_x = x; }
+ void setY(float y) { m_y = y; }
+ void set(float x, float y)
+ {
+ m_x = x;
+ m_y = y;
+ }
+ void move(float dx, float dy)
+ {
+ m_x += dx;
+ m_y += dy;
+ }
+ void scale(float sx, float sy)
+ {
+ m_x *= sx;
+ m_y *= sy;
+ }
+
+ void normalize();
+
+ float dot(const FloatPoint& a) const
+ {
+ return m_x * a.x() + m_y * a.y();
+ }
+
+ float length() const;
+ float lengthSquared() const
+ {
+ return m_x * m_x + m_y * m_y;
+ }
+
+#if PLATFORM(CG)
+ FloatPoint(const CGPoint&);
+ operator CGPoint() const;
+#endif
+
+#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
+ FloatPoint(const NSPoint&);
+ operator NSPoint() const;
+#endif
+
+#if PLATFORM(QT)
+ FloatPoint(const QPointF&);
+ operator QPointF() const;
+#endif
+
+#if PLATFORM(HAIKU)
+ FloatPoint(const BPoint&);
+ operator BPoint() const;
+#endif
+
+#if PLATFORM(SKIA)
+ operator SkPoint() const;
+ FloatPoint(const SkPoint&);
+#endif
+
+ FloatPoint matrixTransform(const TransformationMatrix&) const;
+ FloatPoint matrixTransform(const AffineTransform&) const;
+
+private:
+ float m_x, m_y;
+};
+
+
+inline FloatPoint& operator+=(FloatPoint& a, const FloatSize& b)
+{
+ a.move(b.width(), b.height());
+ return a;
+}
+
+inline FloatPoint& operator+=(FloatPoint& a, const FloatPoint& b)
+{
+ a.move(b.x(), b.y());
+ return a;
+}
+
+inline FloatPoint& operator-=(FloatPoint& a, const FloatSize& b)
+{
+ a.move(-b.width(), -b.height());
+ return a;
+}
+
+inline FloatPoint operator+(const FloatPoint& a, const FloatSize& b)
+{
+ return FloatPoint(a.x() + b.width(), a.y() + b.height());
+}
+
+inline FloatPoint operator+(const FloatPoint& a, const FloatPoint& b)
+{
+ return FloatPoint(a.x() + b.x(), a.y() + b.y());
+}
+
+inline FloatSize operator-(const FloatPoint& a, const FloatPoint& b)
+{
+ return FloatSize(a.x() - b.x(), a.y() - b.y());
+}
+
+inline FloatPoint operator-(const FloatPoint& a, const FloatSize& b)
+{
+ return FloatPoint(a.x() - b.width(), a.y() - b.height());
+}
+
+inline bool operator==(const FloatPoint& a, const FloatPoint& b)
+{
+ return a.x() == b.x() && a.y() == b.y();
+}
+
+inline bool operator!=(const FloatPoint& a, const FloatPoint& b)
+{
+ return a.x() != b.x() || a.y() != b.y();
+}
+
+inline float operator*(const FloatPoint& a, const FloatPoint& b)
+{
+ // dot product
+ return a.dot(b);
+}
+
+inline IntPoint roundedIntPoint(const FloatPoint& p)
+{
+ return IntPoint(static_cast<int>(roundf(p.x())), static_cast<int>(roundf(p.y())));
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/FloatPoint3D.cpp b/Source/WebCore/platform/graphics/FloatPoint3D.cpp
new file mode 100644
index 0000000..ed1816b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatPoint3D.cpp
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#include "FloatPoint3D.h"
+
+#include <math.h>
+
+namespace WebCore {
+
+void FloatPoint3D::normalize()
+{
+ float tempLength = length();
+
+ if (tempLength) {
+ m_x /= tempLength;
+ m_y /= tempLength;
+ m_z /= tempLength;
+ }
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/FloatPoint3D.h b/Source/WebCore/platform/graphics/FloatPoint3D.h
new file mode 100644
index 0000000..ba0ee9d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatPoint3D.h
@@ -0,0 +1,187 @@
+/*
+ Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@webkit.org>
+ 2010 Zoltan Herczeg <zherczeg@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FloatPoint3D_h
+#define FloatPoint3D_h
+
+#include "FloatPoint.h"
+
+namespace WebCore {
+
+class FloatPoint3D {
+public:
+ FloatPoint3D()
+ : m_x(0)
+ , m_y(0)
+ , m_z(0)
+ {
+ }
+
+ FloatPoint3D(float x, float y, float z)
+ : m_x(x)
+ , m_y(y)
+ , m_z(z)
+ {
+ }
+
+ FloatPoint3D(const FloatPoint& p)
+ : m_x(p.x())
+ , m_y(p.y())
+ , m_z(0)
+ {
+ }
+
+ FloatPoint3D(const FloatPoint3D& p)
+ : m_x(p.x())
+ , m_y(p.y())
+ , m_z(p.z())
+ {
+ }
+
+ float x() const { return m_x; }
+ void setX(float x) { m_x = x; }
+
+ float y() const { return m_y; }
+ void setY(float y) { m_y = y; }
+
+ float z() const { return m_z; }
+ void setZ(float z) { m_z = z; }
+ void set(float x, float y, float z)
+ {
+ m_x = x;
+ m_y = y;
+ m_z = z;
+ }
+ void move(float dx, float dy, float dz)
+ {
+ m_x += dx;
+ m_y += dy;
+ m_z += dz;
+ }
+ void scale(float sx, float sy, float sz)
+ {
+ m_x *= sx;
+ m_y *= sy;
+ m_z *= sz;
+ }
+
+ bool isZero() const
+ {
+ return !m_x && !m_y && !m_z;
+ }
+
+ void normalize();
+
+ float dot(const FloatPoint3D& a) const
+ {
+ return m_x * a.x() + m_y * a.y() + m_z * a.z();
+ }
+
+ // Sets this FloatPoint3D to the cross product of the passed two.
+ // It is safe for "this" to be the same as either or both of the
+ // arguments.
+ void cross(const FloatPoint3D& a, const FloatPoint3D& b)
+ {
+ float x = a.y() * b.z() - a.z() * b.y();
+ float y = a.z() * b.x() - a.x() * b.z();
+ float z = a.x() * b.y() - a.y() * b.x();
+ m_x = x;
+ m_y = y;
+ m_z = z;
+ }
+
+ // Convenience function returning "this cross point" as a
+ // stack-allocated result.
+ FloatPoint3D cross(const FloatPoint3D& point) const
+ {
+ FloatPoint3D result;
+ result.cross(*this, point);
+ return result;
+ }
+
+ float lengthSquared() const { return this->dot(*this); }
+ float length() const { return sqrtf(lengthSquared()); }
+
+ float distanceTo(const FloatPoint3D& a) const;
+
+private:
+ float m_x;
+ float m_y;
+ float m_z;
+};
+
+inline FloatPoint3D& operator +=(FloatPoint3D& a, const FloatPoint3D& b)
+{
+ a.move(b.x(), b.y(), b.z());
+ return a;
+}
+
+inline FloatPoint3D& operator -=(FloatPoint3D& a, const FloatPoint3D& b)
+{
+ a.move(-b.x(), -b.y(), -b.z());
+ return a;
+}
+
+inline FloatPoint3D operator+(const FloatPoint3D& a, const FloatPoint3D& b)
+{
+ return FloatPoint3D(a.x() + b.x(), a.y() + b.y(), a.z() + b.z());
+}
+
+inline FloatPoint3D operator-(const FloatPoint3D& a, const FloatPoint3D& b)
+{
+ return FloatPoint3D(a.x() - b.x(), a.y() - b.y(), a.z() - b.z());
+}
+
+inline bool operator==(const FloatPoint3D& a, const FloatPoint3D& b)
+{
+ return a.x() == b.x() && a.y() == b.y() && a.z() == b.z();
+}
+
+inline bool operator!=(const FloatPoint3D& a, const FloatPoint3D& b)
+{
+ return a.x() != b.x() || a.y() != b.y() || a.z() != b.z();
+}
+
+inline float operator*(const FloatPoint3D& a, const FloatPoint3D& b)
+{
+ // dot product
+ return a.dot(b);
+}
+
+inline FloatPoint3D operator*(float k, const FloatPoint3D& v)
+{
+ return FloatPoint3D(k * v.x(), k * v.y(), k * v.z());
+}
+
+inline FloatPoint3D operator*(const FloatPoint3D& v, float k)
+{
+ return FloatPoint3D(k * v.x(), k * v.y(), k * v.z());
+}
+
+inline float FloatPoint3D::distanceTo(const FloatPoint3D& a) const
+{
+ return (*this - a).length();
+}
+
+} // namespace WebCore
+
+#endif // FloatPoint3D_h
diff --git a/Source/WebCore/platform/graphics/FloatQuad.cpp b/Source/WebCore/platform/graphics/FloatQuad.cpp
new file mode 100644
index 0000000..d1069fb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatQuad.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "FloatQuad.h"
+
+#include <algorithm>
+
+using std::max;
+using std::min;
+
+namespace WebCore {
+
+static inline float min4(float a, float b, float c, float d)
+{
+ return min(min(a, b), min(c, d));
+}
+
+static inline float max4(float a, float b, float c, float d)
+{
+ return max(max(a, b), max(c, d));
+}
+
+inline float dot(const FloatSize& a, const FloatSize& b)
+{
+ return a.width() * b.width() + a.height() * b.height();
+}
+
+inline bool isPointInTriangle(const FloatPoint& p, const FloatPoint& t1, const FloatPoint& t2, const FloatPoint& t3)
+{
+ // Compute vectors
+ FloatSize v0 = t3 - t1;
+ FloatSize v1 = t2 - t1;
+ FloatSize v2 = p - t1;
+
+ // Compute dot products
+ float dot00 = dot(v0, v0);
+ float dot01 = dot(v0, v1);
+ float dot02 = dot(v0, v2);
+ float dot11 = dot(v1, v1);
+ float dot12 = dot(v1, v2);
+
+ // Compute barycentric coordinates
+ float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
+ float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+ float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+
+ // Check if point is in triangle
+ return (u >= 0) && (v >= 0) && (u + v <= 1);
+}
+
+FloatRect FloatQuad::boundingBox() const
+{
+ float left = min4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x());
+ float top = min4(m_p1.y(), m_p2.y(), m_p3.y(), m_p4.y());
+
+ float right = max4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x());
+ float bottom = max4(m_p1.y(), m_p2.y(), m_p3.y(), m_p4.y());
+
+ return FloatRect(left, top, right - left, bottom - top);
+}
+
+bool FloatQuad::isRectilinear() const
+{
+ return (m_p1.x() == m_p2.x() && m_p2.y() == m_p3.y() && m_p3.x() == m_p4.x() && m_p4.y() == m_p1.y())
+ || (m_p1.y() == m_p2.y() && m_p2.x() == m_p3.x() && m_p3.y() == m_p4.y() && m_p4.x() == m_p1.x());
+}
+
+bool FloatQuad::containsPoint(const FloatPoint& p) const
+{
+ return isPointInTriangle(p, m_p1, m_p2, m_p3) || isPointInTriangle(p, m_p1, m_p3, m_p4);
+}
+
+// Note that we only handle convex quads here.
+bool FloatQuad::containsQuad(const FloatQuad& other) const
+{
+ return containsPoint(other.p1()) && containsPoint(other.p2()) && containsPoint(other.p3()) && containsPoint(other.p4());
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/FloatQuad.h b/Source/WebCore/platform/graphics/FloatQuad.h
new file mode 100644
index 0000000..6cd86f6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatQuad.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 FloatQuad_h
+#define FloatQuad_h
+
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+
+namespace WebCore {
+
+// A FloatQuad is a collection of 4 points, often representing the result of
+// mapping a rectangle through transforms. When initialized from a rect, the
+// points are in clockwise order from top left.
+class FloatQuad {
+public:
+ FloatQuad()
+ {
+ }
+
+ FloatQuad(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3, const FloatPoint& p4)
+ : m_p1(p1)
+ , m_p2(p2)
+ , m_p3(p3)
+ , m_p4(p4)
+ {
+ }
+
+ FloatQuad(const FloatRect& inRect)
+ : m_p1(inRect.location())
+ , m_p2(inRect.right(), inRect.y())
+ , m_p3(inRect.right(), inRect.bottom())
+ , m_p4(inRect.x(), inRect.bottom())
+ {
+ }
+
+ FloatPoint p1() const { return m_p1; }
+ FloatPoint p2() const { return m_p2; }
+ FloatPoint p3() const { return m_p3; }
+ FloatPoint p4() const { return m_p4; }
+
+ void setP1(const FloatPoint& p) { m_p1 = p; }
+ void setP2(const FloatPoint& p) { m_p2 = p; }
+ void setP3(const FloatPoint& p) { m_p3 = p; }
+ void setP4(const FloatPoint& p) { m_p4 = p; }
+
+ // isEmpty tests that the bounding box is empty. This will not identify
+ // "slanted" empty quads.
+ bool isEmpty() const { return boundingBox().isEmpty(); }
+
+ // Tests whether this quad can be losslessly represented by a FloatRect,
+ // that is, if two edges are parallel to the x-axis and the other two
+ // are parallel to the y-axis. If this method returns true, the
+ // corresponding FloatRect can be retrieved with boundingBox().
+ bool isRectilinear() const;
+
+ // Tests whether the given point is inside, or on an edge or corner of this quad.
+ bool containsPoint(const FloatPoint&) const;
+
+ // Tests whether the four corners of other are inside, or coincident with the sides of this quad.
+ // Note that this only works for convex quads, but that includes all quads that originate
+ // from transformed rects.
+ bool containsQuad(const FloatQuad&) const;
+
+ FloatRect boundingBox() const;
+ IntRect enclosingBoundingBox() const
+ {
+ return enclosingIntRect(boundingBox());
+ }
+
+ void move(const FloatSize& offset)
+ {
+ m_p1 += offset;
+ m_p2 += offset;
+ m_p3 += offset;
+ m_p4 += offset;
+ }
+
+ void move(float dx, float dy)
+ {
+ m_p1.move(dx, dy);
+ m_p2.move(dx, dy);
+ m_p3.move(dx, dy);
+ m_p4.move(dx, dy);
+ }
+
+private:
+ FloatPoint m_p1;
+ FloatPoint m_p2;
+ FloatPoint m_p3;
+ FloatPoint m_p4;
+};
+
+inline FloatQuad& operator+=(FloatQuad& a, const FloatSize& b)
+{
+ a.move(b);
+ return a;
+}
+
+inline FloatQuad& operator-=(FloatQuad& a, const FloatSize& b)
+{
+ a.move(-b.width(), -b.height());
+ return a;
+}
+
+inline bool operator==(const FloatQuad& a, const FloatQuad& b)
+{
+ return a.p1() == b.p1() &&
+ a.p2() == b.p2() &&
+ a.p3() == b.p3() &&
+ a.p4() == b.p4();
+}
+
+inline bool operator!=(const FloatQuad& a, const FloatQuad& b)
+{
+ return a.p1() != b.p1() ||
+ a.p2() != b.p2() ||
+ a.p3() != b.p3() ||
+ a.p4() != b.p4();
+}
+
+} // namespace WebCore
+
+
+#endif // FloatQuad_h
+
diff --git a/Source/WebCore/platform/graphics/FloatRect.cpp b/Source/WebCore/platform/graphics/FloatRect.cpp
new file mode 100644
index 0000000..0d8a24e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatRect.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#include "FloatConversion.h"
+#include "IntRect.h"
+#include <algorithm>
+#include <limits>
+#include <math.h>
+
+using std::max;
+using std::min;
+
+namespace WebCore {
+
+FloatRect::FloatRect(const IntRect& r) : m_location(r.location()), m_size(r.size())
+{
+}
+
+FloatRect FloatRect::narrowPrecision(double x, double y, double width, double height)
+{
+ return FloatRect(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), narrowPrecisionToFloat(width), narrowPrecisionToFloat(height));
+}
+
+bool FloatRect::intersects(const FloatRect& other) const
+{
+ // Checking emptiness handles negative widths as well as zero.
+ return !isEmpty() && !other.isEmpty()
+ && x() < other.right() && other.x() < right()
+ && y() < other.bottom() && other.y() < bottom();
+}
+
+bool FloatRect::contains(const FloatRect& other) const
+{
+ return x() <= other.x() && right() >= other.right()
+ && y() <= other.y() && bottom() >= other.bottom();
+}
+
+void FloatRect::intersect(const FloatRect& other)
+{
+ float l = max(x(), other.x());
+ float t = max(y(), other.y());
+ float r = min(right(), other.right());
+ float b = min(bottom(), other.bottom());
+
+ // Return a clean empty rectangle for non-intersecting cases.
+ if (l >= r || t >= b) {
+ l = 0;
+ t = 0;
+ r = 0;
+ b = 0;
+ }
+
+ setLocationAndSizeFromEdges(l, t, r, b);
+}
+
+void FloatRect::unite(const FloatRect& other)
+{
+ // Handle empty special cases first.
+ if (other.isEmpty())
+ return;
+ if (isEmpty()) {
+ *this = other;
+ return;
+ }
+
+ float l = min(x(), other.x());
+ float t = min(y(), other.y());
+ float r = max(right(), other.right());
+ float b = max(bottom(), other.bottom());
+
+ setLocationAndSizeFromEdges(l, t, r, b);
+}
+
+void FloatRect::scale(float sx, float sy)
+{
+ m_location.setX(x() * sx);
+ m_location.setY(y() * sy);
+ m_size.setWidth(width() * sx);
+ m_size.setHeight(height() * sy);
+}
+
+void FloatRect::fitToPoints(const FloatPoint& p0, const FloatPoint& p1)
+{
+ float left = min(p0.x(), p1.x());
+ float top = min(p0.y(), p1.y());
+ float right = max(p0.x(), p1.x());
+ float bottom = max(p0.y(), p1.y());
+
+ setLocationAndSizeFromEdges(left, top, right, bottom);
+}
+
+namespace {
+// Helpers for 3- and 4-way max and min.
+
+template <typename T>
+T min3(const T& v1, const T& v2, const T& v3)
+{
+ return min(min(v1, v2), v3);
+}
+
+template <typename T>
+T max3(const T& v1, const T& v2, const T& v3)
+{
+ return max(max(v1, v2), v3);
+}
+
+template <typename T>
+T min4(const T& v1, const T& v2, const T& v3, const T& v4)
+{
+ return min(min(v1, v2), min(v3, v4));
+}
+
+template <typename T>
+T max4(const T& v1, const T& v2, const T& v3, const T& v4)
+{
+ return max(max(v1, v2), max(v3, v4));
+}
+
+} // anonymous namespace
+
+void FloatRect::fitToPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2)
+{
+ float left = min3(p0.x(), p1.x(), p2.x());
+ float top = min3(p0.y(), p1.y(), p2.y());
+ float right = max3(p0.x(), p1.x(), p2.x());
+ float bottom = max3(p0.y(), p1.y(), p2.y());
+
+ setLocationAndSizeFromEdges(left, top, right, bottom);
+}
+
+void FloatRect::fitToPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3)
+{
+ float left = min4(p0.x(), p1.x(), p2.x(), p3.x());
+ float top = min4(p0.y(), p1.y(), p2.y(), p3.y());
+ float right = max4(p0.x(), p1.x(), p2.x(), p3.x());
+ float bottom = max4(p0.y(), p1.y(), p2.y(), p3.y());
+
+ setLocationAndSizeFromEdges(left, top, right, bottom);
+}
+
+static inline int safeFloatToInt(float x)
+{
+ static const int s_intMax = std::numeric_limits<int>::max();
+ static const int s_intMin = std::numeric_limits<int>::min();
+
+ if (x >= static_cast<float>(s_intMax))
+ return s_intMax;
+ if (x < static_cast<float>(s_intMin))
+ return s_intMin;
+ return static_cast<int>(x);
+}
+
+IntRect enclosingIntRect(const FloatRect& rect)
+{
+ float left = floorf(rect.x());
+ float top = floorf(rect.y());
+ float width = ceilf(rect.right()) - left;
+ float height = ceilf(rect.bottom()) - top;
+ return IntRect(safeFloatToInt(left), safeFloatToInt(top),
+ safeFloatToInt(width), safeFloatToInt(height));
+}
+
+FloatRect mapRect(const FloatRect& r, const FloatRect& srcRect, const FloatRect& destRect)
+{
+ if (srcRect.width() == 0 || srcRect.height() == 0)
+ return FloatRect();
+
+ float widthScale = destRect.width() / srcRect.width();
+ float heightScale = destRect.height() / srcRect.height();
+ return FloatRect(destRect.x() + (r.x() - srcRect.x()) * widthScale,
+ destRect.y() + (r.y() - srcRect.y()) * heightScale,
+ r.width() * widthScale, r.height() * heightScale);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/FloatRect.h b/Source/WebCore/platform/graphics/FloatRect.h
new file mode 100644
index 0000000..10ad838
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatRect.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 FloatRect_h
+#define FloatRect_h
+
+#include "FloatPoint.h"
+
+#if PLATFORM(CG)
+typedef struct CGRect CGRect;
+#endif
+
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGRect NSRect;
+#else
+typedef struct _NSRect NSRect;
+#endif
+#endif
+
+#if PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QRectF;
+QT_END_NAMESPACE
+#endif
+
+#if PLATFORM(WX) && USE(WXGC)
+class wxRect2DDouble;
+#endif
+
+#if PLATFORM(HAIKU)
+class BRect;
+#endif
+
+#if PLATFORM(SKIA)
+struct SkRect;
+#endif
+
+#if PLATFORM(CAIRO)
+typedef struct _cairo_rectangle cairo_rectangle_t;
+#endif
+
+namespace WebCore {
+
+#if PLATFORM(OPENVG)
+class VGRect;
+#endif
+
+class IntRect;
+
+class FloatRect {
+public:
+ FloatRect() { }
+ FloatRect(const FloatPoint& location, const FloatSize& size)
+ : m_location(location), m_size(size) { }
+ FloatRect(float x, float y, float width, float height)
+ : m_location(FloatPoint(x, y)), m_size(FloatSize(width, height)) { }
+ FloatRect(const IntRect&);
+
+ static FloatRect narrowPrecision(double x, double y, double width, double height);
+
+ FloatPoint location() const { return m_location; }
+ FloatSize size() const { return m_size; }
+
+ void setLocation(const FloatPoint& location) { m_location = location; }
+ void setSize(const FloatSize& size) { m_size = size; }
+
+ float x() const { return m_location.x(); }
+ float y() const { return m_location.y(); }
+ float width() const { return m_size.width(); }
+ float height() const { return m_size.height(); }
+
+ void setX(float x) { m_location.setX(x); }
+ void setY(float y) { m_location.setY(y); }
+ void setWidth(float width) { m_size.setWidth(width); }
+ void setHeight(float height) { m_size.setHeight(height); }
+
+ bool isEmpty() const { return m_size.isEmpty(); }
+
+ float left() const { return x(); }
+ float right() const { return x() + width(); }
+ float top() const { return y(); }
+ float bottom() const { return y() + height(); }
+
+ FloatPoint center() const { return FloatPoint(x() + width() / 2, y() + height() / 2); }
+
+ void move(const FloatSize& delta) { m_location += delta; }
+ void move(float dx, float dy) { m_location.move(dx, dy); }
+
+ bool intersects(const FloatRect&) const;
+ bool contains(const FloatRect&) const;
+
+ void intersect(const FloatRect&);
+ void unite(const FloatRect&);
+
+ // Note, this doesn't match what IntRect::contains(IntPoint&) does; the int version
+ // is really checking for containment of 1x1 rect, but that doesn't make sense with floats.
+ bool contains(float px, float py) const
+ { return px >= x() && px <= right() && py >= y() && py <= bottom(); }
+ bool contains(const FloatPoint& point) const { return contains(point.x(), point.y()); }
+
+
+ void inflateX(float dx) {
+ m_location.setX(m_location.x() - dx);
+ m_size.setWidth(m_size.width() + dx + dx);
+ }
+ void inflateY(float dy) {
+ m_location.setY(m_location.y() - dy);
+ m_size.setHeight(m_size.height() + dy + dy);
+ }
+ void inflate(float d) { inflateX(d); inflateY(d); }
+ void scale(float s) { scale(s, s); }
+ void scale(float sx, float sy);
+
+ // Re-initializes this rectangle to fit the sets of passed points.
+ void fitToPoints(const FloatPoint& p0, const FloatPoint& p1);
+ void fitToPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2);
+ void fitToPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3);
+
+#if PLATFORM(CG)
+ FloatRect(const CGRect&);
+ operator CGRect() const;
+#endif
+
+#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
+ FloatRect(const NSRect&);
+ operator NSRect() const;
+#endif
+
+#if PLATFORM(QT)
+ FloatRect(const QRectF&);
+ operator QRectF() const;
+ FloatRect normalized() const;
+#endif
+
+#if PLATFORM(WX) && USE(WXGC)
+ FloatRect(const wxRect2DDouble&);
+ operator wxRect2DDouble() const;
+#endif
+
+#if PLATFORM(HAIKU)
+ FloatRect(const BRect&);
+ operator BRect() const;
+#endif
+
+#if PLATFORM(SKIA)
+ FloatRect(const SkRect&);
+ operator SkRect() const;
+#endif
+
+#if PLATFORM(OPENVG)
+ operator VGRect() const;
+#endif
+
+#if PLATFORM(CAIRO)
+ FloatRect(const cairo_rectangle_t&);
+ operator cairo_rectangle_t() const;
+#endif
+
+private:
+ FloatPoint m_location;
+ FloatSize m_size;
+
+ void setLocationAndSizeFromEdges(float left, float top, float right, float bottom)
+ {
+ m_location.set(left, top);
+ m_size.setWidth(right - left);
+ m_size.setHeight(bottom - top);
+ }
+};
+
+inline FloatRect intersection(const FloatRect& a, const FloatRect& b)
+{
+ FloatRect c = a;
+ c.intersect(b);
+ return c;
+}
+
+inline FloatRect unionRect(const FloatRect& a, const FloatRect& b)
+{
+ FloatRect c = a;
+ c.unite(b);
+ return c;
+}
+
+
+inline bool operator==(const FloatRect& a, const FloatRect& b)
+{
+ return a.location() == b.location() && a.size() == b.size();
+}
+
+inline bool operator!=(const FloatRect& a, const FloatRect& b)
+{
+ return a.location() != b.location() || a.size() != b.size();
+}
+
+IntRect enclosingIntRect(const FloatRect&);
+
+// Map rect r from srcRect to an equivalent rect in destRect.
+FloatRect mapRect(const FloatRect& r, const FloatRect& srcRect, const FloatRect& destRect);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/FloatSize.cpp b/Source/WebCore/platform/graphics/FloatSize.cpp
new file mode 100644
index 0000000..c199297
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatSize.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatSize.h"
+
+#include "FloatConversion.h"
+#include "IntSize.h"
+#include <math.h>
+
+namespace WebCore {
+
+FloatSize::FloatSize(const IntSize& size) : m_width(size.width()), m_height(size.height())
+{
+}
+
+float FloatSize::diagonalLength() const
+{
+ return sqrtf(diagonalLengthSquared());
+}
+
+FloatSize FloatSize::narrowPrecision(double width, double height)
+{
+ return FloatSize(narrowPrecisionToFloat(width), narrowPrecisionToFloat(height));
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/FloatSize.h b/Source/WebCore/platform/graphics/FloatSize.h
new file mode 100644
index 0000000..160fc9a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FloatSize.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ * 2008 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 FloatSize_h
+#define FloatSize_h
+
+#include "IntSize.h"
+#include <wtf/MathExtras.h>
+
+#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN))
+typedef struct CGSize CGSize;
+#endif
+
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGSize NSSize;
+#else
+typedef struct _NSSize NSSize;
+#endif
+#endif
+
+namespace WebCore {
+
+class IntSize;
+
+class FloatSize {
+public:
+ FloatSize() : m_width(0), m_height(0) { }
+ FloatSize(float width, float height) : m_width(width), m_height(height) { }
+ FloatSize(const IntSize&);
+
+ static FloatSize narrowPrecision(double width, double height);
+
+ float width() const { return m_width; }
+ float height() const { return m_height; }
+
+ void setWidth(float width) { m_width = width; }
+ void setHeight(float height) { m_height = height; }
+
+ bool isEmpty() const { return m_width <= 0 || m_height <= 0; }
+
+ float aspectRatio() const { return m_width / m_height; }
+
+ void scale(float scale)
+ {
+ m_width *= scale;
+ m_height *= scale;
+ }
+
+ FloatSize expandedTo(const FloatSize& other) const
+ {
+ return FloatSize(m_width > other.m_width ? m_width : other.m_width,
+ m_height > other.m_height ? m_height : other.m_height);
+ }
+
+ FloatSize shrunkTo(const FloatSize& other) const
+ {
+ return FloatSize(m_width < other.m_width ? m_width : other.m_width,
+ m_height < other.m_height ? m_height : other.m_height);
+ }
+
+ float diagonalLength() const;
+ float diagonalLengthSquared() const
+ {
+ return m_width * m_width + m_height * m_height;
+ }
+
+#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN))
+ explicit FloatSize(const CGSize&); // don't do this implicitly since it's lossy
+ operator CGSize() const;
+#endif
+
+#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
+ explicit FloatSize(const NSSize &); // don't do this implicitly since it's lossy
+ operator NSSize() const;
+#endif
+
+private:
+ float m_width, m_height;
+};
+
+inline FloatSize& operator+=(FloatSize& a, const FloatSize& b)
+{
+ a.setWidth(a.width() + b.width());
+ a.setHeight(a.height() + b.height());
+ return a;
+}
+
+inline FloatSize& operator-=(FloatSize& a, const FloatSize& b)
+{
+ a.setWidth(a.width() - b.width());
+ a.setHeight(a.height() - b.height());
+ return a;
+}
+
+inline FloatSize operator+(const FloatSize& a, const FloatSize& b)
+{
+ return FloatSize(a.width() + b.width(), a.height() + b.height());
+}
+
+inline FloatSize operator-(const FloatSize& a, const FloatSize& b)
+{
+ return FloatSize(a.width() - b.width(), a.height() - b.height());
+}
+
+inline FloatSize operator-(const FloatSize& size)
+{
+ return FloatSize(-size.width(), -size.height());
+}
+
+inline bool operator==(const FloatSize& a, const FloatSize& b)
+{
+ return a.width() == b.width() && a.height() == b.height();
+}
+
+inline bool operator!=(const FloatSize& a, const FloatSize& b)
+{
+ return a.width() != b.width() || a.height() != b.height();
+}
+
+inline IntSize roundedIntSize(const FloatSize& p)
+{
+ return IntSize(static_cast<int>(roundf(p.width())), static_cast<int>(roundf(p.height())));
+}
+
+} // namespace WebCore
+
+#endif // FloatSize_h
diff --git a/Source/WebCore/platform/graphics/Font.cpp b/Source/WebCore/platform/graphics/Font.cpp
new file mode 100644
index 0000000..887e21d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Font.cpp
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "FloatRect.h"
+#include "FontCache.h"
+#include "FontTranscoder.h"
+#include "IntPoint.h"
+#include "GlyphBuffer.h"
+#include "WidthIterator.h"
+#include <wtf/MathExtras.h>
+#include <wtf/UnusedParam.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+const uint8_t Font::gRoundingHackCharacterTable[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+Font::CodePath Font::s_codePath = Auto;
+
+// ============================================================================================
+// Font Implementation (Cross-Platform Portion)
+// ============================================================================================
+
+Font::Font()
+ : m_letterSpacing(0)
+ , m_wordSpacing(0)
+ , m_isPlatformFont(false)
+ , m_needsTranscoding(false)
+{
+}
+
+Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
+ : m_fontDescription(fd)
+ , m_letterSpacing(letterSpacing)
+ , m_wordSpacing(wordSpacing)
+ , m_isPlatformFont(false)
+ , m_needsTranscoding(fontTranscoder().needsTranscoding(fd))
+{
+}
+
+Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
+ : m_fontList(FontFallbackList::create())
+ , m_letterSpacing(0)
+ , m_wordSpacing(0)
+ , m_isPlatformFont(true)
+{
+ m_fontDescription.setUsePrinterFont(isPrinterFont);
+ m_fontDescription.setFontSmoothing(fontSmoothingMode);
+ m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
+ m_fontList->setPlatformFont(fontData);
+}
+
+Font::Font(const Font& other)
+ : m_fontDescription(other.m_fontDescription)
+ , m_fontList(other.m_fontList)
+ , m_letterSpacing(other.m_letterSpacing)
+ , m_wordSpacing(other.m_wordSpacing)
+ , m_isPlatformFont(other.m_isPlatformFont)
+ , m_needsTranscoding(fontTranscoder().needsTranscoding(other.m_fontDescription))
+{
+}
+
+Font& Font::operator=(const Font& other)
+{
+ m_fontDescription = other.m_fontDescription;
+ m_fontList = other.m_fontList;
+ m_letterSpacing = other.m_letterSpacing;
+ m_wordSpacing = other.m_wordSpacing;
+ m_isPlatformFont = other.m_isPlatformFont;
+ m_needsTranscoding = other.m_needsTranscoding;
+ return *this;
+}
+
+bool Font::operator==(const Font& other) const
+{
+ // Our FontData don't have to be checked, since checking the font description will be fine.
+ // FIXME: This does not work if the font was made with the FontPlatformData constructor.
+ if (loadingCustomFonts() || other.loadingCustomFonts())
+ return false;
+
+ FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0;
+ FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0;
+
+ return first == second
+ && m_fontDescription == other.m_fontDescription
+ && m_letterSpacing == other.m_letterSpacing
+ && m_wordSpacing == other.m_wordSpacing
+ && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0);
+}
+
+void Font::update(PassRefPtr<FontSelector> fontSelector) const
+{
+ // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
+ // being reasonably safe (because inherited fonts in the render tree pick up the new
+ // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
+ // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
+ // and could eventually be rectified by using RefPtrs for Fonts themselves.
+ if (!m_fontList)
+ m_fontList = FontFallbackList::create();
+ m_fontList->invalidate(fontSelector);
+}
+
+void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+ // Don't draw anything while we are using custom fonts that are in the process of loading.
+ if (loadingCustomFonts())
+ return;
+
+ to = (to == -1 ? run.length() : to);
+
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont()) {
+ drawTextUsingSVGFont(context, run, point, from, to);
+ return;
+ }
+#endif
+
+ if (codePath(run) != Complex)
+ return drawSimpleText(context, run, point, from, to);
+
+ return drawComplexText(context, run, point, from, to);
+}
+
+void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
+{
+ if (loadingCustomFonts())
+ return;
+
+ if (to < 0)
+ to = run.length();
+
+#if ENABLE(SVG_FONTS)
+ // FIXME: Implement for SVG fonts.
+ if (primaryFont()->isSVGFont())
+ return;
+#endif
+
+ if (codePath(run) != Complex)
+ drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
+ else
+ drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
+}
+
+float Font::floatWidth(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont())
+ return floatWidthUsingSVGFont(run);
+#endif
+
+ CodePath codePathToUse = codePath(run);
+ if (codePathToUse != Complex) {
+ // If the complex text implementation cannot return fallback fonts, avoid
+ // returning them for simple text as well.
+ static bool returnFallbackFonts = canReturnFallbackFontsForComplexText();
+ return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow ? glyphOverflow : 0);
+ }
+
+ return floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
+}
+
+float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
+{
+#if !ENABLE(SVG_FONTS)
+ UNUSED_PARAM(extraCharsAvailable);
+#else
+ if (primaryFont()->isSVGFont())
+ return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName);
+#endif
+
+ charsConsumed = run.length();
+ glyphName = "";
+
+ if (codePath(run) != Complex)
+ return floatWidthForSimpleText(run, 0);
+
+ return floatWidthForComplexText(run);
+}
+
+FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
+{
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont())
+ return selectionRectForTextUsingSVGFont(run, point, h, from, to);
+#endif
+
+ to = (to == -1 ? run.length() : to);
+
+ if (codePath(run) != Complex)
+ return selectionRectForSimpleText(run, point, h, from, to);
+
+ return selectionRectForComplexText(run, point, h, from, to);
+}
+
+int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
+{
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont())
+ return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs);
+#endif
+
+ if (codePath(run) != Complex)
+ return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
+
+ return offsetForPositionForComplexText(run, x, includePartialGlyphs);
+}
+
+#if ENABLE(SVG_FONTS)
+bool Font::isSVGFont() const
+{
+ return primaryFont()->isSVGFont();
+}
+#endif
+
+String Font::normalizeSpaces(const String& string)
+{
+ const UChar* characters = string.characters();
+ unsigned length = string.length();
+ Vector<UChar, 256> buffer(length);
+ bool didReplacement = false;
+
+ for (unsigned i = 0; i < length; ++i) {
+ UChar originalCharacter = characters[i];
+ buffer[i] = normalizeSpaces(originalCharacter);
+ if (buffer[i] != originalCharacter)
+ didReplacement = true;
+ }
+
+ return didReplacement ? String(buffer.data(), length) : string;
+}
+
+static bool shouldUseFontSmoothing = true;
+
+void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
+{
+ ASSERT(isMainThread());
+ shouldUseFontSmoothing = shouldUseSmoothing;
+}
+
+bool Font::shouldUseSmoothing()
+{
+ return shouldUseFontSmoothing;
+}
+
+void Font::setCodePath(CodePath p)
+{
+ s_codePath = p;
+}
+
+Font::CodePath Font::codePath()
+{
+ return s_codePath;
+}
+
+Font::CodePath Font::codePath(const TextRun& run) const
+{
+ if (s_codePath != Auto)
+ return s_codePath;
+
+#if PLATFORM(QT)
+ if (run.padding() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
+ return Complex;
+#endif
+
+ CodePath result = Simple;
+
+ // Start from 0 since drawing and highlighting also measure the characters before run->from
+ for (int i = 0; i < run.length(); i++) {
+ const UChar c = run[i];
+ if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
+ continue;
+ if (c <= 0x36F)
+ return Complex;
+
+ if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
+ continue;
+ if (c <= 0x05CF)
+ return Complex;
+
+ if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
+ continue;
+ if (c <= 0x1059)
+ return Complex;
+
+ if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
+ continue;
+ if (c <= 0x11FF)
+ return Complex;
+
+ if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
+ continue;
+ if (c <= 0x18AF)
+ return Complex;
+
+ if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
+ continue;
+ if (c <= 0x194F)
+ return Complex;
+
+ if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics
+ continue;
+ if (c <= 0x2000) {
+ result = SimpleWithGlyphOverflow;
+ continue;
+ }
+
+ if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
+ continue;
+ if (c <= 0x20FF)
+ return Complex;
+
+ if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
+ continue;
+ if (c <= 0xFE2F)
+ return Complex;
+ }
+
+ if (typesettingFeatures())
+ return Complex;
+
+ return result;
+}
+
+bool Font::isCJKIdeograph(UChar32 c)
+{
+ // The basic CJK Unified Ideographs block.
+ if (c >= 0x4E00 && c <= 0x9FFF)
+ return true;
+
+ // CJK Unified Ideographs Extension A.
+ if (c >= 0x3400 && c <= 0x4DBF)
+ return true;
+
+ // CJK Radicals Supplement.
+ if (c >= 0x2E80 && c <= 0x2EFF)
+ return true;
+
+ // Kangxi Radicals.
+ if (c >= 0x2F00 && c <= 0x2FDF)
+ return true;
+
+ // CJK Strokes.
+ if (c >= 0x31C0 && c <= 0x31EF)
+ return true;
+
+ // CJK Compatibility Ideographs.
+ if (c >= 0xF900 && c <= 0xFAFF)
+ return true;
+
+ // CJK Unified Ideographs Extension B.
+ if (c >= 0x20000 && c <= 0x2A6DF)
+ return true;
+
+ // CJK Unified Ideographs Extension C.
+ if (c >= 0x2A700 && c <= 0x2B73F)
+ return true;
+
+ // CJK Unified Ideographs Extension D.
+ if (c >= 0x2B740 && c <= 0x2B81F)
+ return true;
+
+ // CJK Compatibility Ideographs Supplement.
+ if (c >= 0x2F800 && c <= 0x2FA1F)
+ return true;
+
+ return false;
+}
+
+bool Font::isCJKIdeographOrSymbol(UChar32 c)
+{
+ // 0x2C7 Caron, Mandarin Chinese 3rd Tone
+ // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
+ // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
+ // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
+ if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
+ return true;
+
+ // Ideographic Description Characters.
+ if (c >= 0x2FF0 && c <= 0x2FFF)
+ return true;
+
+ // CJK Symbols and Punctuation.
+ if (c >= 0x3000 && c <= 0x303F)
+ return true;
+
+ // Hiragana
+ if (c >= 0x3040 && c <= 0x309F)
+ return true;
+
+ // Katakana
+ if (c >= 0x30A0 && c <= 0x30FF)
+ return true;
+
+ // Bopomofo
+ if (c >= 0x3100 && c <= 0x312F)
+ return true;
+
+ // Bopomofo Extended
+ if (c >= 0x31A0 && c <= 0x31BF)
+ return true;
+
+ // Enclosed CJK Letters and Months.
+ if (c >= 0x3200 && c <= 0x32FF)
+ return true;
+
+ // CJK Compatibility.
+ if (c >= 0x3300 && c <= 0x33FF)
+ return true;
+
+ // CJK Compatibility Forms.
+ if (c >= 0xFE30 && c <= 0xFE4F)
+ return true;
+
+ // Halfwidth and Fullwidth Forms
+ // Usually only used in CJK
+ if (c >= 0xFF00 && c <= 0xFFEF)
+ return true;
+
+ // Emoji.
+ if (c >= 0x1F200 && c <= 0x1F6F)
+ return true;
+
+ return isCJKIdeograph(c);
+}
+
+bool Font::canReceiveTextEmphasis(UChar32 c)
+{
+ CharCategory category = Unicode::category(c);
+ if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
+ return false;
+
+ // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
+ if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
+ || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
+ return false;
+
+ return true;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/Font.h b/Source/WebCore/platform/graphics/Font.h
new file mode 100644
index 0000000..40a8828
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Font.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Font_h
+#define Font_h
+
+#include "CharacterNames.h"
+#include "FontDescription.h"
+#include "FontFallbackList.h"
+#include "SimpleFontData.h"
+#include "TextRun.h"
+#include "TypesettingFeatures.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/MathExtras.h>
+
+#if PLATFORM(QT)
+#include <QFont>
+#endif
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatRect;
+class FontData;
+class FontFallbackList;
+class FontPlatformData;
+class FontSelector;
+class GlyphBuffer;
+class GlyphPageTreeNode;
+class GraphicsContext;
+class SVGFontElement;
+
+struct GlyphData;
+
+const unsigned defaultUnitsPerEm = 1000;
+
+struct GlyphOverflow {
+ GlyphOverflow()
+ : left(0)
+ , right(0)
+ , top(0)
+ , bottom(0)
+ {
+ }
+
+ int left;
+ int right;
+ int top;
+ int bottom;
+};
+
+class Font {
+public:
+ Font();
+ Font(const FontDescription&, short letterSpacing, short wordSpacing);
+ // This constructor is only used if the platform wants to start with a native font.
+ Font(const FontPlatformData&, bool isPrinting, FontSmoothingMode = AutoSmoothing);
+ ~Font();
+
+ Font(const Font&);
+ Font& operator=(const Font&);
+
+ bool operator==(const Font& other) const;
+ bool operator!=(const Font& other) const { return !(*this == other); }
+
+ const FontDescription& fontDescription() const { return m_fontDescription; }
+
+ int pixelSize() const { return fontDescription().computedPixelSize(); }
+ float size() const { return fontDescription().computedSize(); }
+
+ void update(PassRefPtr<FontSelector>) const;
+
+ void drawText(GraphicsContext*, const TextRun&, const FloatPoint&, int from = 0, int to = -1) const;
+ void drawEmphasisMarks(GraphicsContext*, const TextRun&, const AtomicString& mark, const FloatPoint&, int from = 0, int to = -1) const;
+
+ int width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* glyphOverflow = 0) const { return lroundf(floatWidth(run, fallbackFonts, glyphOverflow)); }
+ float floatWidth(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* glyphOverflow = 0) const;
+ float floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const;
+
+ int offsetForPosition(const TextRun&, float position, bool includePartialGlyphs) const;
+ FloatRect selectionRectForText(const TextRun&, const FloatPoint&, int h, int from = 0, int to = -1) const;
+
+ bool isSmallCaps() const { return m_fontDescription.smallCaps(); }
+
+ short wordSpacing() const { return m_wordSpacing; }
+ short letterSpacing() const { return m_letterSpacing; }
+ void setWordSpacing(short s) { m_wordSpacing = s; }
+ void setLetterSpacing(short s) { m_letterSpacing = s; }
+ bool isFixedPitch() const;
+ bool isPrinterFont() const { return m_fontDescription.usePrinterFont(); }
+
+ FontRenderingMode renderingMode() const { return m_fontDescription.renderingMode(); }
+
+ TypesettingFeatures typesettingFeatures() const
+ {
+ TextRenderingMode textRenderingMode = m_fontDescription.textRenderingMode();
+ return textRenderingMode == OptimizeLegibility || textRenderingMode == GeometricPrecision ? Kerning | Ligatures : 0;
+ }
+
+ FontFamily& firstFamily() { return m_fontDescription.firstFamily(); }
+ const FontFamily& family() const { return m_fontDescription.family(); }
+
+ bool italic() const { return m_fontDescription.italic(); }
+ FontWeight weight() const { return m_fontDescription.weight(); }
+
+ bool isPlatformFont() const { return m_isPlatformFont; }
+
+ // Metrics that we query the FontFallbackList for.
+ int ascent(FontBaseline baselineType = AlphabeticBaseline) const { return primaryFont()->ascent(baselineType); }
+ int descent(FontBaseline baselineType = AlphabeticBaseline) const { return primaryFont()->descent(baselineType); }
+ int height() const { return ascent() + descent(); }
+ int lineSpacing() const { return primaryFont()->lineSpacing(); }
+ int lineGap() const { return primaryFont()->lineGap(); }
+ float xHeight() const { return primaryFont()->xHeight(); }
+ unsigned unitsPerEm() const { return primaryFont()->unitsPerEm(); }
+ int spaceWidth() const { return (int)ceilf(primaryFont()->adjustedSpaceWidth() + m_letterSpacing); }
+ float tabWidth(const SimpleFontData& fontData) const { return 8 * ceilf(fontData.adjustedSpaceWidth() + letterSpacing()); }
+ int emphasisMarkAscent(const AtomicString&) const;
+ int emphasisMarkDescent(const AtomicString&) const;
+ int emphasisMarkHeight(const AtomicString&) const;
+
+ const SimpleFontData* primaryFont() const;
+ const FontData* fontDataAt(unsigned) const;
+ GlyphData glyphDataForCharacter(UChar32, bool mirror, FontDataVariant = AutoVariant) const;
+ bool primaryFontHasGlyphForCharacter(UChar32) const;
+ // Used for complex text, and does not utilize the glyph map cache.
+ const FontData* fontDataForCharacters(const UChar*, int length) const;
+
+ static bool isCJKIdeograph(UChar32);
+ static bool isCJKIdeographOrSymbol(UChar32);
+
+#if PLATFORM(QT)
+ QFont font() const;
+#endif
+
+ static void setShouldUseSmoothing(bool);
+ static bool shouldUseSmoothing();
+
+ enum CodePath { Auto, Simple, Complex, SimpleWithGlyphOverflow };
+
+private:
+#if ENABLE(SVG_FONTS)
+ void drawTextUsingSVGFont(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
+ float floatWidthUsingSVGFont(const TextRun&) const;
+ float floatWidthUsingSVGFont(const TextRun&, int extraCharsAvailable, int& charsConsumed, String& glyphName) const;
+ FloatRect selectionRectForTextUsingSVGFont(const TextRun&, const FloatPoint&, int h, int from, int to) const;
+ int offsetForPositionForTextUsingSVGFont(const TextRun&, float position, bool includePartialGlyphs) const;
+#endif
+
+ enum ForTextEmphasisOrNot { NotForTextEmphasis, ForTextEmphasis };
+
+ // Returns the initial in-stream advance.
+ float getGlyphsAndAdvancesForSimpleText(const TextRun&, int from, int to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const;
+ void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
+ void drawEmphasisMarksForSimpleText(GraphicsContext*, const TextRun&, const AtomicString& mark, const FloatPoint&, int from, int to) const;
+ void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const;
+ void drawGlyphBuffer(GraphicsContext*, const GlyphBuffer&, const FloatPoint&) const;
+ void drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer&, const AtomicString&, const FloatPoint&) const;
+ float floatWidthForSimpleText(const TextRun&, GlyphBuffer*, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
+ int offsetForPositionForSimpleText(const TextRun&, float position, bool includePartialGlyphs) const;
+ FloatRect selectionRectForSimpleText(const TextRun&, const FloatPoint&, int h, int from, int to) const;
+
+ bool getEmphasisMarkGlyphData(const AtomicString&, GlyphData&) const;
+
+ static bool canReturnFallbackFontsForComplexText();
+
+ CodePath codePath(const TextRun&) const;
+
+ // Returns the initial in-stream advance.
+ float getGlyphsAndAdvancesForComplexText(const TextRun&, int from, int to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const;
+ void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
+ void drawEmphasisMarksForComplexText(GraphicsContext*, const TextRun&, const AtomicString& mark, const FloatPoint&, int from, int to) const;
+ float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
+ int offsetForPositionForComplexText(const TextRun&, float position, bool includePartialGlyphs) const;
+ FloatRect selectionRectForComplexText(const TextRun&, const FloatPoint&, int h, int from, int to) const;
+
+ friend struct WidthIterator;
+
+public:
+ // Useful for debugging the different font rendering code paths.
+ static void setCodePath(CodePath);
+ static CodePath codePath();
+ static CodePath s_codePath;
+
+ static const uint8_t gRoundingHackCharacterTable[256];
+ static bool isRoundingHackCharacter(UChar32 c)
+ {
+ return (((c & ~0xFF) == 0 && gRoundingHackCharacterTable[c]));
+ }
+
+ FontSelector* fontSelector() const;
+ static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == noBreakSpace; }
+ static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || (c >= 0x200c && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == objectReplacementCharacter; }
+ static bool canReceiveTextEmphasis(UChar32 c);
+
+ static inline UChar normalizeSpaces(UChar character)
+ {
+ if (treatAsSpace(character))
+ return space;
+
+ if (treatAsZeroWidthSpace(character))
+ return zeroWidthSpace;
+
+ return character;
+ }
+
+ static String normalizeSpaces(const String&);
+
+#if ENABLE(SVG_FONTS)
+ bool isSVGFont() const;
+ SVGFontElement* svgFont() const;
+#endif
+
+ bool needsTranscoding() const { return m_needsTranscoding; }
+
+private:
+ bool loadingCustomFonts() const
+ {
+ return m_fontList && m_fontList->loadingCustomFonts();
+ }
+
+ FontDescription m_fontDescription;
+ mutable RefPtr<FontFallbackList> m_fontList;
+ short m_letterSpacing;
+ short m_wordSpacing;
+ bool m_isPlatformFont;
+ bool m_needsTranscoding;
+};
+
+inline Font::~Font()
+{
+}
+
+inline const SimpleFontData* Font::primaryFont() const
+{
+ ASSERT(m_fontList);
+ return m_fontList->primarySimpleFontData(this);
+}
+
+inline const FontData* Font::fontDataAt(unsigned index) const
+{
+ ASSERT(m_fontList);
+ return m_fontList->fontDataAt(this, index);
+}
+
+inline const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const
+{
+ ASSERT(m_fontList);
+ return m_fontList->fontDataForCharacters(this, characters, length);
+}
+
+inline bool Font::isFixedPitch() const
+{
+ ASSERT(m_fontList);
+ return m_fontList->isFixedPitch(this);
+}
+
+inline FontSelector* Font::fontSelector() const
+{
+ return m_fontList ? m_fontList->fontSelector() : 0;
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/FontBaseline.h b/Source/WebCore/platform/graphics/FontBaseline.h
new file mode 100644
index 0000000..f7d256d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontBaseline.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 FontBaseline_h
+#define FontBaseline_h
+
+namespace WebCore {
+
+enum FontBaseline { AlphabeticBaseline, IdeographicBaseline };
+
+} // namespace WebCore
+
+#endif // FontBaseline_h
diff --git a/Source/WebCore/platform/graphics/FontCache.cpp b/Source/WebCore/platform/graphics/FontCache.cpp
new file mode 100644
index 0000000..149ea79
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontCache.cpp
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "Font.h"
+#include "FontFallbackList.h"
+#include "FontPlatformData.h"
+#include "FontSelector.h"
+#include <wtf/HashMap.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+FontCache* fontCache()
+{
+ DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ());
+ return &globalFontCache;
+}
+
+FontCache::FontCache()
+{
+}
+
+struct FontPlatformDataCacheKey : FastAllocBase {
+ FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, unsigned weight = 0, bool italic = false,
+ bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode, FontOrientation orientation = Horizontal)
+ : m_size(size)
+ , m_weight(weight)
+ , m_family(family)
+ , m_italic(italic)
+ , m_printerFont(isPrinterFont)
+ , m_renderingMode(renderingMode)
+ , m_orientation(orientation)
+ {
+ }
+
+ FontPlatformDataCacheKey(HashTableDeletedValueType) : m_size(hashTableDeletedSize()) { }
+ bool isHashTableDeletedValue() const { return m_size == hashTableDeletedSize(); }
+
+ bool operator==(const FontPlatformDataCacheKey& other) const
+ {
+ return equalIgnoringCase(m_family, other.m_family) && m_size == other.m_size &&
+ m_weight == other.m_weight && m_italic == other.m_italic && m_printerFont == other.m_printerFont &&
+ m_renderingMode == other.m_renderingMode && m_orientation == other.m_orientation;
+ }
+
+ unsigned m_size;
+ unsigned m_weight;
+ AtomicString m_family;
+ bool m_italic;
+ bool m_printerFont;
+ FontRenderingMode m_renderingMode;
+ FontOrientation m_orientation;
+
+private:
+ static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; }
+};
+
+inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey)
+{
+ unsigned hashCodes[4] = {
+ CaseFoldingHash::hash(fontKey.m_family),
+ fontKey.m_size,
+ fontKey.m_weight,
+ static_cast<unsigned>(fontKey.m_orientation) << 3 | static_cast<unsigned>(fontKey.m_italic) << 2 | static_cast<unsigned>(fontKey.m_printerFont) << 1 | static_cast<unsigned>(fontKey.m_renderingMode)
+ };
+ return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+}
+
+struct FontPlatformDataCacheKeyHash {
+ static unsigned hash(const FontPlatformDataCacheKey& font)
+ {
+ return computeHash(font);
+ }
+
+ static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> {
+ static const bool emptyValueIsZero = true;
+ static const FontPlatformDataCacheKey& emptyValue()
+ {
+ DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (nullAtom));
+ return key;
+ }
+ static void constructDeletedValue(FontPlatformDataCacheKey& slot)
+ {
+ new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FontPlatformDataCacheKey& value)
+ {
+ return value.isHashTableDeletedValue();
+ }
+};
+
+typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache;
+
+static FontPlatformDataCache* gFontPlatformDataCache = 0;
+
+static const AtomicString& alternateFamilyName(const AtomicString& familyName)
+{
+ // Alias Courier <-> Courier New
+ DEFINE_STATIC_LOCAL(AtomicString, courier, ("Courier"));
+ DEFINE_STATIC_LOCAL(AtomicString, courierNew, ("Courier New"));
+ if (equalIgnoringCase(familyName, courier))
+ return courierNew;
+#if !OS(WINDOWS)
+ // On Windows, Courier New (truetype font) is always present and
+ // Courier is a bitmap font. So, we don't want to map Courier New to
+ // Courier.
+ if (equalIgnoringCase(familyName, courierNew))
+ return courier;
+#endif
+
+ // Alias Times and Times New Roman.
+ DEFINE_STATIC_LOCAL(AtomicString, times, ("Times"));
+ DEFINE_STATIC_LOCAL(AtomicString, timesNewRoman, ("Times New Roman"));
+ if (equalIgnoringCase(familyName, times))
+ return timesNewRoman;
+ if (equalIgnoringCase(familyName, timesNewRoman))
+ return times;
+
+ // Alias Arial and Helvetica
+ DEFINE_STATIC_LOCAL(AtomicString, arial, ("Arial"));
+ DEFINE_STATIC_LOCAL(AtomicString, helvetica, ("Helvetica"));
+ if (equalIgnoringCase(familyName, arial))
+ return helvetica;
+ if (equalIgnoringCase(familyName, helvetica))
+ return arial;
+
+#if OS(WINDOWS)
+ // On Windows, bitmap fonts are blocked altogether so that we have to
+ // alias MS Sans Serif (bitmap font) -> Microsoft Sans Serif (truetype font)
+ DEFINE_STATIC_LOCAL(AtomicString, msSans, ("MS Sans Serif"));
+ DEFINE_STATIC_LOCAL(AtomicString, microsoftSans, ("Microsoft Sans Serif"));
+ if (equalIgnoringCase(familyName, msSans))
+ return microsoftSans;
+
+ // Alias MS Serif (bitmap) -> Times New Roman (truetype font). There's no
+ // 'Microsoft Sans Serif-equivalent' for Serif.
+ static AtomicString msSerif("MS Serif");
+ if (equalIgnoringCase(familyName, msSerif))
+ return timesNewRoman;
+#endif
+
+ return emptyAtom;
+}
+
+FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fontDescription,
+ const AtomicString& familyName,
+ bool checkingAlternateName)
+{
+ if (!gFontPlatformDataCache) {
+ gFontPlatformDataCache = new FontPlatformDataCache;
+ platformInit();
+ }
+
+ FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.weight(), fontDescription.italic(),
+ fontDescription.usePrinterFont(), fontDescription.renderingMode(), fontDescription.orientation());
+ FontPlatformData* result = 0;
+ bool foundResult;
+ FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key);
+ if (it == gFontPlatformDataCache->end()) {
+ result = createFontPlatformData(fontDescription, familyName);
+ gFontPlatformDataCache->set(key, result);
+ foundResult = result;
+ } else {
+ result = it->second;
+ foundResult = true;
+ }
+
+ if (!foundResult && !checkingAlternateName) {
+ // We were unable to find a font. We have a small set of fonts that we alias to other names,
+ // e.g., Arial/Helvetica, Courier/Courier New, etc. Try looking up the font under the aliased name.
+ const AtomicString& alternateName = alternateFamilyName(familyName);
+ if (!alternateName.isEmpty())
+ result = getCachedFontPlatformData(fontDescription, alternateName, true);
+ if (result)
+ gFontPlatformDataCache->set(key, new FontPlatformData(*result)); // Cache the result under the old name.
+ }
+
+ return result;
+}
+
+struct FontDataCacheKeyHash {
+ static unsigned hash(const FontPlatformData& platformData)
+ {
+ return platformData.hash();
+ }
+
+ static bool equal(const FontPlatformData& a, const FontPlatformData& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
+ static const bool emptyValueIsZero = true;
+ static const bool needsDestruction = true;
+ static const FontPlatformData& emptyValue()
+ {
+ DEFINE_STATIC_LOCAL(FontPlatformData, key, (0.f, false, false));
+ return key;
+ }
+ static void constructDeletedValue(FontPlatformData& slot)
+ {
+ new (&slot) FontPlatformData(HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FontPlatformData& value)
+ {
+ return value.isHashTableDeletedValue();
+ }
+};
+
+typedef HashMap<FontPlatformData, pair<SimpleFontData*, unsigned>, FontDataCacheKeyHash, FontDataCacheKeyTraits> FontDataCache;
+
+static FontDataCache* gFontDataCache = 0;
+
+const int cMaxInactiveFontData = 120; // Pretty Low Threshold
+const float cTargetInactiveFontData = 100;
+static ListHashSet<const SimpleFontData*>* gInactiveFontData = 0;
+
+SimpleFontData* FontCache::getCachedFontData(const FontDescription& fontDescription, const AtomicString& family, bool checkingAlternateName)
+{
+ FontPlatformData* platformData = getCachedFontPlatformData(fontDescription, family, checkingAlternateName);
+ if (!platformData)
+ return 0;
+
+ return getCachedFontData(platformData);
+}
+
+SimpleFontData* FontCache::getCachedFontData(const FontPlatformData* platformData)
+{
+ if (!platformData)
+ return 0;
+
+ if (!gFontDataCache) {
+ gFontDataCache = new FontDataCache;
+ gInactiveFontData = new ListHashSet<const SimpleFontData*>;
+ }
+
+ FontDataCache::iterator result = gFontDataCache->find(*platformData);
+ if (result == gFontDataCache->end()) {
+ pair<SimpleFontData*, unsigned> newValue(new SimpleFontData(*platformData), 1);
+ gFontDataCache->set(*platformData, newValue);
+ return newValue.first;
+ }
+ if (!result.get()->second.second++) {
+ ASSERT(gInactiveFontData->contains(result.get()->second.first));
+ gInactiveFontData->remove(result.get()->second.first);
+ }
+
+ return result.get()->second.first;
+}
+
+void FontCache::releaseFontData(const SimpleFontData* fontData)
+{
+ ASSERT(gFontDataCache);
+ ASSERT(!fontData->isCustomFont());
+
+ FontDataCache::iterator it = gFontDataCache->find(fontData->platformData());
+ ASSERT(it != gFontDataCache->end());
+
+ if (!--it->second.second) {
+ gInactiveFontData->add(fontData);
+ if (gInactiveFontData->size() > cMaxInactiveFontData)
+ purgeInactiveFontData(gInactiveFontData->size() - cTargetInactiveFontData);
+ }
+}
+
+void FontCache::purgeInactiveFontData(int count)
+{
+ if (!gInactiveFontData)
+ return;
+
+ static bool isPurging; // Guard against reentry when e.g. a deleted FontData releases its small caps FontData.
+ if (isPurging)
+ return;
+
+ isPurging = true;
+
+ Vector<const SimpleFontData*, 20> fontDataToDelete;
+ ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontData->end();
+ ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontData->begin();
+ for (int i = 0; i < count && it != end; ++it, ++i) {
+ const SimpleFontData* fontData = *it.get();
+ gFontDataCache->remove(fontData->platformData());
+ fontDataToDelete.append(fontData);
+ }
+
+ if (it == end) {
+ // Removed everything
+ gInactiveFontData->clear();
+ } else {
+ for (int i = 0; i < count; ++i)
+ gInactiveFontData->remove(gInactiveFontData->begin());
+ }
+
+ size_t fontDataToDeleteCount = fontDataToDelete.size();
+ for (size_t i = 0; i < fontDataToDeleteCount; ++i)
+ delete fontDataToDelete[i];
+
+ if (gFontPlatformDataCache) {
+ Vector<FontPlatformDataCacheKey> keysToRemove;
+ keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size());
+ FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end();
+ for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) {
+ if (platformData->second && !gFontDataCache->contains(*platformData->second))
+ keysToRemove.append(platformData->first);
+ }
+
+ size_t keysToRemoveCount = keysToRemove.size();
+ for (size_t i = 0; i < keysToRemoveCount; ++i)
+ delete gFontPlatformDataCache->take(keysToRemove[i]);
+ }
+
+ isPurging = false;
+}
+
+size_t FontCache::fontDataCount()
+{
+ if (gFontDataCache)
+ return gFontDataCache->size();
+ return 0;
+}
+
+size_t FontCache::inactiveFontDataCount()
+{
+ if (gInactiveFontData)
+ return gInactiveFontData->size();
+ return 0;
+}
+
+const FontData* FontCache::getFontData(const Font& font, int& familyIndex, FontSelector* fontSelector)
+{
+ SimpleFontData* result = 0;
+
+ int startIndex = familyIndex;
+ const FontFamily* startFamily = &font.fontDescription().family();
+ for (int i = 0; startFamily && i < startIndex; i++)
+ startFamily = startFamily->next();
+ const FontFamily* currFamily = startFamily;
+ while (currFamily && !result) {
+ familyIndex++;
+ if (currFamily->family().length()) {
+ if (fontSelector) {
+ FontData* data = fontSelector->getFontData(font.fontDescription(), currFamily->family());
+ if (data)
+ return data;
+ }
+ result = getCachedFontData(font.fontDescription(), currFamily->family());
+ }
+ currFamily = currFamily->next();
+ }
+
+ if (!currFamily)
+ familyIndex = cAllFamiliesScanned;
+
+ if (!result)
+ // We didn't find a font. Try to find a similar font using our own specific knowledge about our platform.
+ // For example on OS X, we know to map any families containing the words Arabic, Pashto, or Urdu to the
+ // Geeza Pro font.
+ result = getSimilarFontPlatformData(font);
+
+ if (!result && startIndex == 0) {
+ // If it's the primary font that we couldn't find, we try the following. In all other cases, we will
+ // just use per-character system fallback.
+
+ if (fontSelector) {
+ // Try the user's preferred standard font.
+ if (FontData* data = fontSelector->getFontData(font.fontDescription(), "-webkit-standard"))
+ return data;
+ }
+
+ // Still no result. Hand back our last resort fallback font.
+ result = getLastResortFallbackFont(font.fontDescription());
+ }
+ return result;
+}
+
+static HashSet<FontSelector*>* gClients;
+
+void FontCache::addClient(FontSelector* client)
+{
+ if (!gClients)
+ gClients = new HashSet<FontSelector*>;
+
+ ASSERT(!gClients->contains(client));
+ gClients->add(client);
+}
+
+void FontCache::removeClient(FontSelector* client)
+{
+ ASSERT(gClients);
+ ASSERT(gClients->contains(client));
+
+ gClients->remove(client);
+}
+
+static unsigned gGeneration = 0;
+
+unsigned FontCache::generation()
+{
+ return gGeneration;
+}
+
+void FontCache::invalidate()
+{
+ if (!gClients) {
+ ASSERT(!gFontPlatformDataCache);
+ return;
+ }
+
+ if (gFontPlatformDataCache) {
+ deleteAllValues(*gFontPlatformDataCache);
+ delete gFontPlatformDataCache;
+ gFontPlatformDataCache = new FontPlatformDataCache;
+ }
+
+ gGeneration++;
+
+ Vector<RefPtr<FontSelector> > clients;
+ size_t numClients = gClients->size();
+ clients.reserveInitialCapacity(numClients);
+ HashSet<FontSelector*>::iterator end = gClients->end();
+ for (HashSet<FontSelector*>::iterator it = gClients->begin(); it != end; ++it)
+ clients.append(*it);
+
+ ASSERT(numClients == clients.size());
+ for (size_t i = 0; i < numClients; ++i)
+ clients[i]->fontCacheInvalidated();
+
+ purgeInactiveFontData();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/FontCache.h b/Source/WebCore/platform/graphics/FontCache.h
new file mode 100644
index 0000000..e6845d9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontCache.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 FontCache_h
+#define FontCache_h
+
+#include <limits.h>
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.h>
+
+#if PLATFORM(WIN)
+#include <objidl.h>
+#include <mlang.h>
+#endif
+
+namespace WebCore
+{
+
+class Font;
+class FontPlatformData;
+class FontData;
+class FontDescription;
+class FontSelector;
+class SimpleFontData;
+
+class FontCache : public Noncopyable {
+public:
+ friend FontCache* fontCache();
+
+ const FontData* getFontData(const Font&, int& familyIndex, FontSelector*);
+ void releaseFontData(const SimpleFontData*);
+
+ // This method is implemented by the platform.
+ // FIXME: Font data returned by this method never go inactive because callers don't track and release them.
+ const SimpleFontData* getFontDataForCharacters(const Font&, const UChar* characters, int length);
+
+ // Also implemented by the platform.
+ void platformInit();
+
+#if OS(WINCE) && !PLATFORM(QT)
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ IMLangFontLink2* getFontLinkInterface();
+#else
+ IMLangFontLink* getFontLinkInterface();
+#endif
+ static void comInitialize();
+ static void comUninitialize();
+ static IMultiLanguage* getMultiLanguageInterface();
+#elif PLATFORM(WIN)
+ IMLangFontLink2* getFontLinkInterface();
+#endif
+
+ void getTraitsInFamily(const AtomicString&, Vector<unsigned>&);
+
+ SimpleFontData* getCachedFontData(const FontDescription& fontDescription, const AtomicString& family, bool checkingAlternateName = false);
+ SimpleFontData* getLastResortFallbackFont(const FontDescription&);
+
+ void addClient(FontSelector*);
+ void removeClient(FontSelector*);
+
+ unsigned generation();
+ void invalidate();
+
+ size_t fontDataCount();
+ size_t inactiveFontDataCount();
+ void purgeInactiveFontData(int count = INT_MAX);
+
+private:
+ FontCache();
+ ~FontCache();
+
+ // FIXME: This method should eventually be removed.
+ FontPlatformData* getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName = false);
+
+ // These methods are implemented by each platform.
+ SimpleFontData* getSimilarFontPlatformData(const Font&);
+ FontPlatformData* createFontPlatformData(const FontDescription&, const AtomicString& family);
+
+ SimpleFontData* getCachedFontData(const FontPlatformData*);
+
+ friend class SimpleFontData; // For getCachedFontData(const FontPlatformData*)
+ friend class FontFallbackList;
+};
+
+// Get the global fontCache.
+FontCache* fontCache();
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/FontData.cpp b/Source/WebCore/platform/graphics/FontData.cpp
new file mode 100644
index 0000000..c40e13c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontData.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FontData.h"
+
+namespace WebCore {
+
+FontData::~FontData()
+{
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/FontData.h b/Source/WebCore/platform/graphics/FontData.h
new file mode 100644
index 0000000..ee94a98
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontData.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 FontData_h
+#define FontData_h
+
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+class SimpleFontData;
+
+class FontData : public Noncopyable {
+public:
+ FontData()
+ : m_maxGlyphPageTreeLevel(0)
+ {
+ }
+
+ virtual ~FontData();
+
+ virtual const SimpleFontData* fontDataForCharacter(UChar32) const = 0;
+ virtual bool containsCharacters(const UChar*, int length) const = 0;
+ virtual bool isCustomFont() const = 0;
+ virtual bool isLoading() const = 0;
+ virtual bool isSegmented() const = 0;
+
+ void setMaxGlyphPageTreeLevel(unsigned level) const { m_maxGlyphPageTreeLevel = level; }
+ unsigned maxGlyphPageTreeLevel() const { return m_maxGlyphPageTreeLevel; }
+
+#ifndef NDEBUG
+ virtual String description() const = 0;
+#endif
+
+private:
+ mutable unsigned m_maxGlyphPageTreeLevel;
+};
+
+} // namespace WebCore
+
+#endif // FontData_h
diff --git a/Source/WebCore/platform/graphics/FontDescription.cpp b/Source/WebCore/platform/graphics/FontDescription.cpp
new file mode 100644
index 0000000..58ddf81
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontDescription.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2007 Nicholas Shanks <contact@nickshanks.com>
+ * Copyright (C) 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "FontDescription.h"
+
+namespace WebCore {
+
+FontWeight FontDescription::lighterWeight(void) const
+{
+ // FIXME: Should actually return the CSS weight corresponding to next lightest
+ // weight of the currently used font family.
+ switch (m_weight) {
+ case FontWeight100:
+ case FontWeight200:
+ return FontWeight100;
+
+ case FontWeight300:
+ return FontWeight200;
+
+ case FontWeight400:
+ case FontWeight500:
+ return FontWeight300;
+
+ case FontWeight600:
+ case FontWeight700:
+ return FontWeight400;
+
+ case FontWeight800:
+ return FontWeight500;
+
+ case FontWeight900:
+ return FontWeight700;
+ }
+ ASSERT_NOT_REACHED();
+ return FontWeightNormal;
+}
+
+FontWeight FontDescription::bolderWeight(void) const
+{
+ // FIXME: Should actually return the CSS weight corresponding to next heaviest
+ // weight of the currently used font family.
+ switch (m_weight) {
+ case FontWeight100:
+ case FontWeight200:
+ return FontWeight300;
+
+ case FontWeight300:
+ return FontWeight400;
+
+ case FontWeight400:
+ case FontWeight500:
+ return FontWeight700;
+
+ case FontWeight600:
+ case FontWeight700:
+ return FontWeight800;
+
+ case FontWeight800:
+ case FontWeight900:
+ return FontWeight900;
+ }
+ ASSERT_NOT_REACHED();
+ return FontWeightNormal;
+}
+
+FontTraitsMask FontDescription::traitsMask() const
+{
+ return static_cast<FontTraitsMask>((m_italic ? FontStyleItalicMask : FontStyleNormalMask)
+ | (m_smallCaps ? FontVariantSmallCapsMask : FontVariantNormalMask)
+ | (FontWeight100Mask << (m_weight - FontWeight100)));
+
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/FontDescription.h b/Source/WebCore/platform/graphics/FontDescription.h
new file mode 100644
index 0000000..12900bf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontDescription.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIother.m_ If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USm_
+ *
+ */
+
+#ifndef FontDescription_h
+#define FontDescription_h
+
+#include "FontFamily.h"
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include "FontSmoothingMode.h"
+#include "FontTraitsMask.h"
+#include "TextRenderingMode.h"
+
+namespace WebCore {
+
+enum FontWeight {
+ FontWeight100,
+ FontWeight200,
+ FontWeight300,
+ FontWeight400,
+ FontWeight500,
+ FontWeight600,
+ FontWeight700,
+ FontWeight800,
+ FontWeight900,
+ FontWeightNormal = FontWeight400,
+ FontWeightBold = FontWeight700
+};
+
+class FontDescription {
+public:
+ enum GenericFamilyType { NoFamily, StandardFamily, SerifFamily, SansSerifFamily,
+ MonospaceFamily, CursiveFamily, FantasyFamily };
+
+ FontDescription()
+ : m_specifiedSize(0)
+ , m_computedSize(0)
+ , m_orientation(Horizontal)
+ , m_italic(false)
+ , m_smallCaps(false)
+ , m_isAbsoluteSize(false)
+ , m_weight(FontWeightNormal)
+ , m_genericFamily(NoFamily)
+ , m_usePrinterFont(false)
+ , m_renderingMode(NormalRenderingMode)
+ , m_keywordSize(0)
+ , m_fontSmoothing(AutoSmoothing)
+ , m_textRendering(AutoTextRendering)
+ , m_isSpecifiedFont(false)
+ {
+ }
+
+ bool operator==(const FontDescription&) const;
+ bool operator!=(const FontDescription& other) const { return !(*this == other); }
+
+ const FontFamily& family() const { return m_familyList; }
+ FontFamily& firstFamily() { return m_familyList; }
+ float specifiedSize() const { return m_specifiedSize; }
+ float computedSize() const { return m_computedSize; }
+ bool italic() const { return m_italic; }
+ int computedPixelSize() const { return int(m_computedSize + 0.5f); }
+ bool smallCaps() const { return m_smallCaps; }
+ bool isAbsoluteSize() const { return m_isAbsoluteSize; }
+ FontWeight weight() const { return static_cast<FontWeight>(m_weight); }
+ FontWeight lighterWeight() const;
+ FontWeight bolderWeight() const;
+ GenericFamilyType genericFamily() const { return static_cast<GenericFamilyType>(m_genericFamily); }
+ bool usePrinterFont() const { return m_usePrinterFont; }
+ // only use fixed default size when there is only one font family, and that family is "monospace"
+ bool useFixedDefaultSize() const { return genericFamily() == MonospaceFamily && !family().next() && family().family() == "-webkit-monospace"; }
+ FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); }
+ unsigned keywordSize() const { return m_keywordSize; }
+ FontSmoothingMode fontSmoothing() const { return static_cast<FontSmoothingMode>(m_fontSmoothing); }
+ TextRenderingMode textRenderingMode() const { return static_cast<TextRenderingMode>(m_textRendering); }
+
+ FontTraitsMask traitsMask() const;
+ bool isSpecifiedFont() const { return m_isSpecifiedFont; }
+ FontOrientation orientation() const { return m_orientation; }
+
+ void setFamily(const FontFamily& family) { m_familyList = family; }
+ void setComputedSize(float s) { m_computedSize = s; }
+ void setSpecifiedSize(float s) { m_specifiedSize = s; }
+ void setItalic(bool i) { m_italic = i; }
+ void setSmallCaps(bool c) { m_smallCaps = c; }
+ void setIsAbsoluteSize(bool s) { m_isAbsoluteSize = s; }
+ void setWeight(FontWeight w) { m_weight = w; }
+ void setGenericFamily(GenericFamilyType genericFamily) { m_genericFamily = genericFamily; }
+#if PLATFORM(CHROMIUM) && OS(DARWIN)
+ void setUsePrinterFont(bool) { }
+#else
+ void setUsePrinterFont(bool p) { m_usePrinterFont = p; }
+#endif
+ void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; }
+ void setKeywordSize(unsigned s) { m_keywordSize = s; }
+ void setFontSmoothing(FontSmoothingMode smoothing) { m_fontSmoothing = smoothing; }
+ void setTextRenderingMode(TextRenderingMode rendering) { m_textRendering = rendering; }
+ void setIsSpecifiedFont(bool isSpecifiedFont) { m_isSpecifiedFont = isSpecifiedFont; }
+ void setOrientation(FontOrientation orientation) { m_orientation = orientation; }
+
+private:
+ FontFamily m_familyList; // The list of font families to be used.
+
+ float m_specifiedSize; // Specified CSS value. Independent of rendering issues such as integer
+ // rounding, minimum font sizes, and zooming.
+ float m_computedSize; // Computed size adjusted for the minimum font size and the zoom factor.
+
+ FontOrientation m_orientation;
+
+ bool m_italic : 1;
+ bool m_smallCaps : 1;
+ bool m_isAbsoluteSize : 1; // Whether or not CSS specified an explicit size
+ // (logical sizes like "medium" don't count).
+ unsigned m_weight : 8; // FontWeight
+ unsigned m_genericFamily : 3; // GenericFamilyType
+ bool m_usePrinterFont : 1;
+
+ unsigned m_renderingMode : 1; // Used to switch between CG and GDI text on Windows.
+
+ unsigned m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so,
+ // then we can accurately translate across different generic families to adjust for different preference settings
+ // (e.g., 13px monospace vs. 16px everything else). Sizes are 1-8 (like the HTML size values for <font>).
+
+ unsigned m_fontSmoothing : 2; // FontSmoothingMode
+ unsigned m_textRendering : 2; // TextRenderingMode
+ bool m_isSpecifiedFont : 1; // True if a web page specifies a non-generic font family as the first font family.
+};
+
+inline bool FontDescription::operator==(const FontDescription& other) const
+{
+ return m_familyList == other.m_familyList
+ && m_specifiedSize == other.m_specifiedSize
+ && m_computedSize == other.m_computedSize
+ && m_italic == other.m_italic
+ && m_smallCaps == other.m_smallCaps
+ && m_isAbsoluteSize == other.m_isAbsoluteSize
+ && m_weight == other.m_weight
+ && m_genericFamily == other.m_genericFamily
+ && m_usePrinterFont == other.m_usePrinterFont
+ && m_renderingMode == other.m_renderingMode
+ && m_keywordSize == other.m_keywordSize
+ && m_fontSmoothing == other.m_fontSmoothing
+ && m_textRendering == other.m_textRendering
+ && m_isSpecifiedFont == other.m_isSpecifiedFont
+ && m_orientation == other.m_orientation;
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/FontFallbackList.cpp b/Source/WebCore/platform/graphics/FontFallbackList.cpp
new file mode 100644
index 0000000..649c117
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontFallbackList.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "FontFallbackList.h"
+
+#include "Font.h"
+#include "FontCache.h"
+#include "SegmentedFontData.h"
+
+namespace WebCore {
+
+FontFallbackList::FontFallbackList()
+ : m_pageZero(0)
+ , m_cachedPrimarySimpleFontData(0)
+ , m_fontSelector(0)
+ , m_familyIndex(0)
+ , m_pitch(UnknownPitch)
+ , m_loadingCustomFonts(false)
+ , m_generation(fontCache()->generation())
+{
+}
+
+void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector)
+{
+ releaseFontData();
+ m_fontList.clear();
+ m_pageZero = 0;
+ m_pages.clear();
+ m_cachedPrimarySimpleFontData = 0;
+ m_familyIndex = 0;
+ m_pitch = UnknownPitch;
+ m_loadingCustomFonts = false;
+ m_fontSelector = fontSelector;
+ m_generation = fontCache()->generation();
+}
+
+void FontFallbackList::releaseFontData()
+{
+ unsigned numFonts = m_fontList.size();
+ for (unsigned i = 0; i < numFonts; ++i) {
+ if (!m_fontList[i].second) {
+ ASSERT(!m_fontList[i].first->isSegmented());
+ fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first));
+ }
+ }
+}
+
+void FontFallbackList::determinePitch(const Font* font) const
+{
+ const FontData* fontData = primaryFontData(font);
+ if (!fontData->isSegmented())
+ m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch();
+ else {
+ const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData);
+ unsigned numRanges = segmentedFontData->numRanges();
+ if (numRanges == 1)
+ m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch();
+ else
+ m_pitch = VariablePitch;
+ }
+}
+
+const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned realizedFontIndex) const
+{
+ if (realizedFontIndex < m_fontList.size())
+ return m_fontList[realizedFontIndex].first; // This fallback font is already in our list.
+
+ // Make sure we're not passing in some crazy value here.
+ ASSERT(realizedFontIndex == m_fontList.size());
+
+ if (m_familyIndex == cAllFamiliesScanned)
+ return 0;
+
+ // Ask the font cache for the font data.
+ // We are obtaining this font for the first time. We keep track of the families we've looked at before
+ // in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our
+ // |m_familyIndex| as it scans for the right font to make.
+ ASSERT(fontCache()->generation() == m_generation);
+ const FontData* result = fontCache()->getFontData(*font, m_familyIndex, m_fontSelector.get());
+ if (result) {
+ m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont()));
+ if (result->isLoading())
+ m_loadingCustomFonts = true;
+ }
+ return result;
+}
+
+const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const UChar* characters, int length) const
+{
+ // This method is only called when the primary font does not contain the characters we need.
+ // Begin our search at position 1.
+ unsigned realizedFontIndex = 1;
+ const FontData* fontData = fontDataAt(font, realizedFontIndex);
+ while (fontData && !fontData->containsCharacters(characters, length))
+ fontData = fontDataAt(font, ++realizedFontIndex);
+
+ if (!fontData) {
+ ASSERT(fontCache()->generation() == m_generation);
+ fontData = fontCache()->getFontDataForCharacters(*font, characters, length);
+ }
+
+ return fontData;
+}
+
+void FontFallbackList::setPlatformFont(const FontPlatformData& platformData)
+{
+ m_familyIndex = cAllFamiliesScanned;
+ ASSERT(fontCache()->generation() == m_generation);
+ const FontData* fontData = fontCache()->getCachedFontData(&platformData);
+ m_fontList.append(pair<const FontData*, bool>(fontData, fontData->isCustomFont()));
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/FontFallbackList.h b/Source/WebCore/platform/graphics/FontFallbackList.h
new file mode 100644
index 0000000..a10f5af
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontFallbackList.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontFallbackList_h
+#define FontFallbackList_h
+
+#include "FontSelector.h"
+#include "SimpleFontData.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class Font;
+class GlyphPageTreeNode;
+class GraphicsContext;
+class IntRect;
+class FontDescription;
+class FontPlatformData;
+class FontSelector;
+
+const int cAllFamiliesScanned = -1;
+
+class FontFallbackList : public RefCounted<FontFallbackList> {
+public:
+ static PassRefPtr<FontFallbackList> create() { return adoptRef(new FontFallbackList()); }
+
+ ~FontFallbackList() { releaseFontData(); }
+ void invalidate(PassRefPtr<FontSelector>);
+
+ bool isFixedPitch(const Font* f) const { if (m_pitch == UnknownPitch) determinePitch(f); return m_pitch == FixedPitch; };
+ void determinePitch(const Font*) const;
+
+ bool loadingCustomFonts() const { return m_loadingCustomFonts; }
+
+ FontSelector* fontSelector() const { return m_fontSelector.get(); }
+ unsigned generation() const { return m_generation; }
+
+private:
+ FontFallbackList();
+
+ const SimpleFontData* primarySimpleFontData(const Font* f)
+ {
+ ASSERT(isMainThread());
+ if (!m_cachedPrimarySimpleFontData)
+ m_cachedPrimarySimpleFontData = primaryFontData(f)->fontDataForCharacter(' ');
+ return m_cachedPrimarySimpleFontData;
+ }
+
+ const FontData* primaryFontData(const Font* f) const { return fontDataAt(f, 0); }
+ const FontData* fontDataAt(const Font*, unsigned index) const;
+ const FontData* fontDataForCharacters(const Font*, const UChar*, int length) const;
+
+ void setPlatformFont(const FontPlatformData&);
+
+ void releaseFontData();
+
+ mutable Vector<pair<const FontData*, bool>, 1> m_fontList;
+ mutable HashMap<int, GlyphPageTreeNode*> m_pages;
+ mutable GlyphPageTreeNode* m_pageZero;
+ mutable const SimpleFontData* m_cachedPrimarySimpleFontData;
+ RefPtr<FontSelector> m_fontSelector;
+ mutable int m_familyIndex;
+ mutable Pitch m_pitch;
+ mutable bool m_loadingCustomFonts;
+ unsigned m_generation;
+
+ friend class Font;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/FontFamily.cpp b/Source/WebCore/platform/graphics/FontFamily.cpp
new file mode 100644
index 0000000..12b59a4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontFamily.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FontFamily.h"
+
+namespace WebCore {
+
+FontFamily::FontFamily(const FontFamily& other)
+ : m_family(other.m_family)
+ , m_next(other.m_next)
+{
+}
+
+FontFamily& FontFamily::operator=(const FontFamily& other)
+{
+ m_family = other.m_family;
+ m_next = other.m_next;
+ return *this;
+}
+
+bool operator==(const FontFamily& a, const FontFamily& b)
+{
+ if (a.family() != b.family())
+ return false;
+ const FontFamily* ap;
+ const FontFamily* bp;
+ for (ap = a.next(), bp = b.next(); ap != bp; ap = ap->next(), bp = bp->next()) {
+ if (!ap || !bp)
+ return false;
+ if (ap->family() != bp->family())
+ return false;
+ }
+ return true;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/FontFamily.h b/Source/WebCore/platform/graphics/FontFamily.h
new file mode 100644
index 0000000..21a6b64
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontFamily.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 FontFamily_h
+#define FontFamily_h
+
+#include <wtf/RefCounted.h>
+#include <wtf/ListRefPtr.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+class SharedFontFamily;
+
+class FontFamily {
+public:
+ FontFamily() { }
+ FontFamily(const FontFamily&);
+ FontFamily& operator=(const FontFamily&);
+
+ void setFamily(const AtomicString& family) { m_family = family; }
+ const AtomicString& family() const { return m_family; }
+ bool familyIsEmpty() const { return m_family.isEmpty(); }
+
+ const FontFamily* next() const;
+
+ void appendFamily(PassRefPtr<SharedFontFamily>);
+ PassRefPtr<SharedFontFamily> releaseNext();
+
+private:
+ AtomicString m_family;
+ ListRefPtr<SharedFontFamily> m_next;
+};
+
+class SharedFontFamily : public FontFamily, public RefCounted<SharedFontFamily> {
+public:
+ static PassRefPtr<SharedFontFamily> create()
+ {
+ return adoptRef(new SharedFontFamily);
+ }
+
+private:
+ SharedFontFamily() { }
+};
+
+bool operator==(const FontFamily&, const FontFamily&);
+inline bool operator!=(const FontFamily& a, const FontFamily& b) { return !(a == b); }
+
+inline const FontFamily* FontFamily::next() const
+{
+ return m_next.get();
+}
+
+inline void FontFamily::appendFamily(PassRefPtr<SharedFontFamily> family)
+{
+ m_next = family;
+}
+
+inline PassRefPtr<SharedFontFamily> FontFamily::releaseNext()
+{
+ return m_next.release();
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/FontFastPath.cpp b/Source/WebCore/platform/graphics/FontFastPath.cpp
new file mode 100644
index 0000000..367c8a2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontFastPath.cpp
@@ -0,0 +1,486 @@
+/**
+ * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "CharacterNames.h"
+#include "FloatRect.h"
+#include "FontCache.h"
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GlyphPageTreeNode.h"
+#include "SimpleFontData.h"
+#include "WidthIterator.h"
+
+#include <wtf/MathExtras.h>
+#include <wtf/unicode/Unicode.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const
+{
+ ASSERT(isMainThread());
+
+ if (variant == AutoVariant) {
+ if (m_fontDescription.smallCaps()) {
+ UChar32 upperC = toUpper(c);
+ if (upperC != c) {
+ c = upperC;
+ variant = SmallCapsVariant;
+ } else
+ variant = NormalVariant;
+ } else
+ variant = NormalVariant;
+ }
+
+ if (mirror)
+ c = mirroredChar(c);
+
+ unsigned pageNumber = (c / GlyphPage::size);
+
+ GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
+ if (!node) {
+ node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
+ if (pageNumber)
+ m_fontList->m_pages.set(pageNumber, node);
+ else
+ m_fontList->m_pageZero = node;
+ }
+
+ GlyphPage* page;
+ if (variant == NormalVariant) {
+ // Fastest loop, for the common case (normal variant).
+ while (true) {
+ page = node->page();
+ if (page) {
+ GlyphData data = page->glyphDataForCharacter(c);
+ if (data.fontData) {
+ if (data.fontData->platformData().orientation() == Vertical && data.fontData->orientation() == Horizontal && Font::isCJKIdeographOrSymbol(c)) {
+ const SimpleFontData* ideographFontData = data.fontData->brokenIdeographFontData();
+ GlyphPageTreeNode* ideographNode = GlyphPageTreeNode::getRootChild(ideographFontData, pageNumber);
+ const GlyphPage* ideographPage = ideographNode->page();
+ if (ideographPage) {
+ GlyphData data = ideographPage->glyphDataForCharacter(c);
+ if (data.fontData)
+ return data;
+ }
+
+ // Shouldn't be possible to even reach this point.
+ ASSERT_NOT_REACHED();
+ }
+ return data;
+ }
+
+ if (node->isSystemFallback())
+ break;
+ }
+
+ // Proceed with the fallback list.
+ node = node->getChild(fontDataAt(node->level()), pageNumber);
+ if (pageNumber)
+ m_fontList->m_pages.set(pageNumber, node);
+ else
+ m_fontList->m_pageZero = node;
+ }
+ } else {
+ while (true) {
+ page = node->page();
+ if (page) {
+ GlyphData data = page->glyphDataForCharacter(c);
+ if (data.fontData) {
+ // The variantFontData function should not normally return 0.
+ // But if it does, we will just render the capital letter big.
+ const SimpleFontData* variantFontData = data.fontData->variantFontData(m_fontDescription, variant);
+ if (!variantFontData)
+ return data;
+
+ GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData, pageNumber);
+ const GlyphPage* variantPage = variantNode->page();
+ if (variantPage) {
+ GlyphData data = variantPage->glyphDataForCharacter(c);
+ if (data.fontData)
+ return data;
+ }
+
+ // Do not attempt system fallback off the variantFontData. This is the very unlikely case that
+ // a font has the lowercase character but the small caps font does not have its uppercase version.
+ return variantFontData->missingGlyphData();
+ }
+
+ if (node->isSystemFallback())
+ break;
+ }
+
+ // Proceed with the fallback list.
+ node = node->getChild(fontDataAt(node->level()), pageNumber);
+ if (pageNumber)
+ m_fontList->m_pages.set(pageNumber, node);
+ else
+ m_fontList->m_pageZero = node;
+ }
+ }
+
+ ASSERT(page);
+ ASSERT(node->isSystemFallback());
+
+ // System fallback is character-dependent. When we get here, we
+ // know that the character in question isn't in the system fallback
+ // font's glyph page. Try to lazily create it here.
+ UChar codeUnits[2];
+ int codeUnitsLength;
+ if (c <= 0xFFFF) {
+ codeUnits[0] = Font::normalizeSpaces(c);
+ codeUnitsLength = 1;
+ } else {
+ codeUnits[0] = U16_LEAD(c);
+ codeUnits[1] = U16_TRAIL(c);
+ codeUnitsLength = 2;
+ }
+ const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
+ if (variant != NormalVariant && characterFontData)
+ characterFontData = characterFontData->variantFontData(m_fontDescription, variant);
+ if (characterFontData) {
+ // Got the fallback glyph and font.
+ GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
+ GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
+ // Cache it so we don't have to do system fallback again next time.
+ if (variant == NormalVariant) {
+#if OS(WINCE)
+ // missingGlyphData returns a null character, which is not suitable for GDI to display.
+ // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
+ // display the character, probably because the font package is not installed correctly.
+ // So we just always set the glyph to be same as the character, and let GDI solve it.
+ page->setGlyphDataForCharacter(c, c, characterFontData);
+ return page->glyphDataForCharacter(c);
+#else
+ page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
+#endif
+ }
+ return data;
+ }
+
+ // Even system fallback can fail; use the missing glyph in that case.
+ // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
+ GlyphData data = primaryFont()->missingGlyphData();
+ if (variant == NormalVariant) {
+#if OS(WINCE)
+ // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
+ page->setGlyphDataForCharacter(c, c, data.fontData);
+ return page->glyphDataForCharacter(c);
+#else
+ page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
+#endif
+ }
+ return data;
+}
+
+bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
+{
+ unsigned pageNumber = (character / GlyphPage::size);
+
+ GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
+ GlyphPage* page = node->page();
+
+ return page && page->fontDataForCharacter(character);
+}
+
+// FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
+// standard emphasis marks do so.
+bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
+{
+ if (mark.isEmpty())
+ return false;
+
+#if ENABLE(SVG_FONTS)
+ // FIXME: Implement for SVG fonts.
+ if (primaryFont()->isSVGFont())
+ return false;
+#endif
+
+ UChar32 character = mark[0];
+
+ if (U16_IS_SURROGATE(character)) {
+ if (!U16_IS_SURROGATE_LEAD(character))
+ return false;
+
+ if (mark.length() < 2)
+ return false;
+
+ UChar low = mark[1];
+ if (!U16_IS_TRAIL(low))
+ return false;
+
+ character = U16_GET_SUPPLEMENTARY(character, low);
+ }
+
+ glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
+ return true;
+}
+
+int Font::emphasisMarkAscent(const AtomicString& mark) const
+{
+ GlyphData markGlyphData;
+ if (!getEmphasisMarkGlyphData(mark, markGlyphData))
+ return 0;
+
+ const SimpleFontData* markFontData = markGlyphData.fontData;
+ ASSERT(markFontData);
+ if (!markFontData)
+ return 0;
+
+ return markFontData->ascent();
+}
+
+int Font::emphasisMarkDescent(const AtomicString& mark) const
+{
+ GlyphData markGlyphData;
+ if (!getEmphasisMarkGlyphData(mark, markGlyphData))
+ return 0;
+
+ const SimpleFontData* markFontData = markGlyphData.fontData;
+ ASSERT(markFontData);
+ if (!markFontData)
+ return 0;
+
+ return markFontData->descent();
+}
+
+int Font::emphasisMarkHeight(const AtomicString& mark) const
+{
+ GlyphData markGlyphData;
+ if (!getEmphasisMarkGlyphData(mark, markGlyphData))
+ return 0;
+
+ const SimpleFontData* markFontData = markGlyphData.fontData;
+ ASSERT(markFontData);
+ if (!markFontData)
+ return 0;
+
+ return markFontData->height();
+}
+
+float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
+{
+ float initialAdvance;
+
+ WidthIterator it(this, run, 0, false, forTextEmphasis);
+ it.advance(from);
+ float beforeWidth = it.m_runWidthSoFar;
+ it.advance(to, &glyphBuffer);
+
+ if (glyphBuffer.isEmpty())
+ return 0;
+
+ float afterWidth = it.m_runWidthSoFar;
+
+ if (run.rtl()) {
+ float finalRoundingWidth = it.m_finalRoundingWidth;
+ it.advance(run.length());
+ initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
+ } else
+ initialAdvance = beforeWidth;
+
+ if (run.rtl()) {
+ for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
+ glyphBuffer.swap(i, end);
+ }
+
+ return initialAdvance;
+}
+
+void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+ // This glyph buffer holds our glyphs+advances+font data for each glyph.
+ GlyphBuffer glyphBuffer;
+
+ float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
+
+ if (glyphBuffer.isEmpty())
+ return;
+
+ FloatPoint startPoint(startX, point.y());
+ drawGlyphBuffer(context, glyphBuffer, startPoint);
+}
+
+void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
+{
+ GlyphBuffer glyphBuffer;
+ float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
+
+ if (glyphBuffer.isEmpty())
+ return;
+
+ drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
+}
+
+void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
+{
+ // Draw each contiguous run of glyphs that use the same font data.
+ const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
+ FloatSize offset = glyphBuffer.offsetAt(0);
+ FloatPoint startPoint(point);
+ float nextX = startPoint.x();
+ int lastFrom = 0;
+ int nextGlyph = 0;
+ while (nextGlyph < glyphBuffer.size()) {
+ const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
+ FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
+ if (nextFontData != fontData || nextOffset != offset) {
+ drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
+
+ lastFrom = nextGlyph;
+ fontData = nextFontData;
+ offset = nextOffset;
+ startPoint.setX(nextX);
+ }
+ nextX += glyphBuffer.advanceAt(nextGlyph);
+ nextGlyph++;
+ }
+
+ drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
+}
+
+inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
+{
+ if (fontData->orientation() == Horizontal) {
+ FloatRect bounds = fontData->boundsForGlyph(glyph);
+ return bounds.x() + bounds.width() / 2;
+ }
+ // FIXME: Use glyph bounds once they make sense for vertical fonts.
+ return fontData->widthForGlyph(glyph) / 2;
+}
+
+inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
+{
+ return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
+}
+
+void Font::drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
+{
+ GlyphData markGlyphData;
+ if (!getEmphasisMarkGlyphData(mark, markGlyphData))
+ return;
+
+ const SimpleFontData* markFontData = markGlyphData.fontData;
+ ASSERT(markFontData);
+ if (!markFontData)
+ return;
+
+ Glyph markGlyph = markGlyphData.glyph;
+ Glyph spaceGlyph = markFontData->spaceGlyph();
+
+ float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
+ FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
+
+ GlyphBuffer markBuffer;
+ for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
+ float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
+ float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph;
+ markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
+ middleOfLastGlyph = middleOfNextGlyph;
+ }
+ markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
+
+ drawGlyphBuffer(context, markBuffer, startPoint);
+}
+
+float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+ WidthIterator it(this, run, fallbackFonts, glyphOverflow);
+ it.advance(run.length(), glyphBuffer);
+
+ if (glyphOverflow) {
+ glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - ascent());
+ glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - descent());
+ glyphOverflow->left = ceilf(it.firstGlyphOverflow());
+ glyphOverflow->right = ceilf(it.lastGlyphOverflow());
+ }
+
+ return it.m_runWidthSoFar;
+}
+
+FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
+{
+ WidthIterator it(this, run);
+ it.advance(from);
+ float beforeWidth = it.m_runWidthSoFar;
+ it.advance(to);
+ float afterWidth = it.m_runWidthSoFar;
+
+ // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning.
+ if (run.rtl()) {
+ it.advance(run.length());
+ float totalWidth = it.m_runWidthSoFar;
+ return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
+ }
+
+ return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
+}
+
+int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
+{
+ float delta = x;
+
+ WidthIterator it(this, run);
+ GlyphBuffer localGlyphBuffer;
+ unsigned offset;
+ if (run.rtl()) {
+ delta -= floatWidthForSimpleText(run, 0);
+ while (1) {
+ offset = it.m_currentCharacter;
+ float w;
+ if (!it.advanceOneCharacter(w, &localGlyphBuffer))
+ break;
+ delta += w;
+ if (includePartialGlyphs) {
+ if (delta - w / 2 >= 0)
+ break;
+ } else {
+ if (delta >= 0)
+ break;
+ }
+ }
+ } else {
+ while (1) {
+ offset = it.m_currentCharacter;
+ float w;
+ if (!it.advanceOneCharacter(w, &localGlyphBuffer))
+ break;
+ delta -= w;
+ if (includePartialGlyphs) {
+ if (delta + w / 2 <= 0)
+ break;
+ } else {
+ if (delta <= 0)
+ break;
+ }
+ }
+ }
+
+ return offset;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/FontOrientation.h b/Source/WebCore/platform/graphics/FontOrientation.h
new file mode 100644
index 0000000..12cf5c1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontOrientation.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 FontOrientation_h
+#define FontOrientation_h
+
+namespace WebCore {
+
+enum FontOrientation { Horizontal, Vertical };
+
+} // namespace WebCore
+
+#endif // FontOrientation_h
diff --git a/Source/WebCore/platform/graphics/FontRenderingMode.h b/Source/WebCore/platform/graphics/FontRenderingMode.h
new file mode 100644
index 0000000..c1ce497
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontRenderingMode.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 FontRenderingMode_h
+#define FontRenderingMode_h
+
+namespace WebCore {
+
+// This setting is used to provide ways of switching between multiple rendering modes that may have different
+// metrics. It is used to switch between CG and GDI text on Windows.
+enum FontRenderingMode { NormalRenderingMode, AlternateRenderingMode };
+
+} // namespace WebCore
+
+#endif // FontRenderingMode_h
diff --git a/Source/WebCore/platform/graphics/FontSelector.h b/Source/WebCore/platform/graphics/FontSelector.h
new file mode 100644
index 0000000..156bf10
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontSelector.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 FontSelector_h
+#define FontSelector_h
+
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class FontData;
+class FontDescription;
+
+class FontSelector : public RefCounted<FontSelector> {
+public:
+ virtual ~FontSelector() { }
+ virtual FontData* getFontData(const FontDescription&, const AtomicString& familyName) = 0;
+
+ virtual void fontCacheInvalidated() { }
+};
+
+} // namespace WebCore
+
+#endif // FontSelector_h
diff --git a/Source/WebCore/platform/graphics/FontSmoothingMode.h b/Source/WebCore/platform/graphics/FontSmoothingMode.h
new file mode 100644
index 0000000..7c23394
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontSmoothingMode.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 FontSmoothingMode_h
+#define FontSmoothingMode_h
+
+namespace WebCore {
+
+ enum FontSmoothingMode { AutoSmoothing, NoSmoothing, Antialiased, SubpixelAntialiased };
+
+} // namespace WebCore
+
+#endif // FontSmoothingMode_h
diff --git a/Source/WebCore/platform/graphics/FontTraitsMask.h b/Source/WebCore/platform/graphics/FontTraitsMask.h
new file mode 100644
index 0000000..686c30c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/FontTraitsMask.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 FontTraitsMask_h
+#define FontTraitsMask_h
+
+namespace WebCore {
+
+ enum {
+ FontStyleNormalBit = 0,
+ FontStyleItalicBit,
+ FontVariantNormalBit,
+ FontVariantSmallCapsBit,
+ FontWeight100Bit,
+ FontWeight200Bit,
+ FontWeight300Bit,
+ FontWeight400Bit,
+ FontWeight500Bit,
+ FontWeight600Bit,
+ FontWeight700Bit,
+ FontWeight800Bit,
+ FontWeight900Bit,
+ FontTraitsMaskWidth
+ };
+
+ enum FontTraitsMask {
+ FontStyleNormalMask = 1 << FontStyleNormalBit,
+ FontStyleItalicMask = 1 << FontStyleItalicBit,
+ FontStyleMask = FontStyleNormalMask | FontStyleItalicMask,
+
+ FontVariantNormalMask = 1 << FontVariantNormalBit,
+ FontVariantSmallCapsMask = 1 << FontVariantSmallCapsBit,
+ FontVariantMask = FontVariantNormalMask | FontVariantSmallCapsMask,
+
+ FontWeight100Mask = 1 << FontWeight100Bit,
+ FontWeight200Mask = 1 << FontWeight200Bit,
+ FontWeight300Mask = 1 << FontWeight300Bit,
+ FontWeight400Mask = 1 << FontWeight400Bit,
+ FontWeight500Mask = 1 << FontWeight500Bit,
+ FontWeight600Mask = 1 << FontWeight600Bit,
+ FontWeight700Mask = 1 << FontWeight700Bit,
+ FontWeight800Mask = 1 << FontWeight800Bit,
+ FontWeight900Mask = 1 << FontWeight900Bit,
+ FontWeightMask = FontWeight100Mask | FontWeight200Mask | FontWeight300Mask | FontWeight400Mask | FontWeight500Mask | FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask
+ };
+
+} // namespace WebCore
+#endif // FontTraitsMask_h
diff --git a/Source/WebCore/platform/graphics/GeneratedImage.cpp b/Source/WebCore/platform/graphics/GeneratedImage.cpp
new file mode 100644
index 0000000..f2c175b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GeneratedImage.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "GeneratedImage.h"
+
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+
+using namespace std;
+
+namespace WebCore {
+
+void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp)
+{
+ context->save();
+ context->setCompositeOperation(compositeOp);
+ context->clip(dstRect);
+ context->translate(dstRect.x(), dstRect.y());
+ if (dstRect.size() != srcRect.size())
+ context->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height()));
+ context->translate(-srcRect.x(), -srcRect.y());
+ context->fillRect(FloatRect(FloatPoint(), m_size), *m_generator.get());
+ context->restore();
+}
+
+void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect)
+{
+ // Allow the generator to provide visually-equivalent tiling parameters for better performance.
+ IntSize adjustedSize = m_size;
+ FloatRect adjustedSrcRect = srcRect;
+ m_generator->adjustParametersForTiledDrawing(adjustedSize, adjustedSrcRect);
+
+ // Create a BitmapImage and call drawPattern on it.
+ OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(adjustedSize);
+ if (!imageBuffer)
+ return;
+
+ // Fill with the gradient.
+ GraphicsContext* graphicsContext = imageBuffer->context();
+ graphicsContext->fillRect(FloatRect(FloatPoint(), adjustedSize), *m_generator.get());
+
+ // Tile the image buffer into the context.
+ imageBuffer->drawPattern(context, adjustedSrcRect, patternTransform, phase, styleColorSpace, compositeOp, destRect);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/GeneratedImage.h b/Source/WebCore/platform/graphics/GeneratedImage.h
new file mode 100644
index 0000000..67a3150
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GeneratedImage.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 GeneratedImage_h
+#define GeneratedImage_h
+
+#include "Image.h"
+
+#include "Generator.h"
+#include "IntSize.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class GeneratedImage : public Image {
+public:
+ static PassRefPtr<GeneratedImage> create(PassRefPtr<Generator> generator, const IntSize& size)
+ {
+ return adoptRef(new GeneratedImage(generator, size));
+ }
+ virtual ~GeneratedImage() {}
+
+ virtual bool hasSingleSecurityOrigin() const { return true; }
+
+ // These are only used for SVGGeneratedImage right now
+ virtual void setContainerSize(const IntSize& size) { m_size = size; }
+ virtual bool usesContainerSize() const { return true; }
+ virtual bool hasRelativeWidth() const { return true; }
+ virtual bool hasRelativeHeight() const { return true; }
+
+ virtual IntSize size() const { return m_size; }
+
+ // Assume that generated content has no decoded data we need to worry about
+ virtual void destroyDecodedData(bool /*destroyAll*/ = true) { }
+ virtual unsigned decodedSize() const { return 0; }
+
+protected:
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
+ virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect);
+
+ GeneratedImage(PassRefPtr<Generator> generator, const IntSize& size)
+ : m_generator(generator)
+ , m_size(size)
+ {
+ }
+
+ RefPtr<Generator> m_generator;
+ IntSize m_size;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/Generator.h b/Source/WebCore/platform/graphics/Generator.h
new file mode 100644
index 0000000..b64d051
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Generator.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 Generator_h
+#define Generator_h
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class FloatRect;
+class GraphicsContext;
+
+class Generator : public RefCounted<Generator> {
+public:
+ virtual ~Generator() {};
+
+ virtual void fill(GraphicsContext*, const FloatRect&) = 0;
+ virtual void adjustParametersForTiledDrawing(IntSize& /* size */, FloatRect& /* srcRect */) { }
+};
+
+} //namespace
+
+#endif
diff --git a/Source/WebCore/platform/graphics/GlyphBuffer.h b/Source/WebCore/platform/graphics/GlyphBuffer.h
new file mode 100644
index 0000000..6f1fe7b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GlyphBuffer.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2008 Torch Mobile Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 GlyphBuffer_h
+#define GlyphBuffer_h
+
+#include "FloatSize.h"
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN))
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+#if PLATFORM(CAIRO) || (PLATFORM(WX) && defined(__WXGTK__))
+#include <cairo.h>
+#endif
+
+namespace WebCore {
+
+typedef unsigned short Glyph;
+class SimpleFontData;
+
+#if PLATFORM(CAIRO)
+// FIXME: Why does Cairo use such a huge struct instead of just an offset into an array?
+typedef cairo_glyph_t GlyphBufferGlyph;
+#elif OS(WINCE)
+typedef wchar_t GlyphBufferGlyph;
+#else
+typedef Glyph GlyphBufferGlyph;
+#endif
+
+// CG uses CGSize instead of FloatSize so that the result of advances()
+// can be passed directly to CGContextShowGlyphsWithAdvances in FontMac.mm
+#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN))
+typedef CGSize GlyphBufferAdvance;
+#elif OS(WINCE)
+// There is no cross-platform code that uses the height of GlyphBufferAdvance,
+// so we can save memory space on embedded devices by storing only the width
+typedef float GlyphBufferAdvance;
+#else
+typedef FloatSize GlyphBufferAdvance;
+#endif
+
+class GlyphBuffer {
+public:
+ bool isEmpty() const { return m_fontData.isEmpty(); }
+ int size() const { return m_fontData.size(); }
+
+ void clear()
+ {
+ m_fontData.clear();
+ m_glyphs.clear();
+ m_advances.clear();
+#if PLATFORM(WIN)
+ m_offsets.clear();
+#endif
+ }
+
+ GlyphBufferGlyph* glyphs(int from) { return m_glyphs.data() + from; }
+ GlyphBufferAdvance* advances(int from) { return m_advances.data() + from; }
+ const GlyphBufferGlyph* glyphs(int from) const { return m_glyphs.data() + from; }
+ const GlyphBufferAdvance* advances(int from) const { return m_advances.data() + from; }
+
+ const SimpleFontData* fontDataAt(int index) const { return m_fontData[index]; }
+
+ void swap(int index1, int index2)
+ {
+ const SimpleFontData* f = m_fontData[index1];
+ m_fontData[index1] = m_fontData[index2];
+ m_fontData[index2] = f;
+
+ GlyphBufferGlyph g = m_glyphs[index1];
+ m_glyphs[index1] = m_glyphs[index2];
+ m_glyphs[index2] = g;
+
+ GlyphBufferAdvance s = m_advances[index1];
+ m_advances[index1] = m_advances[index2];
+ m_advances[index2] = s;
+
+#if PLATFORM(WIN)
+ FloatSize offset = m_offsets[index1];
+ m_offsets[index1] = m_offsets[index2];
+ m_offsets[index2] = offset;
+#endif
+ }
+
+ Glyph glyphAt(int index) const
+ {
+#if PLATFORM(CAIRO)
+ return m_glyphs[index].index;
+#else
+ return m_glyphs[index];
+#endif
+ }
+
+ float advanceAt(int index) const
+ {
+#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN))
+ return m_advances[index].width;
+#elif OS(WINCE)
+ return m_advances[index];
+#else
+ return m_advances[index].width();
+#endif
+ }
+
+ FloatSize offsetAt(int index) const
+ {
+#if PLATFORM(WIN)
+ return m_offsets[index];
+#else
+ UNUSED_PARAM(index);
+ return FloatSize();
+#endif
+ }
+
+ void add(Glyph glyph, const SimpleFontData* font, float width, const FloatSize* offset = 0)
+ {
+ m_fontData.append(font);
+
+#if PLATFORM(CAIRO)
+ cairo_glyph_t cairoGlyph;
+ cairoGlyph.index = glyph;
+ m_glyphs.append(cairoGlyph);
+#else
+ m_glyphs.append(glyph);
+#endif
+
+#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN))
+ CGSize advance = { width, 0 };
+ m_advances.append(advance);
+#elif OS(WINCE)
+ m_advances.append(width);
+#else
+ m_advances.append(FloatSize(width, 0));
+#endif
+
+#if PLATFORM(WIN)
+ if (offset)
+ m_offsets.append(*offset);
+ else
+ m_offsets.append(FloatSize());
+#else
+ UNUSED_PARAM(offset);
+#endif
+ }
+
+#if !OS(WINCE)
+ void add(Glyph glyph, const SimpleFontData* font, GlyphBufferAdvance advance)
+ {
+ m_fontData.append(font);
+#if PLATFORM(CAIRO)
+ cairo_glyph_t cairoGlyph;
+ cairoGlyph.index = glyph;
+ m_glyphs.append(cairoGlyph);
+#else
+ m_glyphs.append(glyph);
+#endif
+
+ m_advances.append(advance);
+ }
+#endif
+
+private:
+ Vector<const SimpleFontData*, 2048> m_fontData;
+ Vector<GlyphBufferGlyph, 2048> m_glyphs;
+ Vector<GlyphBufferAdvance, 2048> m_advances;
+#if PLATFORM(WIN)
+ Vector<FloatSize, 2048> m_offsets;
+#endif
+};
+
+}
+#endif
diff --git a/Source/WebCore/platform/graphics/GlyphMetricsMap.h b/Source/WebCore/platform/graphics/GlyphMetricsMap.h
new file mode 100644
index 0000000..fa85bcc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GlyphMetricsMap.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2006, 2009 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 GlyphMetricsMap_h
+#define GlyphMetricsMap_h
+
+#include <wtf/FixedArray.h>
+#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+typedef unsigned short Glyph;
+
+const float cGlyphSizeUnknown = -1;
+
+template<class T> class GlyphMetricsMap : public Noncopyable {
+public:
+ GlyphMetricsMap() : m_filledPrimaryPage(false) { }
+ ~GlyphMetricsMap()
+ {
+ if (m_pages)
+ deleteAllValues(*m_pages);
+ }
+
+ T metricsForGlyph(Glyph glyph)
+ {
+ return locatePage(glyph / GlyphMetricsPage::size)->metricsForGlyph(glyph);
+ }
+
+ void setMetricsForGlyph(Glyph glyph, const T& metrics)
+ {
+ locatePage(glyph / GlyphMetricsPage::size)->setMetricsForGlyph(glyph, metrics);
+ }
+
+private:
+ struct GlyphMetricsPage {
+ static const size_t size = 256; // Usually covers Latin-1 in a single page.
+ FixedArray<T, size> m_metrics;
+
+ T metricsForGlyph(Glyph glyph) const { return m_metrics[glyph % size]; }
+ void setMetricsForGlyph(Glyph glyph, const T& metrics)
+ {
+ setMetricsForIndex(glyph % size, metrics);
+ }
+ void setMetricsForIndex(unsigned index, const T& metrics)
+ {
+ m_metrics[index] = metrics;
+ }
+ };
+
+ GlyphMetricsPage* locatePage(unsigned pageNumber)
+ {
+ if (!pageNumber && m_filledPrimaryPage)
+ return &m_primaryPage;
+ return locatePageSlowCase(pageNumber);
+ }
+
+ GlyphMetricsPage* locatePageSlowCase(unsigned pageNumber);
+
+ static T unknownMetrics();
+
+ bool m_filledPrimaryPage;
+ GlyphMetricsPage m_primaryPage; // We optimize for the page that contains glyph indices 0-255.
+ OwnPtr<HashMap<int, GlyphMetricsPage*> > m_pages;
+};
+
+template<> inline float GlyphMetricsMap<float>::unknownMetrics()
+{
+ return cGlyphSizeUnknown;
+}
+
+template<> inline FloatRect GlyphMetricsMap<FloatRect>::unknownMetrics()
+{
+ return FloatRect(0, 0, cGlyphSizeUnknown, cGlyphSizeUnknown);
+}
+
+template<class T> typename GlyphMetricsMap<T>::GlyphMetricsPage* GlyphMetricsMap<T>::locatePageSlowCase(unsigned pageNumber)
+{
+ GlyphMetricsPage* page;
+ if (!pageNumber) {
+ ASSERT(!m_filledPrimaryPage);
+ page = &m_primaryPage;
+ m_filledPrimaryPage = true;
+ } else {
+ if (m_pages) {
+ if ((page = m_pages->get(pageNumber)))
+ return page;
+ } else
+ m_pages = adoptPtr(new HashMap<int, GlyphMetricsPage*>);
+ page = new GlyphMetricsPage;
+ m_pages->set(pageNumber, page);
+ }
+
+ // Fill in the whole page with the unknown glyph information.
+ for (unsigned i = 0; i < GlyphMetricsPage::size; i++)
+ page->setMetricsForIndex(i, unknownMetrics());
+
+ return page;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp
new file mode 100644
index 0000000..3df14b9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "CharacterNames.h"
+#include "PlatformString.h"
+#include "SegmentedFontData.h"
+#include "SimpleFontData.h"
+#include <stdio.h>
+#include <wtf/text/CString.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+using std::max;
+using std::min;
+
+HashMap<int, GlyphPageTreeNode*>* GlyphPageTreeNode::roots = 0;
+GlyphPageTreeNode* GlyphPageTreeNode::pageZeroRoot = 0;
+
+GlyphPageTreeNode* GlyphPageTreeNode::getRoot(unsigned pageNumber)
+{
+ static bool initialized;
+ if (!initialized) {
+ initialized = true;
+ roots = new HashMap<int, GlyphPageTreeNode*>;
+ pageZeroRoot = new GlyphPageTreeNode;
+ }
+
+ GlyphPageTreeNode* node = pageNumber ? roots->get(pageNumber) : pageZeroRoot;
+ if (!node) {
+ node = new GlyphPageTreeNode;
+#ifndef NDEBUG
+ node->m_pageNumber = pageNumber;
+#endif
+ if (pageNumber)
+ roots->set(pageNumber, node);
+ else
+ pageZeroRoot = node;
+ }
+ return node;
+}
+
+size_t GlyphPageTreeNode::treeGlyphPageCount()
+{
+ size_t count = 0;
+ if (roots) {
+ HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end();
+ for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); it != end; ++it)
+ count += it->second->pageCount();
+ }
+
+ if (pageZeroRoot)
+ count += pageZeroRoot->pageCount();
+
+ return count;
+}
+
+size_t GlyphPageTreeNode::pageCount() const
+{
+ size_t count = m_page && m_page->owner() == this ? 1 : 0;
+ HashMap<const FontData*, GlyphPageTreeNode*>::const_iterator end = m_children.end();
+ for (HashMap<const FontData*, GlyphPageTreeNode*>::const_iterator it = m_children.begin(); it != end; ++it)
+ count += it->second->pageCount();
+
+ return count;
+}
+
+void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData)
+{
+ // Enumerate all the roots and prune any tree that contains our custom font data.
+ if (roots) {
+ HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end();
+ for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); it != end; ++it)
+ it->second->pruneCustomFontData(fontData);
+ }
+
+ if (pageZeroRoot)
+ pageZeroRoot->pruneCustomFontData(fontData);
+}
+
+void GlyphPageTreeNode::pruneTreeFontData(const SimpleFontData* fontData)
+{
+ if (roots) {
+ HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end();
+ for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); it != end; ++it)
+ it->second->pruneFontData(fontData);
+ }
+
+ if (pageZeroRoot)
+ pageZeroRoot->pruneFontData(fontData);
+}
+
+GlyphPageTreeNode::~GlyphPageTreeNode()
+{
+ deleteAllValues(m_children);
+ delete m_systemFallbackChild;
+}
+
+static bool fill(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ if (!fontData->isSVGFont())
+ return pageToFill->fill(offset, length, buffer, bufferLength, fontData);
+
+ // SVG Fonts do not use the glyph page cache. Zero fill the glyph
+ // positions and return false to indicate the glyphs were not found.
+ for (unsigned i = 0; i < length; ++i)
+ pageToFill->setGlyphDataForIndex(offset + i, 0, 0);
+ return false;
+}
+
+void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNumber)
+{
+ ASSERT(!m_page);
+
+ // This function must not be called for the root of the tree, because that
+ // level does not contain any glyphs.
+ ASSERT(m_level > 0 && m_parent);
+
+ // The parent's page will be 0 if we are level one or the parent's font data
+ // did not contain any glyphs for that page.
+ GlyphPage* parentPage = m_parent->page();
+
+ // NULL FontData means we're being asked for the system fallback font.
+ if (fontData) {
+ if (m_level == 1) {
+ // Children of the root hold pure pages. These will cover only one
+ // font data's glyphs, and will have glyph index 0 if the font data does not
+ // contain the glyph.
+ unsigned start = pageNumber * GlyphPage::size;
+ UChar buffer[GlyphPage::size * 2 + 2];
+ unsigned bufferLength;
+ unsigned i;
+
+ // Fill in a buffer with the entire "page" of characters that we want to look up glyphs for.
+ if (start < 0x10000) {
+ bufferLength = GlyphPage::size;
+ for (i = 0; i < GlyphPage::size; i++)
+ buffer[i] = start + i;
+
+ if (start == 0) {
+ // Control characters must not render at all.
+ for (i = 0; i < 0x20; ++i)
+ buffer[i] = zeroWidthSpace;
+ for (i = 0x7F; i < 0xA0; i++)
+ buffer[i] = zeroWidthSpace;
+ buffer[softHyphen] = zeroWidthSpace;
+
+ // \n, \t, and nonbreaking space must render as a space.
+ buffer[(int)'\n'] = ' ';
+ buffer[(int)'\t'] = ' ';
+ buffer[noBreakSpace] = ' ';
+ } else if (start == (leftToRightMark & ~(GlyphPage::size - 1))) {
+ // LRM, RLM, LRE, RLE, ZWNJ, ZWJ, and PDF must not render at all.
+ buffer[leftToRightMark - start] = zeroWidthSpace;
+ buffer[rightToLeftMark - start] = zeroWidthSpace;
+ buffer[leftToRightEmbed - start] = zeroWidthSpace;
+ buffer[rightToLeftEmbed - start] = zeroWidthSpace;
+ buffer[leftToRightOverride - start] = zeroWidthSpace;
+ buffer[rightToLeftOverride - start] = zeroWidthSpace;
+ buffer[zeroWidthNonJoiner - start] = zeroWidthSpace;
+ buffer[zeroWidthJoiner - start] = zeroWidthSpace;
+ buffer[popDirectionalFormatting - start] = zeroWidthSpace;
+ } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) {
+ // Object replacement character must not render at all.
+ buffer[objectReplacementCharacter - start] = zeroWidthSpace;
+ }
+ } else {
+ bufferLength = GlyphPage::size * 2;
+ for (i = 0; i < GlyphPage::size; i++) {
+ int c = i + start;
+ buffer[i * 2] = U16_LEAD(c);
+ buffer[i * 2 + 1] = U16_TRAIL(c);
+ }
+ }
+
+ m_page = GlyphPage::create(this);
+
+ // Now that we have a buffer full of characters, we want to get back an array
+ // of glyph indices. This part involves calling into the platform-specific
+ // routine of our glyph map for actually filling in the page with the glyphs.
+ // Success is not guaranteed. For example, Times fails to fill page 260, giving glyph data
+ // for only 128 out of 256 characters.
+ bool haveGlyphs;
+ if (fontData->isSegmented()) {
+ haveGlyphs = false;
+
+ const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData);
+ unsigned numRanges = segmentedFontData->numRanges();
+ bool zeroFilled = false;
+ RefPtr<GlyphPage> scratchPage;
+ GlyphPage* pageToFill = m_page.get();
+ for (unsigned i = 0; i < numRanges; i++) {
+ const FontDataRange& range = segmentedFontData->rangeAt(i);
+ // all this casting is to ensure all the parameters to min and max have the same type,
+ // to avoid ambiguous template parameter errors on Windows
+ int from = max(0, static_cast<int>(range.from()) - static_cast<int>(start));
+ int to = 1 + min(static_cast<int>(range.to()) - static_cast<int>(start), static_cast<int>(GlyphPage::size) - 1);
+ if (from < static_cast<int>(GlyphPage::size) && to > 0) {
+ if (haveGlyphs && !scratchPage) {
+ scratchPage = GlyphPage::create(this);
+ pageToFill = scratchPage.get();
+ }
+
+ if (!zeroFilled) {
+ if (from > 0 || to < static_cast<int>(GlyphPage::size)) {
+ for (unsigned i = 0; i < GlyphPage::size; i++)
+ pageToFill->setGlyphDataForIndex(i, 0, 0);
+ }
+ zeroFilled = true;
+ }
+ haveGlyphs |= fill(pageToFill, from, to - from, buffer + from * (start < 0x10000 ? 1 : 2), (to - from) * (start < 0x10000 ? 1 : 2), range.fontData());
+ if (scratchPage) {
+ ASSERT(to <= static_cast<int>(GlyphPage::size));
+ for (int j = from; j < to; j++) {
+ if (!m_page->glyphAt(j) && pageToFill->glyphAt(j))
+ m_page->setGlyphDataForIndex(j, pageToFill->glyphDataForIndex(j));
+ }
+ }
+ }
+ }
+ } else
+ haveGlyphs = fill(m_page.get(), 0, GlyphPage::size, buffer, bufferLength, static_cast<const SimpleFontData*>(fontData));
+
+ if (!haveGlyphs)
+ m_page = 0;
+ } else if (parentPage && parentPage->owner() != m_parent) {
+ // The page we're overriding may not be owned by our parent node.
+ // This happens when our parent node provides no useful overrides
+ // and just copies the pointer to an already-existing page (see
+ // below).
+ //
+ // We want our override to be shared by all nodes that reference
+ // that page to avoid duplication, and so standardize on having the
+ // page's owner collect all the overrides. Call getChild on the
+ // page owner with the desired font data (this will populate
+ // the page) and then reference it.
+ m_page = parentPage->owner()->getChild(fontData, pageNumber)->page();
+ } else {
+ // Get the pure page for the fallback font (at level 1 with no
+ // overrides). getRootChild will always create a page if one
+ // doesn't exist, but the page doesn't necessarily have glyphs
+ // (this pointer may be 0).
+ GlyphPage* fallbackPage = getRootChild(fontData, pageNumber)->page();
+ if (!parentPage) {
+ // When the parent has no glyphs for this page, we can easily
+ // override it just by supplying the glyphs from our font.
+ m_page = fallbackPage;
+ } else if (!fallbackPage) {
+ // When our font has no glyphs for this page, we can just reference the
+ // parent page.
+ m_page = parentPage;
+ } else {
+ // Combine the parent's glyphs and ours to form a new more complete page.
+ m_page = GlyphPage::create(this);
+
+ // Overlay the parent page on the fallback page. Check if the fallback font
+ // has added anything.
+ bool newGlyphs = false;
+ for (unsigned i = 0; i < GlyphPage::size; i++) {
+ if (parentPage->glyphAt(i))
+ m_page->setGlyphDataForIndex(i, parentPage->glyphDataForIndex(i));
+ else if (fallbackPage->glyphAt(i)) {
+ m_page->setGlyphDataForIndex(i, fallbackPage->glyphDataForIndex(i));
+ newGlyphs = true;
+ } else
+ m_page->setGlyphDataForIndex(i, 0, 0);
+ }
+
+ if (!newGlyphs)
+ // We didn't override anything, so our override is just the parent page.
+ m_page = parentPage;
+ }
+ }
+ } else {
+ m_page = GlyphPage::create(this);
+ // System fallback. Initialized with the parent's page here, as individual
+ // entries may use different fonts depending on character. If the Font
+ // ever finds it needs a glyph out of the system fallback page, it will
+ // ask the system for the best font to use and fill that glyph in for us.
+ if (parentPage)
+ m_page->copyFrom(*parentPage);
+ else
+ m_page->clear();
+ }
+}
+
+GlyphPageTreeNode* GlyphPageTreeNode::getChild(const FontData* fontData, unsigned pageNumber)
+{
+ ASSERT(fontData || !m_isSystemFallback);
+ ASSERT(pageNumber == m_pageNumber);
+
+ GlyphPageTreeNode* child = fontData ? m_children.get(fontData) : m_systemFallbackChild;
+ if (!child) {
+ child = new GlyphPageTreeNode;
+ child->m_parent = this;
+ child->m_level = m_level + 1;
+ if (fontData && fontData->isCustomFont()) {
+ for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent)
+ curr->m_customFontCount++;
+ }
+
+#ifndef NDEBUG
+ child->m_pageNumber = m_pageNumber;
+#endif
+ if (fontData) {
+ m_children.set(fontData, child);
+ fontData->setMaxGlyphPageTreeLevel(max(fontData->maxGlyphPageTreeLevel(), child->m_level));
+ } else {
+ m_systemFallbackChild = child;
+ child->m_isSystemFallback = true;
+ }
+ child->initializePage(fontData, pageNumber);
+ }
+ return child;
+}
+
+void GlyphPageTreeNode::pruneCustomFontData(const FontData* fontData)
+{
+ if (!fontData || !m_customFontCount)
+ return;
+
+ // Prune any branch that contains this FontData.
+ GlyphPageTreeNode* node = m_children.get(fontData);
+ if (node) {
+ m_children.remove(fontData);
+ unsigned fontCount = node->m_customFontCount + 1;
+ delete node;
+ for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent)
+ curr->m_customFontCount -= fontCount;
+ }
+
+ // Check any branches that remain that still have custom fonts underneath them.
+ if (!m_customFontCount)
+ return;
+ HashMap<const FontData*, GlyphPageTreeNode*>::iterator end = m_children.end();
+ for (HashMap<const FontData*, GlyphPageTreeNode*>::iterator it = m_children.begin(); it != end; ++it)
+ it->second->pruneCustomFontData(fontData);
+}
+
+void GlyphPageTreeNode::pruneFontData(const SimpleFontData* fontData, unsigned level)
+{
+ ASSERT(fontData);
+ if (!fontData)
+ return;
+
+ // Prune any branch that contains this FontData.
+ HashMap<const FontData*, GlyphPageTreeNode*>::iterator child = m_children.find(fontData);
+ if (child == m_children.end()) {
+ // If there is no level-1 node for fontData, then there is no deeper node for it in this tree.
+ if (!level)
+ return;
+ } else {
+ GlyphPageTreeNode* node = child->second;
+ m_children.remove(fontData);
+ unsigned customFontCount = node->m_customFontCount;
+ delete node;
+ if (customFontCount) {
+ for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent)
+ curr->m_customFontCount -= customFontCount;
+ }
+ }
+
+ level++;
+ if (level > fontData->maxGlyphPageTreeLevel())
+ return;
+
+ HashMap<const FontData*, GlyphPageTreeNode*>::iterator end = m_children.end();
+ for (HashMap<const FontData*, GlyphPageTreeNode*>::iterator it = m_children.begin(); it != end; ++it)
+ it->second->pruneFontData(fontData, level);
+}
+
+#ifndef NDEBUG
+ void GlyphPageTreeNode::showSubtree()
+ {
+ Vector<char> indent(level());
+ indent.fill('\t', level());
+ indent.append(0);
+
+ HashMap<const FontData*, GlyphPageTreeNode*>::iterator end = m_children.end();
+ for (HashMap<const FontData*, GlyphPageTreeNode*>::iterator it = m_children.begin(); it != end; ++it) {
+ printf("%s\t%p %s\n", indent.data(), it->first, it->first->description().utf8().data());
+ it->second->showSubtree();
+ }
+ if (m_systemFallbackChild) {
+ printf("%s\t* fallback\n", indent.data());
+ m_systemFallbackChild->showSubtree();
+ }
+ }
+#endif
+
+}
+
+#ifndef NDEBUG
+void showGlyphPageTrees()
+{
+ printf("Page 0:\n");
+ showGlyphPageTree(0);
+ HashMap<int, WebCore::GlyphPageTreeNode*>::iterator end = WebCore::GlyphPageTreeNode::roots->end();
+ for (HashMap<int, WebCore::GlyphPageTreeNode*>::iterator it = WebCore::GlyphPageTreeNode::roots->begin(); it != end; ++it) {
+ printf("\nPage %d:\n", it->first);
+ showGlyphPageTree(it->first);
+ }
+}
+
+void showGlyphPageTree(unsigned pageNumber)
+{
+ WebCore::GlyphPageTreeNode::getRoot(pageNumber)->showSubtree();
+}
+#endif
diff --git a/Source/WebCore/platform/graphics/GlyphPageTreeNode.h b/Source/WebCore/platform/graphics/GlyphPageTreeNode.h
new file mode 100644
index 0000000..b68c0ed
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GlyphPageTreeNode.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 GlyphPageTreeNode_h
+#define GlyphPageTreeNode_h
+
+#include <string.h>
+#include <wtf/HashMap.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/unicode/Unicode.h>
+
+#ifndef NDEBUG
+void showGlyphPageTrees();
+void showGlyphPageTree(unsigned pageNumber);
+#endif
+
+namespace WebCore {
+
+class FontData;
+class GlyphPageTreeNode;
+class SimpleFontData;
+
+typedef unsigned short Glyph;
+
+// Holds the glyph index and the corresponding SimpleFontData information for a given
+// character.
+struct GlyphData {
+ GlyphData(Glyph g = 0, const SimpleFontData* f = 0)
+ : glyph(g)
+ , fontData(f)
+ {
+ }
+ Glyph glyph;
+ const SimpleFontData* fontData;
+};
+
+// A GlyphPage contains a fixed-size set of GlyphData mappings for a contiguous
+// range of characters in the Unicode code space. GlyphPages are indexed
+// starting from 0 and incrementing for each 256 glyphs.
+//
+// One page may actually include glyphs from other fonts if the characters are
+// missing in the primary font. It is owned by exactly one GlyphPageTreeNode,
+// although multiple nodes may reference it as their "page" if they are supposed
+// to be overriding the parent's node, but provide no additional information.
+class GlyphPage : public RefCounted<GlyphPage> {
+public:
+ static PassRefPtr<GlyphPage> create(GlyphPageTreeNode* owner)
+ {
+ return adoptRef(new GlyphPage(owner));
+ }
+
+ static const size_t size = 256; // Covers Latin-1 in a single page.
+
+ unsigned indexForCharacter(UChar32 c) const { return c % size; }
+ GlyphData glyphDataForCharacter(UChar32 c) const
+ {
+ unsigned index = indexForCharacter(c);
+ return GlyphData(m_glyphs[index], m_glyphFontData[index]);
+ }
+
+ GlyphData glyphDataForIndex(unsigned index) const
+ {
+ ASSERT(index < size);
+ return GlyphData(m_glyphs[index], m_glyphFontData[index]);
+ }
+
+ Glyph glyphAt(unsigned index) const
+ {
+ ASSERT(index < size);
+ return m_glyphs[index];
+ }
+
+ const SimpleFontData* fontDataForCharacter(UChar32 c) const
+ {
+ return m_glyphFontData[indexForCharacter(c)];
+ }
+
+ void setGlyphDataForCharacter(UChar32 c, Glyph g, const SimpleFontData* f)
+ {
+ setGlyphDataForIndex(indexForCharacter(c), g, f);
+ }
+ void setGlyphDataForIndex(unsigned index, Glyph g, const SimpleFontData* f)
+ {
+ ASSERT(index < size);
+ m_glyphs[index] = g;
+ m_glyphFontData[index] = f;
+ }
+ void setGlyphDataForIndex(unsigned index, const GlyphData& glyphData)
+ {
+ setGlyphDataForIndex(index, glyphData.glyph, glyphData.fontData);
+ }
+
+ void copyFrom(const GlyphPage& other)
+ {
+ memcpy(m_glyphs, other.m_glyphs, sizeof(m_glyphs));
+ memcpy(m_glyphFontData, other.m_glyphFontData, sizeof(m_glyphFontData));
+ }
+
+ void clear()
+ {
+ memset(m_glyphs, 0, sizeof(m_glyphs));
+ memset(m_glyphFontData, 0, sizeof(m_glyphFontData));
+ }
+
+ GlyphPageTreeNode* owner() const { return m_owner; }
+
+ // Implemented by the platform.
+ bool fill(unsigned offset, unsigned length, UChar* characterBuffer, unsigned bufferLength, const SimpleFontData*);
+
+private:
+ GlyphPage(GlyphPageTreeNode* owner)
+ : m_owner(owner)
+ {
+ }
+
+ // Separate arrays, rather than array of GlyphData, to save space.
+ Glyph m_glyphs[size];
+ const SimpleFontData* m_glyphFontData[size];
+
+ GlyphPageTreeNode* m_owner;
+};
+
+// The glyph page tree is a data structure that maps (FontData, glyph page number)
+// to a GlyphPage. Level 0 (the "root") is special. There is one root
+// GlyphPageTreeNode for each glyph page number. The roots do not have a
+// GlyphPage associated with them, and their initializePage() function is never
+// called to fill the glyphs.
+//
+// Each root node maps a FontData pointer to another GlyphPageTreeNode at
+// level 1 (the "root child") that stores the actual glyphs for a specific font data.
+// These nodes will only have a GlyphPage if they have glyphs for that range.
+//
+// Levels greater than one correspond to subsequent levels of the fallback list
+// for that font. These levels override their parent's page of glyphs by
+// filling in holes with the new font (thus making a more complete page).
+//
+// A NULL FontData pointer corresponds to the system fallback
+// font. It is tracked separately from the regular pages and overrides so that
+// the glyph pages do not get polluted with these last-resort glyphs. The
+// system fallback page is not populated at construction like the other pages,
+// but on demand for each glyph, because the system may need to use different
+// fallback fonts for each. This lazy population is done by the Font.
+class GlyphPageTreeNode {
+public:
+ GlyphPageTreeNode()
+ : m_parent(0)
+ , m_level(0)
+ , m_isSystemFallback(false)
+ , m_customFontCount(0)
+ , m_systemFallbackChild(0)
+#ifndef NDEBUG
+ , m_pageNumber(0)
+#endif
+ {
+ }
+
+ ~GlyphPageTreeNode();
+
+ static HashMap<int, GlyphPageTreeNode*>* roots;
+ static GlyphPageTreeNode* pageZeroRoot;
+
+ static GlyphPageTreeNode* getRootChild(const FontData* fontData, unsigned pageNumber)
+ {
+ return getRoot(pageNumber)->getChild(fontData, pageNumber);
+ }
+
+ static void pruneTreeCustomFontData(const FontData*);
+ static void pruneTreeFontData(const SimpleFontData*);
+
+ void pruneCustomFontData(const FontData*);
+ void pruneFontData(const SimpleFontData*, unsigned level = 0);
+
+ GlyphPageTreeNode* parent() const { return m_parent; }
+ GlyphPageTreeNode* getChild(const FontData*, unsigned pageNumber);
+
+ // Returns a page of glyphs (or NULL if there are no glyphs in this page's character range).
+ GlyphPage* page() const { return m_page.get(); }
+
+ // Returns the level of this node. See class-level comment.
+ unsigned level() const { return m_level; }
+
+ // The system fallback font has special rules (see above).
+ bool isSystemFallback() const { return m_isSystemFallback; }
+
+ static size_t treeGlyphPageCount();
+ size_t pageCount() const;
+
+private:
+ static GlyphPageTreeNode* getRoot(unsigned pageNumber);
+ void initializePage(const FontData*, unsigned pageNumber);
+
+#ifndef NDEBUG
+ void showSubtree();
+#endif
+
+ GlyphPageTreeNode* m_parent;
+ RefPtr<GlyphPage> m_page;
+ unsigned m_level : 31;
+ bool m_isSystemFallback : 1;
+ unsigned m_customFontCount;
+ HashMap<const FontData*, GlyphPageTreeNode*> m_children;
+ GlyphPageTreeNode* m_systemFallbackChild;
+
+#ifndef NDEBUG
+ unsigned m_pageNumber;
+
+ friend void ::showGlyphPageTree(unsigned pageNumber);
+#endif
+};
+
+} // namespace WebCore
+
+#endif // GlyphPageTreeNode_h
diff --git a/Source/WebCore/platform/graphics/Gradient.cpp b/Source/WebCore/platform/graphics/Gradient.cpp
new file mode 100644
index 0000000..6d0f535
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Gradient.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "Color.h"
+#include "FloatRect.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1)
+ : m_radial(false)
+ , m_p0(p0)
+ , m_p1(p1)
+ , m_r0(0)
+ , m_r1(0)
+ , m_aspectRatio(1)
+ , m_stopsSorted(false)
+ , m_lastStop(0)
+ , m_spreadMethod(SpreadMethodPad)
+{
+ platformInit();
+}
+
+Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio)
+ : m_radial(true)
+ , m_p0(p0)
+ , m_p1(p1)
+ , m_r0(r0)
+ , m_r1(r1)
+ , m_aspectRatio(aspectRatio)
+ , m_stopsSorted(false)
+ , m_lastStop(0)
+ , m_spreadMethod(SpreadMethodPad)
+{
+ platformInit();
+}
+
+Gradient::~Gradient()
+{
+ platformDestroy();
+}
+
+void Gradient::adjustParametersForTiledDrawing(IntSize& size, FloatRect& srcRect)
+{
+ if (m_radial)
+ return;
+
+ if (srcRect.isEmpty())
+ return;
+
+ if (m_p0.x() == m_p1.x()) {
+ size.setWidth(1);
+ srcRect.setWidth(1);
+ srcRect.setX(0);
+ return;
+ }
+ if (m_p0.y() != m_p1.y())
+ return;
+
+ size.setHeight(1);
+ srcRect.setHeight(1);
+ srcRect.setY(0);
+}
+
+void Gradient::addColorStop(float value, const Color& color)
+{
+ float r;
+ float g;
+ float b;
+ float a;
+ color.getRGBA(r, g, b, a);
+ m_stops.append(ColorStop(value, r, g, b, a));
+
+ m_stopsSorted = false;
+ platformDestroy();
+}
+
+void Gradient::addColorStop(const Gradient::ColorStop& stop)
+{
+ m_stops.append(stop);
+
+ m_stopsSorted = false;
+ platformDestroy();
+}
+
+static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
+{
+ return a.stop < b.stop;
+}
+
+void Gradient::sortStopsIfNecessary()
+{
+ if (m_stopsSorted)
+ return;
+
+ m_stopsSorted = true;
+
+ if (!m_stops.size())
+ return;
+
+ // Shortcut for the ideal case (ordered 2-stop gradient)
+ if (m_stops.size() == 2 && compareStops(*m_stops.begin(), *m_stops.end()))
+ return;
+
+ std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
+}
+
+void Gradient::getColor(float value, float* r, float* g, float* b, float* a) const
+{
+ ASSERT(value >= 0);
+ ASSERT(value <= 1);
+
+ if (m_stops.isEmpty()) {
+ *r = 0;
+ *g = 0;
+ *b = 0;
+ *a = 0;
+ return;
+ }
+ if (!m_stopsSorted) {
+ if (m_stops.size())
+ std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
+ m_stopsSorted = true;
+ }
+ if (value <= 0 || value <= m_stops.first().stop) {
+ *r = m_stops.first().red;
+ *g = m_stops.first().green;
+ *b = m_stops.first().blue;
+ *a = m_stops.first().alpha;
+ return;
+ }
+ if (value >= 1 || value >= m_stops.last().stop) {
+ *r = m_stops.last().red;
+ *g = m_stops.last().green;
+ *b = m_stops.last().blue;
+ *a = m_stops.last().alpha;
+ return;
+ }
+
+ // Find stop before and stop after and interpolate.
+ int stop = findStop(value);
+ const ColorStop& lastStop = m_stops[stop];
+ const ColorStop& nextStop = m_stops[stop + 1];
+ float stopFraction = (value - lastStop.stop) / (nextStop.stop - lastStop.stop);
+ *r = lastStop.red + (nextStop.red - lastStop.red) * stopFraction;
+ *g = lastStop.green + (nextStop.green - lastStop.green) * stopFraction;
+ *b = lastStop.blue + (nextStop.blue - lastStop.blue) * stopFraction;
+ *a = lastStop.alpha + (nextStop.alpha - lastStop.alpha) * stopFraction;
+}
+
+int Gradient::findStop(float value) const
+{
+ ASSERT(value >= 0);
+ ASSERT(value <= 1);
+ ASSERT(m_stopsSorted);
+
+ int numStops = m_stops.size();
+ ASSERT(numStops >= 2);
+ ASSERT(m_lastStop < numStops - 1);
+
+ int i = m_lastStop;
+ if (value < m_stops[i].stop)
+ i = 1;
+ else
+ i = m_lastStop + 1;
+
+ for (; i < numStops - 1; ++i)
+ if (value < m_stops[i].stop)
+ break;
+
+ m_lastStop = i - 1;
+ return m_lastStop;
+}
+
+bool Gradient::hasAlpha() const
+{
+ for (size_t i = 0; i < m_stops.size(); i++) {
+ if (m_stops[i].alpha < 1)
+ return true;
+ }
+
+ return false;
+}
+
+void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod)
+{
+ // FIXME: Should it become necessary, allow calls to this method after m_gradient has been set.
+ ASSERT(m_gradient == 0);
+ m_spreadMethod = spreadMethod;
+}
+
+void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation)
+{
+ m_gradientSpaceTransformation = gradientSpaceTransformation;
+ setPlatformGradientSpaceTransform(gradientSpaceTransformation);
+}
+
+#if !(PLATFORM(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(CAIRO)
+void Gradient::setPlatformGradientSpaceTransform(const AffineTransform&)
+{
+}
+#endif
+
+
+} //namespace
diff --git a/Source/WebCore/platform/graphics/Gradient.h b/Source/WebCore/platform/graphics/Gradient.h
new file mode 100644
index 0000000..790e8e1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Gradient.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 Gradient_h
+#define Gradient_h
+
+#include "AffineTransform.h"
+#include "FloatPoint.h"
+#include "Generator.h"
+#include "GraphicsTypes.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(CG)
+
+typedef struct CGContext* CGContextRef;
+
+#define USE_CG_SHADING defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
+
+#if USE_CG_SHADING
+typedef struct CGShading* CGShadingRef;
+typedef CGShadingRef PlatformGradient;
+#else
+typedef struct CGGradient* CGGradientRef;
+typedef CGGradientRef PlatformGradient;
+#endif
+
+#elif PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QGradient;
+QT_END_NAMESPACE
+typedef QGradient* PlatformGradient;
+#elif PLATFORM(CAIRO)
+typedef struct _cairo_pattern cairo_pattern_t;
+typedef cairo_pattern_t* PlatformGradient;
+#elif PLATFORM(SKIA)
+#if PLATFORM(ANDROID)
+#include "SkShader.h"
+typedef class PlatformGradientRec* PlatformGradient;
+#else
+class SkShader;
+typedef class SkShader* PlatformGradient;
+typedef class SkShader* PlatformPattern;
+#endif
+#elif PLATFORM(HAIKU)
+class BGradient;
+typedef BGradient* PlatformGradient;
+#else
+typedef void* PlatformGradient;
+#endif
+
+namespace WebCore {
+
+ class Color;
+
+ class Gradient : public Generator {
+ public:
+ static PassRefPtr<Gradient> create(const FloatPoint& p0, const FloatPoint& p1)
+ {
+ return adoptRef(new Gradient(p0, p1));
+ }
+ static PassRefPtr<Gradient> create(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio = 1)
+ {
+ return adoptRef(new Gradient(p0, r0, p1, r1, aspectRatio));
+ }
+ virtual ~Gradient();
+
+ struct ColorStop;
+ void addColorStop(const ColorStop&);
+ void addColorStop(float, const Color&);
+
+ void getColor(float value, float* r, float* g, float* b, float* a) const;
+ bool hasAlpha() const;
+
+ bool isRadial() const { return m_radial; }
+ bool isZeroSize() const { return m_p0.x() == m_p1.x() && m_p0.y() == m_p1.y() && (!m_radial || m_r0 == m_r1); }
+
+ const FloatPoint& p0() const { return m_p0; }
+ const FloatPoint& p1() const { return m_p1; }
+
+ void setP0(const FloatPoint& p) { m_p0 = p; }
+ void setP1(const FloatPoint& p) { m_p1 = p; }
+
+ float startRadius() const { return m_r0; }
+ float endRadius() const { return m_r1; }
+
+ void setStartRadius(float r) { m_r0 = r; }
+ void setEndRadius(float r) { m_r1 = r; }
+
+ float aspectRatio() const { return m_aspectRatio; }
+
+#if OS(WINCE) && !PLATFORM(QT)
+ const Vector<ColorStop, 2>& getStops() const;
+#else
+#if PLATFORM(ANDROID)
+ SkShader* getShader(SkShader::TileMode);
+#endif
+ PlatformGradient platformGradient();
+#endif
+
+ struct ColorStop {
+ float stop;
+ float red;
+ float green;
+ float blue;
+ float alpha;
+
+ ColorStop() : stop(0), red(0), green(0), blue(0), alpha(0) { }
+ ColorStop(float s, float r, float g, float b, float a) : stop(s), red(r), green(g), blue(b), alpha(a) { }
+ };
+
+ void setStopsSorted(bool s) { m_stopsSorted = s; }
+
+ void setSpreadMethod(GradientSpreadMethod);
+ GradientSpreadMethod spreadMethod() { return m_spreadMethod; }
+ void setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation);
+ // Qt and CG transform the gradient at draw time
+ AffineTransform gradientSpaceTransform() { return m_gradientSpaceTransformation; }
+
+ virtual void fill(GraphicsContext*, const FloatRect&);
+ virtual void adjustParametersForTiledDrawing(IntSize& size, FloatRect& srcRect);
+
+ void setPlatformGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation);
+
+#if PLATFORM(CG)
+ void paint(CGContextRef);
+ void paint(GraphicsContext*);
+#endif
+
+ private:
+ Gradient(const FloatPoint& p0, const FloatPoint& p1);
+ Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio);
+
+ void platformInit() { m_gradient = 0; }
+ void platformDestroy();
+
+ int findStop(float value) const;
+ void sortStopsIfNecessary();
+
+ bool m_radial;
+ FloatPoint m_p0;
+ FloatPoint m_p1;
+ float m_r0;
+ float m_r1;
+ float m_aspectRatio; // For elliptical gradient, width / height.
+ mutable Vector<ColorStop, 2> m_stops;
+ mutable bool m_stopsSorted;
+ mutable int m_lastStop;
+ GradientSpreadMethod m_spreadMethod;
+ AffineTransform m_gradientSpaceTransformation;
+
+ PlatformGradient m_gradient;
+ };
+
+} //namespace
+
+#endif
diff --git a/Source/WebCore/platform/graphics/GraphicsContext.cpp b/Source/WebCore/platform/graphics/GraphicsContext.cpp
new file mode 100644
index 0000000..25bade7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GraphicsContext.cpp
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#include "BidiResolver.h"
+#include "Font.h"
+#include "Generator.h"
+#include "ImageBuffer.h"
+
+using namespace std;
+
+namespace WebCore {
+
+class TextRunIterator {
+public:
+ TextRunIterator()
+ : m_textRun(0)
+ , m_offset(0)
+ {
+ }
+
+ TextRunIterator(const TextRun* textRun, unsigned offset)
+ : m_textRun(textRun)
+ , m_offset(offset)
+ {
+ }
+
+ TextRunIterator(const TextRunIterator& other)
+ : m_textRun(other.m_textRun)
+ , m_offset(other.m_offset)
+ {
+ }
+
+ unsigned offset() const { return m_offset; }
+ void increment() { m_offset++; }
+ bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); }
+ UChar current() const { return (*m_textRun)[m_offset]; }
+ WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); }
+
+ bool operator==(const TextRunIterator& other)
+ {
+ return m_offset == other.m_offset && m_textRun == other.m_textRun;
+ }
+
+ bool operator!=(const TextRunIterator& other) { return !operator==(other); }
+
+private:
+ const TextRun* m_textRun;
+ int m_offset;
+};
+
+GraphicsContext::GraphicsContext(PlatformGraphicsContext* platformGraphicsContext)
+ : m_updatingControlTints(false)
+{
+ platformInit(platformGraphicsContext);
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ platformDestroy();
+}
+
+void GraphicsContext::save()
+{
+ if (paintingDisabled())
+ return;
+
+ m_stack.append(m_state);
+
+ savePlatformState();
+}
+
+void GraphicsContext::restore()
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_stack.isEmpty()) {
+ LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty");
+ return;
+ }
+ m_state = m_stack.last();
+ m_stack.removeLast();
+
+ restorePlatformState();
+}
+
+void GraphicsContext::setStrokeThickness(float thickness)
+{
+ m_state.strokeThickness = thickness;
+ setPlatformStrokeThickness(thickness);
+}
+
+void GraphicsContext::setStrokeStyle(StrokeStyle style)
+{
+ m_state.strokeStyle = style;
+ setPlatformStrokeStyle(style);
+}
+
+void GraphicsContext::setStrokeColor(const Color& color, ColorSpace colorSpace)
+{
+ m_state.strokeColor = color;
+ m_state.strokeColorSpace = colorSpace;
+ m_state.strokeGradient.clear();
+ m_state.strokePattern.clear();
+ setPlatformStrokeColor(color, colorSpace);
+}
+
+void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace)
+{
+ m_state.shadowOffset = offset;
+ m_state.shadowBlur = blur;
+ m_state.shadowColor = color;
+ m_state.shadowColorSpace = colorSpace;
+ setPlatformShadow(offset, blur, color, colorSpace);
+}
+
+void GraphicsContext::clearShadow()
+{
+ m_state.shadowOffset = FloatSize();
+ m_state.shadowBlur = 0;
+ m_state.shadowColor = Color();
+ m_state.shadowColorSpace = ColorSpaceDeviceRGB;
+ clearPlatformShadow();
+}
+
+bool GraphicsContext::hasShadow() const
+{
+ return m_state.shadowColor.isValid() && m_state.shadowColor.alpha()
+ && (m_state.shadowBlur || m_state.shadowOffset.width() || m_state.shadowOffset.height());
+}
+
+bool GraphicsContext::getShadow(FloatSize& offset, float& blur, Color& color, ColorSpace& colorSpace) const
+{
+ offset = m_state.shadowOffset;
+ blur = m_state.shadowBlur;
+ color = m_state.shadowColor;
+ colorSpace = m_state.shadowColorSpace;
+
+ return hasShadow();
+}
+
+float GraphicsContext::strokeThickness() const
+{
+ return m_state.strokeThickness;
+}
+
+StrokeStyle GraphicsContext::strokeStyle() const
+{
+ return m_state.strokeStyle;
+}
+
+Color GraphicsContext::strokeColor() const
+{
+ return m_state.strokeColor;
+}
+
+ColorSpace GraphicsContext::strokeColorSpace() const
+{
+ return m_state.strokeColorSpace;
+}
+
+WindRule GraphicsContext::fillRule() const
+{
+ return m_state.fillRule;
+}
+
+void GraphicsContext::setFillRule(WindRule fillRule)
+{
+ m_state.fillRule = fillRule;
+}
+
+void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace)
+{
+ m_state.fillColor = color;
+ m_state.fillColorSpace = colorSpace;
+ m_state.fillGradient.clear();
+ m_state.fillPattern.clear();
+ setPlatformFillColor(color, colorSpace);
+}
+
+Color GraphicsContext::fillColor() const
+{
+ return m_state.fillColor;
+}
+
+ColorSpace GraphicsContext::fillColorSpace() const
+{
+ return m_state.fillColorSpace;
+}
+
+void GraphicsContext::setShouldAntialias(bool b)
+{
+ m_state.shouldAntialias = b;
+ setPlatformShouldAntialias(b);
+}
+
+bool GraphicsContext::shouldAntialias() const
+{
+ return m_state.shouldAntialias;
+}
+
+void GraphicsContext::setShouldSmoothFonts(bool b)
+{
+ m_state.shouldSmoothFonts = b;
+ setPlatformShouldSmoothFonts(b);
+}
+
+bool GraphicsContext::shouldSmoothFonts() const
+{
+ return m_state.shouldSmoothFonts;
+}
+
+const GraphicsContextState& GraphicsContext::state() const
+{
+ return m_state;
+}
+
+void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
+{
+ ASSERT(pattern);
+ if (!pattern) {
+ setStrokeColor(Color::black, ColorSpaceDeviceRGB);
+ return;
+ }
+ m_state.strokeGradient.clear();
+ m_state.strokePattern = pattern;
+ setPlatformStrokePattern(m_state.strokePattern.get());
+}
+
+void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
+{
+ ASSERT(pattern);
+ if (!pattern) {
+ setFillColor(Color::black, ColorSpaceDeviceRGB);
+ return;
+ }
+ m_state.fillGradient.clear();
+ m_state.fillPattern = pattern;
+ setPlatformFillPattern(m_state.fillPattern.get());
+}
+
+void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
+{
+ ASSERT(gradient);
+ if (!gradient) {
+ setStrokeColor(Color::black, ColorSpaceDeviceRGB);
+ return;
+ }
+ m_state.strokeGradient = gradient;
+ m_state.strokePattern.clear();
+ setPlatformStrokeGradient(m_state.strokeGradient.get());
+}
+
+void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
+{
+ ASSERT(gradient);
+ if (!gradient) {
+ setFillColor(Color::black, ColorSpaceDeviceRGB);
+ return;
+ }
+ m_state.fillGradient = gradient;
+ m_state.fillPattern.clear();
+ setPlatformFillGradient(m_state.fillGradient.get());
+}
+
+Gradient* GraphicsContext::fillGradient() const
+{
+ return m_state.fillGradient.get();
+}
+
+Gradient* GraphicsContext::strokeGradient() const
+{
+ return m_state.strokeGradient.get();
+}
+
+Pattern* GraphicsContext::fillPattern() const
+{
+ return m_state.fillPattern.get();
+}
+
+Pattern* GraphicsContext::strokePattern() const
+{
+ return m_state.strokePattern.get();
+}
+
+void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms)
+{
+ m_state.shadowsIgnoreTransforms = ignoreTransforms;
+}
+
+bool GraphicsContext::shadowsIgnoreTransforms() const
+{
+ return m_state.shadowsIgnoreTransforms;
+}
+
+bool GraphicsContext::updatingControlTints() const
+{
+ return m_updatingControlTints;
+}
+
+void GraphicsContext::setUpdatingControlTints(bool b)
+{
+ setPaintingDisabled(b);
+ m_updatingControlTints = b;
+}
+
+void GraphicsContext::setPaintingDisabled(bool f)
+{
+ m_state.paintingDisabled = f;
+}
+
+bool GraphicsContext::paintingDisabled() const
+{
+ return m_state.paintingDisabled;
+}
+
+void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op)
+{
+ drawImage(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op);
+}
+
+void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale)
+{
+ drawImage(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale);
+}
+
+void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op)
+{
+ drawImage(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op);
+}
+
+void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale)
+{
+ drawImage(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale);
+}
+
+#if !OS(WINCE) || PLATFORM(QT)
+void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPoint& point, int from, int to)
+{
+ if (paintingDisabled())
+ return;
+
+ font.drawText(this, run, point, from, to);
+}
+#endif
+
+void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRun& run, const AtomicString& mark, const IntPoint& point, int from, int to)
+{
+ if (paintingDisabled())
+ return;
+
+ font.drawEmphasisMarks(this, run, mark, point, from, to);
+}
+
+void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point)
+{
+ if (paintingDisabled())
+ return;
+
+ BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
+ WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
+
+ bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, BidiContext::create(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride())));
+
+ bidiResolver.setPosition(TextRunIterator(&run, 0));
+ bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
+
+ if (!bidiResolver.runCount())
+ return;
+
+ FloatPoint currPoint = point;
+ BidiCharacterRun* bidiRun = bidiResolver.firstRun();
+ while (bidiRun) {
+
+ TextRun subrun = run;
+ subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start());
+ subrun.setRTL(bidiRun->level() % 2);
+ subrun.setDirectionalOverride(bidiRun->dirOverride(false));
+
+ font.drawText(this, subrun, currPoint);
+
+ bidiRun = bidiRun->next();
+ // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
+ if (bidiRun)
+ currPoint.move(font.floatWidth(subrun), 0.f);
+ }
+
+ bidiResolver.deleteRuns();
+}
+
+void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to)
+{
+ if (paintingDisabled())
+ return;
+
+ fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace);
+}
+
+void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
+{
+ if (paintingDisabled() || !image)
+ return;
+
+ float tsw = src.width();
+ float tsh = src.height();
+ float tw = dest.width();
+ float th = dest.height();
+
+ if (tsw == -1)
+ tsw = image->width();
+ if (tsh == -1)
+ tsh = image->height();
+
+ if (tw == -1)
+ tw = image->width();
+ if (th == -1)
+ th = image->height();
+
+ if (useLowQualityScale) {
+ InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
+ // FIXME: Should be InterpolationLow
+ setImageInterpolationQuality(InterpolationNone);
+ image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op);
+ setImageInterpolationQuality(previousInterpolationQuality);
+ } else
+ image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op);
+}
+
+void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale)
+{
+ if (paintingDisabled() || !image)
+ return;
+
+ if (useLowQualityScale) {
+ InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
+ setImageInterpolationQuality(InterpolationLow);
+ image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op);
+ setImageInterpolationQuality(previousInterpolationQuality);
+ } else
+ image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op);
+}
+
+void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
+{
+ if (paintingDisabled() || !image)
+ return;
+
+ if (hRule == Image::StretchTile && vRule == Image::StretchTile) {
+ // Just do a scale.
+ drawImage(image, styleColorSpace, dest, srcRect, op);
+ return;
+ }
+
+ if (useLowQualityScale) {
+ InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
+ setImageInterpolationQuality(InterpolationLow);
+ image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
+ setImageInterpolationQuality(previousInterpolationQuality);
+ } else
+ image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
+}
+
+void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op)
+{
+ drawImageBuffer(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op);
+}
+
+void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale)
+{
+ drawImageBuffer(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale);
+}
+
+void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op)
+{
+ drawImageBuffer(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op);
+}
+
+void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale)
+{
+ drawImageBuffer(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale);
+}
+
+void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
+{
+ if (paintingDisabled() || !image)
+ return;
+
+ float tsw = src.width();
+ float tsh = src.height();
+ float tw = dest.width();
+ float th = dest.height();
+
+ if (tsw == -1)
+ tsw = image->width();
+ if (tsh == -1)
+ tsh = image->height();
+
+ if (tw == -1)
+ tw = image->width();
+ if (th == -1)
+ th = image->height();
+
+ if (useLowQualityScale) {
+ InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
+ // FIXME: Should be InterpolationLow
+ setImageInterpolationQuality(InterpolationNone);
+ image->draw(this, styleColorSpace, dest, src, op, useLowQualityScale);
+ setImageInterpolationQuality(previousInterpolationQuality);
+ } else
+ image->draw(this, styleColorSpace, dest, src, op, useLowQualityScale);
+}
+
+void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
+ const IntSize& bottomLeft, const IntSize& bottomRight)
+{
+ if (paintingDisabled())
+ return;
+
+ Path path;
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ clip(path);
+}
+
+void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
+ const IntSize& bottomLeft, const IntSize& bottomRight)
+{
+ if (paintingDisabled())
+ return;
+
+ Path path;
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ clipOut(path);
+}
+
+void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+ buffer->clip(this, rect);
+}
+
+TextDrawingModeFlags GraphicsContext::textDrawingMode() const
+{
+ return m_state.textDrawingMode;
+}
+
+void GraphicsContext::setTextDrawingMode(TextDrawingModeFlags mode)
+{
+ m_state.textDrawingMode = mode;
+ if (paintingDisabled())
+ return;
+ setPlatformTextDrawingMode(mode);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator)
+{
+ if (paintingDisabled())
+ return;
+ generator.fill(this, rect);
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation)
+{
+ m_state.compositeOperator = compositeOperation;
+ setPlatformCompositeOperation(compositeOperation);
+}
+
+CompositeOperator GraphicsContext::compositeOperation() const
+{
+ return m_state.compositeOperator;
+}
+
+#if !(PLATFORM(SKIA) && !PLATFORM(ANDROID))
+void GraphicsContext::setPlatformFillGradient(Gradient*)
+{
+}
+
+void GraphicsContext::setPlatformFillPattern(Pattern*)
+{
+}
+
+void GraphicsContext::setPlatformStrokeGradient(Gradient*)
+{
+}
+
+void GraphicsContext::setPlatformStrokePattern(Pattern*)
+{
+}
+#endif
+
+#if !PLATFORM(CG) && !(PLATFORM(SKIA) && !PLATFORM(ANDROID))
+// Implement this if you want to go ahead and push the drawing mode into your native context
+// immediately.
+void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
+{
+}
+#endif
+
+<<<<<<< HEAD:WebCore/platform/graphics/GraphicsContext.cpp
+#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !(PLATFORM(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG)
+void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&)
+=======
+#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG)
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle)
+>>>>>>> webkit.org at r75315:Source/WebCore/platform/graphics/GraphicsContext.cpp
+{
+}
+#endif
+
+#if !PLATFORM(CG)
+void GraphicsContext::setPlatformShouldSmoothFonts(bool)
+{
+}
+#endif
+
+#if !PLATFORM(SKIA)
+void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&)
+{
+}
+
+void GraphicsContext::syncSoftwareCanvas()
+{
+}
+
+void GraphicsContext::markDirtyRect(const IntRect&)
+{
+}
+#endif
+
+
+void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
+{
+ // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
+ // works out. For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g.,
+ // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave
+ // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
+ if (penStyle == DottedStroke || penStyle == DashedStroke) {
+ if (p1.x() == p2.x()) {
+ p1.setY(p1.y() + strokeWidth);
+ p2.setY(p2.y() - strokeWidth);
+ } else {
+ p1.setX(p1.x() + strokeWidth);
+ p2.setX(p2.x() - strokeWidth);
+ }
+ }
+
+ if (static_cast<int>(strokeWidth) % 2) { //odd
+ if (p1.x() == p2.x()) {
+ // We're a vertical line. Adjust our x.
+ p1.setX(p1.x() + 0.5f);
+ p2.setX(p2.x() + 0.5f);
+ } else {
+ // We're a horizontal line. Adjust our y.
+ p1.setY(p1.y() + 0.5f);
+ p2.setY(p2.y() + 0.5f);
+ }
+ }
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/GraphicsContext.h b/Source/WebCore/platform/graphics/GraphicsContext.h
new file mode 100644
index 0000000..d72cba1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GraphicsContext.h
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 GraphicsContext_h
+#define GraphicsContext_h
+
+#include "ColorSpace.h"
+#include "DashArray.h"
+#include "FloatRect.h"
+#include "Gradient.h"
+#include "Image.h"
+#include "IntRect.h"
+#include "Path.h"
+#include "Pattern.h"
+#include "TextDirection.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+
+#if PLATFORM(CG)
+typedef struct CGContext PlatformGraphicsContext;
+#elif PLATFORM(CAIRO)
+namespace WebCore {
+class ContextShadow;
+}
+typedef struct _cairo PlatformGraphicsContext;
+#elif PLATFORM(OPENVG)
+namespace WebCore {
+class SurfaceOpenVG;
+}
+typedef class WebCore::SurfaceOpenVG PlatformGraphicsContext;
+#elif PLATFORM(QT)
+#include <QPainter>
+namespace WebCore {
+class ContextShadow;
+}
+typedef QPainter PlatformGraphicsContext;
+#elif PLATFORM(WX)
+class wxGCDC;
+class wxWindowDC;
+
+// wxGraphicsContext allows us to support Path, etc.
+// but on some platforms, e.g. Linux, it requires fairly
+// new software.
+#if USE(WXGC)
+// On OS X, wxGCDC is just a typedef for wxDC, so use wxDC explicitly to make
+// the linker happy.
+#ifdef __APPLE__
+ class wxDC;
+ typedef wxDC PlatformGraphicsContext;
+#else
+ typedef wxGCDC PlatformGraphicsContext;
+#endif
+#else
+ typedef wxWindowDC PlatformGraphicsContext;
+#endif
+#elif PLATFORM(SKIA)
+#if PLATFORM(ANDROID)
+namespace WebCore {
+class PlatformGraphicsContext;
+}
+class SkPaint;
+struct SkPoint;
+#else
+namespace WebCore {
+class PlatformContextSkia;
+}
+typedef WebCore::PlatformContextSkia PlatformGraphicsContext;
+#endif
+#elif PLATFORM(HAIKU)
+class BView;
+typedef BView PlatformGraphicsContext;
+struct pattern;
+#elif OS(WINCE)
+typedef struct HDC__ PlatformGraphicsContext;
+#else
+typedef void PlatformGraphicsContext;
+#endif
+
+#if PLATFORM(WIN)
+typedef struct HDC__* HDC;
+#if !PLATFORM(CG)
+// UInt8 is defined in CoreFoundation/CFBase.h
+typedef unsigned char UInt8;
+#endif
+#endif
+
+#if PLATFORM(QT) && defined(Q_WS_WIN)
+#include <windows.h>
+#endif
+
+namespace WebCore {
+
+#if OS(WINCE) && !PLATFORM(QT)
+ class SharedBitmap;
+ class SimpleFontData;
+ class GlyphBuffer;
+#endif
+
+ const int cMisspellingLineThickness = 3;
+ const int cMisspellingLinePatternWidth = 4;
+ const int cMisspellingLinePatternGapWidth = 1;
+
+ class AffineTransform;
+ class DrawingBuffer;
+ class Font;
+ class Generator;
+ class GraphicsContextPlatformPrivate;
+ class ImageBuffer;
+ class KURL;
+ class SharedGraphicsContext3D;
+ class TextRun;
+
+ enum TextDrawingMode {
+ TextModeInvisible = 0,
+ TextModeFill = 1 << 0,
+ TextModeStroke = 1 << 1,
+ TextModeClip = 1 << 2
+ };
+ typedef unsigned TextDrawingModeFlags;
+
+ enum StrokeStyle {
+ NoStroke,
+ SolidStroke,
+ DottedStroke,
+ DashedStroke
+ };
+
+ enum InterpolationQuality {
+ InterpolationDefault,
+ InterpolationNone,
+ InterpolationLow,
+ InterpolationMedium,
+ InterpolationHigh
+ };
+
+ struct GraphicsContextState {
+ GraphicsContextState()
+ : strokeThickness(0)
+ , shadowBlur(0)
+#if PLATFORM(CAIRO)
+ , globalAlpha(1)
+#endif
+ , textDrawingMode(TextModeFill)
+ , strokeColor(Color::black)
+ , fillColor(Color::black)
+ , strokeStyle(SolidStroke)
+ , fillRule(RULE_NONZERO)
+ , strokeColorSpace(ColorSpaceDeviceRGB)
+ , fillColorSpace(ColorSpaceDeviceRGB)
+ , shadowColorSpace(ColorSpaceDeviceRGB)
+ , compositeOperator(CompositeSourceOver)
+ , shouldAntialias(true)
+ , shouldSmoothFonts(true)
+ , paintingDisabled(false)
+ , shadowsIgnoreTransforms(false)
+ {
+ }
+
+ RefPtr<Gradient> strokeGradient;
+ RefPtr<Pattern> strokePattern;
+
+ RefPtr<Gradient> fillGradient;
+ RefPtr<Pattern> fillPattern;
+
+ FloatSize shadowOffset;
+
+ float strokeThickness;
+ float shadowBlur;
+
+#if PLATFORM(CAIRO)
+ float globalAlpha;
+#endif
+ TextDrawingModeFlags textDrawingMode;
+
+ Color strokeColor;
+ Color fillColor;
+ Color shadowColor;
+
+ StrokeStyle strokeStyle;
+ WindRule fillRule;
+
+ ColorSpace strokeColorSpace;
+ ColorSpace fillColorSpace;
+ ColorSpace shadowColorSpace;
+
+ CompositeOperator compositeOperator;
+
+ bool shouldAntialias : 1;
+ bool shouldSmoothFonts : 1;
+ bool paintingDisabled : 1;
+ bool shadowsIgnoreTransforms : 1;
+ };
+
+ class GraphicsContext : public Noncopyable {
+ public:
+ GraphicsContext(PlatformGraphicsContext*);
+ ~GraphicsContext();
+
+#if !OS(WINCE) || PLATFORM(QT)
+ PlatformGraphicsContext* platformContext() const;
+#endif
+
+ float strokeThickness() const;
+ void setStrokeThickness(float);
+ StrokeStyle strokeStyle() const;
+ void setStrokeStyle(StrokeStyle);
+ Color strokeColor() const;
+ ColorSpace strokeColorSpace() const;
+ void setStrokeColor(const Color&, ColorSpace);
+
+ void setStrokePattern(PassRefPtr<Pattern>);
+ Pattern* strokePattern() const;
+
+ void setStrokeGradient(PassRefPtr<Gradient>);
+ Gradient* strokeGradient() const;
+
+ WindRule fillRule() const;
+ void setFillRule(WindRule);
+ Color fillColor() const;
+ ColorSpace fillColorSpace() const;
+ void setFillColor(const Color&, ColorSpace);
+
+ void setFillPattern(PassRefPtr<Pattern>);
+ Pattern* fillPattern() const;
+
+ void setFillGradient(PassRefPtr<Gradient>);
+ Gradient* fillGradient() const;
+
+ void setShadowsIgnoreTransforms(bool);
+ bool shadowsIgnoreTransforms() const;
+
+ void setShouldAntialias(bool);
+ bool shouldAntialias() const;
+
+ void setShouldSmoothFonts(bool);
+ bool shouldSmoothFonts() const;
+
+ const GraphicsContextState& state() const;
+
+#if PLATFORM(CG)
+ void applyStrokePattern();
+ void applyFillPattern();
+ void drawPath(const Path&);
+
+ // Allow font smoothing (LCD antialiasing). Not part of the graphics state.
+ void setAllowsFontSmoothing(bool);
+#endif
+
+#if PLATFORM(ANDROID)
+ // initialize a paint for bitmaps
+ void setupBitmapPaint(SkPaint*);
+ // initialize a paint for filling
+ void setupFillPaint(SkPaint*);
+ // initialize a paint for stroking
+ void setupStrokePaint(SkPaint*);
+ // initialize a paint for a shadow, or if false is returned, the
+ // parameters are left untouched
+ bool setupShadowPaint(SkPaint* paint, SkPoint* offset);
+ // returns true if there is a valid (non-transparent) fill color
+ bool willFill() const;
+ // returns true if there is a valid (non-transparent) stroke color
+ bool willStroke() const;
+
+ // may return NULL, since we lazily allocate the path. This is the path
+ // that is drawn by drawPath()
+ const SkPath* getCurrPath() const;
+
+ /** platform-specific factory method to return a bitmap graphicscontext,
+ called by <canvas> when we need to draw offscreen. Caller is responsible for
+ deleting the context. Use drawOffscreenContext() to draw the context's image
+ onto another graphics context.
+ */
+ static GraphicsContext* createOffscreenContext(int width, int height);
+#endif
+
+ void save();
+ void restore();
+
+ // These draw methods will do both stroking and filling.
+ // FIXME: ...except drawRect(), which fills properly but always strokes
+ // using a 1-pixel stroke inset from the rect borders (of the correct
+ // stroke color).
+ void drawRect(const IntRect&);
+ void drawLine(const IntPoint&, const IntPoint&);
+ void drawEllipse(const IntRect&);
+ void drawConvexPolygon(size_t numPoints, const FloatPoint*, bool shouldAntialias = false);
+
+ void fillPath(const Path&);
+ void strokePath(const Path&);
+
+ // Arc drawing (used by border-radius in CSS) just supports stroking at the moment.
+ void strokeArc(const IntRect&, int startAngle, int angleSpan);
+
+ void fillRect(const FloatRect&);
+ void fillRect(const FloatRect&, const Color&, ColorSpace);
+ void fillRect(const FloatRect&, Generator&);
+ void fillRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color&, ColorSpace);
+
+ void clearRect(const FloatRect&);
+
+ void strokeRect(const FloatRect&, float lineWidth);
+
+ void drawImage(Image*, ColorSpace styleColorSpace, const IntPoint&, CompositeOperator = CompositeSourceOver);
+ void drawImage(Image*, ColorSpace styleColorSpace, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawImage(Image*, ColorSpace styleColorSpace, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver);
+ void drawImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawImage(Image*, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1),
+ CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize,
+ CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect,
+ Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile,
+ CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+
+ void drawImageBuffer(ImageBuffer*, ColorSpace styleColorSpace, const IntPoint&, CompositeOperator = CompositeSourceOver);
+ void drawImageBuffer(ImageBuffer*, ColorSpace styleColorSpace, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawImageBuffer(ImageBuffer*, ColorSpace styleColorSpace, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver);
+ void drawImageBuffer(ImageBuffer*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawImageBuffer(ImageBuffer*, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1),
+ CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+
+ void setImageInterpolationQuality(InterpolationQuality);
+ InterpolationQuality imageInterpolationQuality() const;
+
+ void clip(const FloatRect&);
+ void addRoundedRectClip(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight);
+ void addInnerRoundedRectClip(const IntRect&, int thickness);
+ void clipOut(const IntRect&);
+ void clipOutRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight);
+ void clipPath(const Path&, WindRule);
+ void clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias = true);
+ void clipToImageBuffer(ImageBuffer*, const FloatRect&);
+
+ TextDrawingModeFlags textDrawingMode() const;
+ void setTextDrawingMode(TextDrawingModeFlags);
+
+ void drawText(const Font&, const TextRun&, const IntPoint&, int from = 0, int to = -1);
+ void drawEmphasisMarks(const Font&, const TextRun& , const AtomicString& mark, const IntPoint&, int from = 0, int to = -1);
+ void drawBidiText(const Font&, const TextRun&, const FloatPoint&);
+ void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, ColorSpace, int from = 0, int to = -1);
+
+ FloatRect roundToDevicePixels(const FloatRect&);
+
+ void drawLineForText(const IntPoint&, int width, bool printing);
+ enum TextCheckingLineStyle {
+ TextCheckingSpellingLineStyle,
+ TextCheckingGrammarLineStyle,
+ TextCheckingReplacementLineStyle
+ };
+ void drawLineForTextChecking(const IntPoint&, int width, TextCheckingLineStyle);
+
+ bool paintingDisabled() const;
+ void setPaintingDisabled(bool);
+
+ bool updatingControlTints() const;
+ void setUpdatingControlTints(bool);
+
+ void beginTransparencyLayer(float opacity);
+ void endTransparencyLayer();
+
+ bool hasShadow() const;
+ void setShadow(const FloatSize&, float blur, const Color&, ColorSpace);
+ bool getShadow(FloatSize&, float&, Color&, ColorSpace&) const;
+ void clearShadow();
+
+ void drawFocusRing(const Vector<IntRect>&, int width, int offset, const Color&);
+ void drawFocusRing(const Path&, int width, int offset, const Color&);
+
+ void setLineCap(LineCap);
+ void setLineDash(const DashArray&, float dashOffset);
+ void setLineJoin(LineJoin);
+ void setMiterLimit(float);
+
+ void setAlpha(float);
+#if PLATFORM(CAIRO)
+ float getAlpha();
+#endif
+
+ void setCompositeOperation(CompositeOperator);
+ CompositeOperator compositeOperation() const;
+
+#if PLATFORM(SKIA)
+ void beginPath();
+ void addPath(const Path&);
+#endif
+
+ void clip(const Path&);
+
+ // This clip function is used only by <canvas> code. It allows
+ // implementations to handle clipping on the canvas differently since
+ // the disipline is different.
+ void canvasClip(const Path&);
+ void clipOut(const Path&);
+
+ void scale(const FloatSize&);
+ void rotate(float angleInRadians);
+ void translate(const FloatSize& size) { translate(size.width(), size.height()); }
+ void translate(float x, float y);
+
+ void setURLForRect(const KURL&, const IntRect&);
+
+ void concatCTM(const AffineTransform&);
+ AffineTransform getCTM() const;
+
+#if OS(WINCE) && !PLATFORM(QT)
+ void setBitmap(PassRefPtr<SharedBitmap>);
+ const AffineTransform& affineTransform() const;
+ AffineTransform& affineTransform();
+ void resetAffineTransform();
+ void fillRect(const FloatRect&, const Gradient*);
+ void drawText(const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point);
+ void drawFrameControl(const IntRect& rect, unsigned type, unsigned state);
+ void drawFocusRect(const IntRect& rect);
+ void paintTextField(const IntRect& rect, unsigned state);
+ void drawBitmap(SharedBitmap*, const IntRect& dstRect, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp);
+ void drawBitmapPattern(SharedBitmap*, const FloatRect& tileRectIn, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize);
+ void drawIcon(HICON icon, const IntRect& dstRect, UINT flags);
+ HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = false, bool mayCreateBitmap = true); // The passed in rect is used to create a bitmap for compositing inside transparency layers.
+ void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = false, bool mayCreateBitmap = true); // The passed in HDC should be the one handed back by getWindowsContext.
+ void drawRoundCorner(bool newClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height);
+#elif PLATFORM(WIN)
+ GraphicsContext(HDC, bool hasAlpha = false); // FIXME: To be removed.
+ bool inTransparencyLayer() const;
+ HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); // The passed in rect is used to create a bitmap for compositing inside transparency layers.
+ void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); // The passed in HDC should be the one handed back by getWindowsContext.
+
+ // When set to true, child windows should be rendered into this context
+ // rather than allowing them just to render to the screen. Defaults to
+ // false.
+ // FIXME: This is a layering violation. GraphicsContext shouldn't know
+ // what a "window" is. It would be much more appropriate for this flag
+ // to be passed as a parameter alongside the GraphicsContext, but doing
+ // that would require lots of changes in cross-platform code that we
+ // aren't sure we want to make.
+ void setShouldIncludeChildWindows(bool);
+ bool shouldIncludeChildWindows() const;
+
+ class WindowsBitmap : public Noncopyable {
+ public:
+ WindowsBitmap(HDC, IntSize);
+ ~WindowsBitmap();
+
+ HDC hdc() const { return m_hdc; }
+ UInt8* buffer() const { return m_bitmapBuffer; }
+ unsigned bufferLength() const { return m_bitmapBufferLength; }
+ IntSize size() const { return m_size; }
+ unsigned bytesPerRow() const { return m_bytesPerRow; }
+
+ private:
+ HDC m_hdc;
+ HBITMAP m_bitmap;
+ UInt8* m_bitmapBuffer;
+ unsigned m_bitmapBufferLength;
+ IntSize m_size;
+ unsigned m_bytesPerRow;
+ };
+
+ WindowsBitmap* createWindowsBitmap(IntSize);
+ // The bitmap should be non-premultiplied.
+ void drawWindowsBitmap(WindowsBitmap*, const IntPoint&);
+#endif
+
+#if (PLATFORM(QT) && defined(Q_WS_WIN)) || (PLATFORM(WX) && OS(WINDOWS))
+ HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true);
+ void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true);
+ bool shouldIncludeChildWindows() const { return false; }
+#endif
+
+#if PLATFORM(WX)
+ bool inTransparencyLayer() const { return false; }
+#endif
+
+#if PLATFORM(QT)
+ bool inTransparencyLayer() const;
+ void pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask);
+ void takeOwnershipOfPlatformContext();
+ static QPainter::CompositionMode toQtCompositionMode(CompositeOperator op);
+#endif
+
+#if PLATFORM(QT) || PLATFORM(CAIRO)
+ ContextShadow* contextShadow();
+#endif
+
+#if PLATFORM(GTK)
+ void setGdkExposeEvent(GdkEventExpose*);
+ GdkWindow* gdkWindow() const;
+ GdkEventExpose* gdkExposeEvent() const;
+#endif
+
+#if PLATFORM(HAIKU)
+ pattern getHaikuStrokeStyle();
+#endif
+
+ void setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&);
+ void syncSoftwareCanvas();
+ void markDirtyRect(const IntRect&); // Hints that a portion of the backing store is dirty.
+
+ private:
+ void platformInit(PlatformGraphicsContext*);
+ void platformDestroy();
+
+#if PLATFORM(WIN) && !OS(WINCE)
+ void platformInit(HDC, bool hasAlpha = false);
+#endif
+
+ void savePlatformState();
+ void restorePlatformState();
+
+ void setPlatformTextDrawingMode(TextDrawingModeFlags);
+ void setPlatformFont(const Font& font);
+
+ void setPlatformStrokeColor(const Color&, ColorSpace);
+ void setPlatformStrokeStyle(StrokeStyle);
+ void setPlatformStrokeThickness(float);
+ void setPlatformStrokeGradient(Gradient*);
+ void setPlatformStrokePattern(Pattern*);
+
+ void setPlatformFillColor(const Color&, ColorSpace);
+ void setPlatformFillGradient(Gradient*);
+ void setPlatformFillPattern(Pattern*);
+
+ void setPlatformShouldAntialias(bool);
+ void setPlatformShouldSmoothFonts(bool);
+
+ void setPlatformShadow(const FloatSize&, float blur, const Color&, ColorSpace);
+ void clearPlatformShadow();
+
+ void setPlatformCompositeOperation(CompositeOperator);
+
+ static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle);
+
+ GraphicsContextPlatformPrivate* m_data;
+
+ GraphicsContextState m_state;
+ Vector<GraphicsContextState> m_stack;
+ bool m_updatingControlTints;
+ };
+
+} // namespace WebCore
+
+#endif // GraphicsContext_h
diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.cpp b/Source/WebCore/platform/graphics/GraphicsContext3D.cpp
new file mode 100644
index 0000000..1224bce
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GraphicsContext3D.cpp
@@ -0,0 +1,1454 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#include "ArrayBufferView.h"
+#include "CheckedInt.h"
+#include "DrawingBuffer.h"
+#include "Image.h"
+#include "ImageData.h"
+
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/PassOwnArrayPtr.h>
+
+namespace WebCore {
+
+namespace {
+
+ unsigned int bytesPerComponent(GC3Denum type)
+ {
+ switch (type) {
+ case GraphicsContext3D::UNSIGNED_BYTE:
+ return 1;
+ case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
+ case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
+ case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
+ return 2;
+ case GraphicsContext3D::FLOAT:
+ return 4;
+ default:
+ return 1;
+ }
+ }
+
+ unsigned int componentsPerPixel(GC3Denum format, GC3Denum type)
+ {
+ switch (type) {
+ case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
+ case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
+ case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
+ case GraphicsContext3D::FLOAT:
+ return 1;
+ default:
+ break;
+ }
+ switch (format) {
+ case GraphicsContext3D::ALPHA:
+ case GraphicsContext3D::LUMINANCE:
+ return 1;
+ case GraphicsContext3D::LUMINANCE_ALPHA:
+ return 2;
+ case GraphicsContext3D::RGB:
+ return 3;
+ case GraphicsContext3D::RGBA:
+ return 4;
+ default:
+ return 4;
+ }
+ }
+
+ // This function should only be called if width and height is non-zero and
+ // format/type are valid. Return 0 if overflow happens.
+ unsigned int imageSizeInBytes(GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type)
+ {
+ ASSERT(width > 0 && height > 0);
+ CheckedInt<uint32_t> checkedWidth(width);
+ CheckedInt<uint32_t> checkedHeight(height);
+ CheckedInt<uint32_t> checkedBytesPerPixel(bytesPerComponent(type) * componentsPerPixel(format, type));
+ CheckedInt<uint32_t> checkedSize = checkedWidth * checkedHeight * checkedBytesPerPixel;
+ if (checkedSize.valid())
+ return checkedSize.value();
+ return 0;
+ }
+
+ uint8_t convertColor16LittleTo8(uint16_t value)
+ {
+ return value >> 8;
+ }
+
+ uint8_t convertColor16BigTo8(uint16_t value)
+ {
+ return static_cast<uint8_t>(value & 0x00FF);
+ }
+
+} // anonymous namespace
+
+
+PassRefPtr<DrawingBuffer> GraphicsContext3D::createDrawingBuffer(const IntSize& size)
+{
+ return DrawingBuffer::create(this, size);
+}
+
+bool GraphicsContext3D::texImage2DResourceSafe(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type)
+{
+ OwnArrayPtr<unsigned char> zero;
+ if (width > 0 && height > 0) {
+ unsigned int size = imageSizeInBytes(width, height, format, type);
+ if (!size) {
+ synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return false;
+ }
+ zero = adoptArrayPtr(new unsigned char[size]);
+ if (!zero.get()) {
+ synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return false;
+ }
+ memset(zero.get(), 0, size);
+ }
+ return texImage2D(target, level, internalformat, width, height, border, format, type, zero.get());
+}
+
+bool GraphicsContext3D::computeFormatAndTypeParameters(GC3Denum format,
+ GC3Denum type,
+ unsigned int* componentsPerPixel,
+ unsigned int* bytesPerComponent)
+{
+ switch (format) {
+ case GraphicsContext3D::ALPHA:
+ *componentsPerPixel = 1;
+ break;
+ case GraphicsContext3D::LUMINANCE:
+ *componentsPerPixel = 1;
+ break;
+ case GraphicsContext3D::LUMINANCE_ALPHA:
+ *componentsPerPixel = 2;
+ break;
+ case GraphicsContext3D::RGB:
+ *componentsPerPixel = 3;
+ break;
+ case GraphicsContext3D::RGBA:
+ *componentsPerPixel = 4;
+ break;
+ default:
+ return false;
+ }
+ switch (type) {
+ case GraphicsContext3D::UNSIGNED_BYTE:
+ *bytesPerComponent = sizeof(unsigned char);
+ break;
+ case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
+ case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
+ case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
+ *componentsPerPixel = 1;
+ *bytesPerComponent = sizeof(unsigned short);
+ break;
+ case GraphicsContext3D::FLOAT: // OES_texture_float
+ *bytesPerComponent = sizeof(float);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool GraphicsContext3D::extractImageData(Image* image,
+ GC3Denum format,
+ GC3Denum type,
+ bool flipY,
+ bool premultiplyAlpha,
+ bool ignoreGammaAndColorProfile,
+ Vector<uint8_t>& data)
+{
+ if (!image)
+ return false;
+ if (!getImageData(image, format, type, premultiplyAlpha, ignoreGammaAndColorProfile, data))
+ return false;
+ if (flipY) {
+ unsigned int componentsPerPixel, bytesPerComponent;
+ if (!computeFormatAndTypeParameters(format, type,
+ &componentsPerPixel,
+ &bytesPerComponent))
+ return false;
+ // The image data is tightly packed, and we upload it as such.
+ unsigned int unpackAlignment = 1;
+ flipVertically(data.data(), image->width(), image->height(),
+ componentsPerPixel * bytesPerComponent,
+ unpackAlignment);
+ }
+ return true;
+}
+
+bool GraphicsContext3D::extractImageData(ImageData* imageData,
+ GC3Denum format,
+ GC3Denum type,
+ bool flipY,
+ bool premultiplyAlpha,
+ Vector<uint8_t>& data)
+{
+ if (!imageData)
+ return false;
+ int width = imageData->width();
+ int height = imageData->height();
+ int dataBytes = width * height * 4;
+ data.resize(dataBytes);
+ if (!packPixels(imageData->data()->data()->data(),
+ SourceFormatRGBA8,
+ width,
+ height,
+ 0,
+ format,
+ type,
+ premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing,
+ data.data()))
+ return false;
+ if (flipY) {
+ unsigned int componentsPerPixel, bytesPerComponent;
+ if (!computeFormatAndTypeParameters(format, type,
+ &componentsPerPixel,
+ &bytesPerComponent))
+ return false;
+ // The image data is tightly packed, and we upload it as such.
+ unsigned int unpackAlignment = 1;
+ flipVertically(data.data(), width, height,
+ componentsPerPixel * bytesPerComponent,
+ unpackAlignment);
+ }
+ return true;
+}
+
+bool GraphicsContext3D::extractTextureData(unsigned int width, unsigned int height,
+ GC3Denum format, GC3Denum type,
+ unsigned int unpackAlignment,
+ bool flipY, bool premultiplyAlpha,
+ const void* pixels,
+ Vector<uint8_t>& data)
+{
+ // Assumes format, type, etc. have already been validated.
+ SourceDataFormat sourceDataFormat = SourceFormatRGBA8;
+ switch (type) {
+ case UNSIGNED_BYTE:
+ switch (format) {
+ case RGBA:
+ sourceDataFormat = SourceFormatRGBA8;
+ break;
+ case RGB:
+ sourceDataFormat = SourceFormatRGB8;
+ break;
+ case ALPHA:
+ sourceDataFormat = SourceFormatA8;
+ break;
+ case LUMINANCE:
+ sourceDataFormat = SourceFormatR8;
+ break;
+ case LUMINANCE_ALPHA:
+ sourceDataFormat = SourceFormatRA8;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ break;
+ case FLOAT: // OES_texture_float
+ switch (format) {
+ case RGBA:
+ sourceDataFormat = SourceFormatRGBA32F;
+ break;
+ case RGB:
+ sourceDataFormat = SourceFormatRGB32F;
+ break;
+ case ALPHA:
+ sourceDataFormat = SourceFormatA32F;
+ break;
+ case LUMINANCE:
+ sourceDataFormat = SourceFormatR32F;
+ break;
+ case LUMINANCE_ALPHA:
+ sourceDataFormat = SourceFormatRA32F;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ break;
+ case UNSIGNED_SHORT_5_5_5_1:
+ sourceDataFormat = SourceFormatRGBA5551;
+ break;
+ case UNSIGNED_SHORT_4_4_4_4:
+ sourceDataFormat = SourceFormatRGBA4444;
+ break;
+ case UNSIGNED_SHORT_5_6_5:
+ sourceDataFormat = SourceFormatRGB565;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ // Resize the output buffer.
+ unsigned int componentsPerPixel, bytesPerComponent;
+ if (!computeFormatAndTypeParameters(format, type,
+ &componentsPerPixel,
+ &bytesPerComponent))
+ return false;
+ unsigned int bytesPerPixel = componentsPerPixel * bytesPerComponent;
+ data.resize(width * height * bytesPerPixel);
+
+ if (!packPixels(static_cast<const uint8_t*>(pixels),
+ sourceDataFormat,
+ width, height, unpackAlignment,
+ format, type,
+ (premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing),
+ data.data()))
+ return false;
+ // The pixel data is now tightly packed.
+ if (flipY)
+ flipVertically(data.data(), width, height, bytesPerPixel, 1);
+ return true;
+}
+
+void GraphicsContext3D::flipVertically(void* imageData,
+ unsigned int width,
+ unsigned int height,
+ unsigned int bytesPerPixel,
+ unsigned int unpackAlignment)
+{
+ if (!width || !height)
+ return;
+ unsigned int validRowBytes = width * bytesPerPixel;
+ unsigned int totalRowBytes = validRowBytes;
+ unsigned int remainder = validRowBytes % unpackAlignment;
+ if (remainder)
+ totalRowBytes += (unpackAlignment - remainder);
+ uint8_t* tempRow = new uint8_t[validRowBytes];
+ uint8_t* data = static_cast<uint8_t*>(imageData);
+ for (unsigned i = 0; i < height / 2; i++) {
+ uint8_t* lowRow = data + (totalRowBytes * i);
+ uint8_t* highRow = data + (totalRowBytes * (height - i - 1));
+ memcpy(tempRow, lowRow, validRowBytes);
+ memcpy(lowRow, highRow, validRowBytes);
+ memcpy(highRow, tempRow, validRowBytes);
+ }
+ delete[] tempRow;
+}
+
+// These functions can not be static, or gcc will not allow them to be
+// used as template parameters. Use an anonymous namespace to prevent
+// the need to declare prototypes for them.
+namespace {
+
+//----------------------------------------------------------------------
+// Pixel unpacking routines.
+
+void unpackRGBA8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[1];
+ destination[2] = source[2];
+ destination[3] = source[3];
+}
+
+void unpackRGBA16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16LittleTo8(source[0]);
+ destination[1] = convertColor16LittleTo8(source[1]);
+ destination[2] = convertColor16LittleTo8(source[2]);
+ destination[3] = convertColor16LittleTo8(source[3]);
+}
+
+void unpackRGBA16BigToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16BigTo8(source[0]);
+ destination[1] = convertColor16BigTo8(source[1]);
+ destination[2] = convertColor16BigTo8(source[2]);
+ destination[3] = convertColor16BigTo8(source[3]);
+}
+
+void unpackRGB8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[1];
+ destination[2] = source[2];
+ destination[3] = 0xFF;
+}
+
+void unpackRGB16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16LittleTo8(source[0]);
+ destination[1] = convertColor16LittleTo8(source[1]);
+ destination[2] = convertColor16LittleTo8(source[2]);
+ destination[3] = 0xFF;
+}
+
+void unpackRGB16BigToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16BigTo8(source[0]);
+ destination[1] = convertColor16BigTo8(source[1]);
+ destination[2] = convertColor16BigTo8(source[2]);
+ destination[3] = 0xFF;
+}
+
+void unpackBGR8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[2];
+ destination[1] = source[1];
+ destination[2] = source[0];
+ destination[3] = 0xFF;
+}
+
+void unpackARGB8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[1];
+ destination[1] = source[2];
+ destination[2] = source[3];
+ destination[3] = source[0];
+}
+
+void unpackARGB16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16LittleTo8(source[1]);
+ destination[1] = convertColor16LittleTo8(source[2]);
+ destination[2] = convertColor16LittleTo8(source[3]);
+ destination[3] = convertColor16LittleTo8(source[0]);
+}
+
+void unpackARGB16BigToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16BigTo8(source[1]);
+ destination[1] = convertColor16BigTo8(source[2]);
+ destination[2] = convertColor16BigTo8(source[3]);
+ destination[3] = convertColor16BigTo8(source[0]);
+}
+
+void unpackABGR8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[3];
+ destination[1] = source[2];
+ destination[2] = source[1];
+ destination[3] = source[0];
+}
+
+void unpackBGRA8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[2];
+ destination[1] = source[1];
+ destination[2] = source[0];
+ destination[3] = source[3];
+}
+
+void unpackBGRA16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16LittleTo8(source[2]);
+ destination[1] = convertColor16LittleTo8(source[1]);
+ destination[2] = convertColor16LittleTo8(source[0]);
+ destination[3] = convertColor16LittleTo8(source[3]);
+}
+
+void unpackBGRA16BigToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16BigTo8(source[2]);
+ destination[1] = convertColor16BigTo8(source[1]);
+ destination[2] = convertColor16BigTo8(source[0]);
+ destination[3] = convertColor16BigTo8(source[3]);
+}
+
+void unpackRGBA5551ToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ uint16_t packedValue = source[0];
+ uint8_t r = packedValue >> 11;
+ uint8_t g = (packedValue >> 6) & 0x1F;
+ uint8_t b = (packedValue >> 1) & 0x1F;
+ destination[0] = (r << 3) | (r & 0x7);
+ destination[1] = (g << 3) | (g & 0x7);
+ destination[2] = (b << 3) | (b & 0x7);
+ destination[3] = (packedValue & 0x1) ? 0xFF : 0x0;
+}
+
+void unpackRGBA4444ToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ uint16_t packedValue = source[0];
+ uint8_t r = packedValue >> 12;
+ uint8_t g = (packedValue >> 8) & 0x0F;
+ uint8_t b = (packedValue >> 4) & 0x0F;
+ uint8_t a = packedValue & 0x0F;
+ destination[0] = r << 4 | r;
+ destination[1] = g << 4 | g;
+ destination[2] = b << 4 | b;
+ destination[3] = a << 4 | a;
+}
+
+void unpackRGB565ToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ uint16_t packedValue = source[0];
+ uint8_t r = packedValue >> 11;
+ uint8_t g = (packedValue >> 5) & 0x3F;
+ uint8_t b = packedValue & 0x1F;
+ destination[0] = (r << 3) | (r & 0x7);
+ destination[1] = (g << 2) | (g & 0x3);
+ destination[2] = (b << 3) | (b & 0x7);
+ destination[3] = 0xFF;
+}
+
+void unpackR8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[0];
+ destination[2] = source[0];
+ destination[3] = 0xFF;
+}
+
+void unpackR16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16LittleTo8(source[0]);
+ destination[1] = convertColor16LittleTo8(source[0]);
+ destination[2] = convertColor16LittleTo8(source[0]);
+ destination[3] = 0xFF;
+}
+
+void unpackR16BigToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16BigTo8(source[0]);
+ destination[1] = convertColor16BigTo8(source[0]);
+ destination[2] = convertColor16BigTo8(source[0]);
+ destination[3] = 0xFF;
+}
+
+void unpackRA8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[0];
+ destination[2] = source[0];
+ destination[3] = source[1];
+}
+
+void unpackRA16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16LittleTo8(source[0]);
+ destination[1] = convertColor16LittleTo8(source[0]);
+ destination[2] = convertColor16LittleTo8(source[0]);
+ destination[3] = convertColor16LittleTo8(source[1]);
+}
+
+void unpackRA16BigToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16BigTo8(source[0]);
+ destination[1] = convertColor16BigTo8(source[0]);
+ destination[2] = convertColor16BigTo8(source[0]);
+ destination[3] = convertColor16BigTo8(source[1]);
+}
+
+void unpackAR8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[1];
+ destination[1] = source[1];
+ destination[2] = source[1];
+ destination[3] = source[0];
+}
+
+void unpackAR16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16LittleTo8(source[1]);
+ destination[1] = convertColor16LittleTo8(source[1]);
+ destination[2] = convertColor16LittleTo8(source[1]);
+ destination[3] = convertColor16LittleTo8(source[0]);
+}
+
+void unpackAR16BigToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = convertColor16BigTo8(source[1]);
+ destination[1] = convertColor16BigTo8(source[1]);
+ destination[2] = convertColor16BigTo8(source[1]);
+ destination[3] = convertColor16BigTo8(source[0]);
+}
+
+void unpackA8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = 0x0;
+ destination[1] = 0x0;
+ destination[2] = 0x0;
+ destination[3] = source[0];
+}
+
+void unpackA16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = 0x0;
+ destination[1] = 0x0;
+ destination[2] = 0x0;
+ destination[3] = convertColor16LittleTo8(source[0]);
+}
+
+void unpackA16BigToRGBA8(const uint16_t* source, uint8_t* destination)
+{
+ destination[0] = 0x0;
+ destination[1] = 0x0;
+ destination[2] = 0x0;
+ destination[3] = convertColor16BigTo8(source[0]);
+}
+
+void unpackRGB32FToRGBA32F(const float* source, float* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[1];
+ destination[2] = source[2];
+ destination[3] = 1;
+}
+
+void unpackR32FToRGBA32F(const float* source, float* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[0];
+ destination[2] = source[0];
+ destination[3] = 1;
+}
+
+void unpackRA32FToRGBA32F(const float* source, float* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[0];
+ destination[2] = source[0];
+ destination[3] = source[1];
+}
+
+void unpackA32FToRGBA32F(const float* source, float* destination)
+{
+ destination[0] = 0;
+ destination[1] = 0;
+ destination[2] = 0;
+ destination[3] = source[0];
+}
+
+//----------------------------------------------------------------------
+// Pixel packing routines.
+//
+
+void packRGBA8ToA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[3];
+}
+
+void packRGBA8ToR8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[0];
+}
+
+void packRGBA8ToR8Premultiply(const uint8_t* source, uint8_t* destination)
+{
+ float scaleFactor = source[3] / 255.0f;
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ destination[0] = sourceR;
+}
+
+// FIXME: this routine is lossy and must be removed.
+void packRGBA8ToR8Unmultiply(const uint8_t* source, uint8_t* destination)
+{
+ float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 1.0f);
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ destination[0] = sourceR;
+}
+
+void packRGBA8ToRA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[3];
+}
+
+void packRGBA8ToRA8Premultiply(const uint8_t* source, uint8_t* destination)
+{
+ float scaleFactor = source[3] / 255.0f;
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ destination[0] = sourceR;
+ destination[1] = source[3];
+}
+
+// FIXME: this routine is lossy and must be removed.
+void packRGBA8ToRA8Unmultiply(const uint8_t* source, uint8_t* destination)
+{
+ float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 1.0f);
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ destination[0] = sourceR;
+ destination[1] = source[3];
+}
+
+void packRGBA8ToRGB8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[1];
+ destination[2] = source[2];
+}
+
+void packRGBA8ToRGB8Premultiply(const uint8_t* source, uint8_t* destination)
+{
+ float scaleFactor = source[3] / 255.0f;
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ destination[0] = sourceR;
+ destination[1] = sourceG;
+ destination[2] = sourceB;
+}
+
+// FIXME: this routine is lossy and must be removed.
+void packRGBA8ToRGB8Unmultiply(const uint8_t* source, uint8_t* destination)
+{
+ float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 1.0f);
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ destination[0] = sourceR;
+ destination[1] = sourceG;
+ destination[2] = sourceB;
+}
+
+// This is only used when the source format is different than SourceFormatRGBA8.
+void packRGBA8ToRGBA8(const uint8_t* source, uint8_t* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[1];
+ destination[2] = source[2];
+ destination[3] = source[3];
+}
+
+void packRGBA8ToRGBA8Premultiply(const uint8_t* source, uint8_t* destination)
+{
+ float scaleFactor = source[3] / 255.0f;
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ destination[0] = sourceR;
+ destination[1] = sourceG;
+ destination[2] = sourceB;
+ destination[3] = source[3];
+}
+
+// FIXME: this routine is lossy and must be removed.
+void packRGBA8ToRGBA8Unmultiply(const uint8_t* source, uint8_t* destination)
+{
+ float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 1.0f);
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ destination[0] = sourceR;
+ destination[1] = sourceG;
+ destination[2] = sourceB;
+ destination[3] = source[3];
+}
+
+void packRGBA8ToUnsignedShort4444(const uint8_t* source, uint16_t* destination)
+{
+ *destination = (((source[0] & 0xF0) << 8)
+ | ((source[1] & 0xF0) << 4)
+ | (source[2] & 0xF0)
+ | (source[3] >> 4));
+}
+
+void packRGBA8ToUnsignedShort4444Premultiply(const uint8_t* source, uint16_t* destination)
+{
+ float scaleFactor = source[3] / 255.0f;
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ *destination = (((sourceR & 0xF0) << 8)
+ | ((sourceG & 0xF0) << 4)
+ | (sourceB & 0xF0)
+ | (source[3] >> 4));
+}
+
+// FIXME: this routine is lossy and must be removed.
+void packRGBA8ToUnsignedShort4444Unmultiply(const uint8_t* source, uint16_t* destination)
+{
+ float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 1.0f);
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ *destination = (((sourceR & 0xF0) << 8)
+ | ((sourceG & 0xF0) << 4)
+ | (sourceB & 0xF0)
+ | (source[3] >> 4));
+}
+
+void packRGBA8ToUnsignedShort5551(const uint8_t* source, uint16_t* destination)
+{
+ *destination = (((source[0] & 0xF8) << 8)
+ | ((source[1] & 0xF8) << 3)
+ | ((source[2] & 0xF8) >> 2)
+ | (source[3] >> 7));
+}
+
+void packRGBA8ToUnsignedShort5551Premultiply(const uint8_t* source, uint16_t* destination)
+{
+ float scaleFactor = source[3] / 255.0f;
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ *destination = (((sourceR & 0xF8) << 8)
+ | ((sourceG & 0xF8) << 3)
+ | ((sourceB & 0xF8) >> 2)
+ | (source[3] >> 7));
+}
+
+// FIXME: this routine is lossy and must be removed.
+void packRGBA8ToUnsignedShort5551Unmultiply(const uint8_t* source, uint16_t* destination)
+{
+ float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 1.0f);
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ *destination = (((sourceR & 0xF8) << 8)
+ | ((sourceG & 0xF8) << 3)
+ | ((sourceB & 0xF8) >> 2)
+ | (source[3] >> 7));
+}
+
+void packRGBA8ToUnsignedShort565(const uint8_t* source, uint16_t* destination)
+{
+ *destination = (((source[0] & 0xF8) << 8)
+ | ((source[1] & 0xFC) << 3)
+ | ((source[2] & 0xF8) >> 3));
+}
+
+void packRGBA8ToUnsignedShort565Premultiply(const uint8_t* source, uint16_t* destination)
+{
+ float scaleFactor = source[3] / 255.0f;
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ *destination = (((sourceR & 0xF8) << 8)
+ | ((sourceG & 0xFC) << 3)
+ | ((sourceB & 0xF8) >> 3));
+}
+
+// FIXME: this routine is lossy and must be removed.
+void packRGBA8ToUnsignedShort565Unmultiply(const uint8_t* source, uint16_t* destination)
+{
+ float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 1.0f);
+ uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
+ uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
+ uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
+ *destination = (((sourceR & 0xF8) << 8)
+ | ((sourceG & 0xFC) << 3)
+ | ((sourceB & 0xF8) >> 3));
+}
+
+void packRGBA32FToRGB32F(const float* source, float* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[1];
+ destination[2] = source[2];
+}
+
+void packRGBA32FToRGB32FPremultiply(const float* source, float* destination)
+{
+ float scaleFactor = source[3];
+ destination[0] = source[0] * scaleFactor;
+ destination[1] = source[1] * scaleFactor;
+ destination[2] = source[2] * scaleFactor;
+}
+
+void packRGBA32FToRGBA32FPremultiply(const float* source, float* destination)
+{
+ float scaleFactor = source[3];
+ destination[0] = source[0] * scaleFactor;
+ destination[1] = source[1] * scaleFactor;
+ destination[2] = source[2] * scaleFactor;
+ destination[3] = source[3];
+}
+
+void packRGBA32FToA32F(const float* source, float* destination)
+{
+ destination[0] = source[3];
+}
+
+void packRGBA32FToR32F(const float* source, float* destination)
+{
+ destination[0] = source[0];
+}
+
+void packRGBA32FToR32FPremultiply(const float* source, float* destination)
+{
+ float scaleFactor = source[3];
+ destination[0] = source[0] * scaleFactor;
+}
+
+
+void packRGBA32FToRA32F(const float* source, float* destination)
+{
+ destination[0] = source[0];
+ destination[1] = source[3];
+}
+
+void packRGBA32FToRA32FPremultiply(const float* source, float* destination)
+{
+ float scaleFactor = source[3];
+ destination[0] = source[0] * scaleFactor;
+ destination[1] = scaleFactor;
+}
+
+} // anonymous namespace
+
+// This is used whenever unpacking is necessary; i.e., the source data
+// is not in RGBA8/RGBA32F format, or the unpack alignment specifies
+// that rows are not tightly packed.
+template<typename SourceType, typename IntermediateType, typename DestType,
+ void unpackingFunc(const SourceType*, IntermediateType*),
+ void packingFunc(const IntermediateType*, DestType*)>
+static void doUnpackingAndPacking(const SourceType* sourceData,
+ unsigned int width,
+ unsigned int height,
+ unsigned int sourceElementsPerPixel,
+ unsigned int sourceElementsPerRow,
+ DestType* destinationData,
+ unsigned int destinationElementsPerPixel)
+{
+ if (!sourceElementsPerRow) {
+ unsigned int numElements = width * height * sourceElementsPerPixel;
+ const SourceType* endPointer = sourceData + numElements;
+ IntermediateType temporaryRGBAData[4];
+ while (sourceData < endPointer) {
+ unpackingFunc(sourceData, temporaryRGBAData);
+ packingFunc(temporaryRGBAData, destinationData);
+ sourceData += sourceElementsPerPixel;
+ destinationData += destinationElementsPerPixel;
+ }
+ } else {
+ IntermediateType temporaryRGBAData[4];
+ for (unsigned int y = 0; y < height; ++y) {
+ const SourceType* currentSource = sourceData;
+ for (unsigned int x = 0; x < width; ++x) {
+ unpackingFunc(currentSource, temporaryRGBAData);
+ packingFunc(temporaryRGBAData, destinationData);
+ currentSource += sourceElementsPerPixel;
+ destinationData += destinationElementsPerPixel;
+ }
+ sourceData += sourceElementsPerRow;
+ }
+ }
+}
+
+template<typename SourceType>
+static void computeIncrementParameters(unsigned int width,
+ unsigned int bytesPerPixel,
+ unsigned int unpackAlignment,
+ unsigned int* sourceElementsPerPixel,
+ unsigned int* sourceElementsPerRow)
+{
+ unsigned int elementSizeInBytes = sizeof(SourceType);
+ ASSERT(elementSizeInBytes <= bytesPerPixel);
+ ASSERT(!(bytesPerPixel % elementSizeInBytes));
+ unsigned int validRowBytes = width * bytesPerPixel;
+ unsigned int totalRowBytes = validRowBytes;
+ if (unpackAlignment) {
+ unsigned int remainder = validRowBytes % unpackAlignment;
+ if (remainder)
+ totalRowBytes += (unpackAlignment - remainder);
+ }
+ *sourceElementsPerPixel = bytesPerPixel / elementSizeInBytes;
+ if (validRowBytes == totalRowBytes)
+ *sourceElementsPerRow = 0;
+ else
+ *sourceElementsPerRow = totalRowBytes / elementSizeInBytes;
+}
+
+// This handles all conversions with a faster path for tightly packed RGBA8 source data.
+template<typename DestType, void packingFunc(const uint8_t*, DestType*)>
+static void doPacking(const void* sourceData,
+ GraphicsContext3D::SourceDataFormat sourceDataFormat,
+ unsigned int width,
+ unsigned int height,
+ unsigned int sourceUnpackAlignment,
+ DestType* destinationData,
+ unsigned int destinationElementsPerPixel)
+{
+ switch (sourceDataFormat) {
+ case GraphicsContext3D::SourceFormatRGBA8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ if (!sourceElementsPerRow) {
+ const uint8_t* source = static_cast<const uint8_t*>(sourceData);
+ unsigned int numElements = width * height * 4;
+ const uint8_t* endPointer = source + numElements;
+ while (source < endPointer) {
+ packingFunc(source, destinationData);
+ source += sourceElementsPerPixel;
+ destinationData += destinationElementsPerPixel;
+ }
+ } else {
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackRGBA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ }
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRGBA16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRGBA16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRGB8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackRGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRGB16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRGB16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatBGR8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackBGR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatARGB8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackARGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatARGB16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackARGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatARGB16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackARGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatABGR8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackABGR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatBGRA8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackBGRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatBGRA16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackBGRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatBGRA16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackBGRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRGBA5551: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA5551ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRGBA4444: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA4444ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRGB565: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGB565ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatR8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatR16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatR16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRA8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRA16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRA16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatAR8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackAR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatAR16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackAR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatAR16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackAR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatA8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint8_t>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatA16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatA16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ default:
+ ASSERT(false);
+ }
+}
+
+// This specialized routine is used only for floating-point texture uploads. It
+// does not need to be as general as doPacking, above; because there are
+// currently no native floating-point image formats in WebKit, there are only a
+// few upload paths.
+template<void packingFunc(const float*, float*)>
+static void doFloatingPointPacking(const void* sourceData,
+ GraphicsContext3D::SourceDataFormat sourceDataFormat,
+ unsigned int width,
+ unsigned int height,
+ unsigned int sourceUnpackAlignment,
+ float* destinationData,
+ unsigned int destinationElementsPerPixel)
+{
+ switch (sourceDataFormat) {
+ case GraphicsContext3D::SourceFormatRGBA8: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<float>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ ASSERT(!sourceElementsPerRow); // Guaranteed because each color channel is sizeof(float) bytes.
+ const float* source = static_cast<const float*>(sourceData);
+ unsigned int numElements = width * height * 4;
+ const float* endPointer = source + numElements;
+ while (source < endPointer) {
+ packingFunc(source, destinationData);
+ source += sourceElementsPerPixel;
+ destinationData += destinationElementsPerPixel;
+ }
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRGB32F: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<float>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<float, float, float, unpackRGB32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatR32F: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<float>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<float, float, float, unpackR32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatRA32F: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<float>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<float, float, float, unpackRA32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::SourceFormatA32F: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<float>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<float, float, float, unpackA32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+bool GraphicsContext3D::packPixels(const uint8_t* sourceData,
+ GraphicsContext3D::SourceDataFormat sourceDataFormat,
+ unsigned int width,
+ unsigned int height,
+ unsigned int sourceUnpackAlignment,
+ unsigned int destinationFormat,
+ unsigned int destinationType,
+ AlphaOp alphaOp,
+ void* destinationData)
+{
+ switch (destinationType) {
+ case UNSIGNED_BYTE: {
+ uint8_t* destination = static_cast<uint8_t*>(destinationData);
+ if (sourceDataFormat == SourceFormatRGBA8 && destinationFormat == RGBA && sourceUnpackAlignment <= 4 && alphaOp == AlphaDoNothing) {
+ // No conversion necessary.
+ memcpy(destinationData, sourceData, width * height * 4);
+ break;
+ }
+ switch (destinationFormat) {
+ case RGB:
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ doPacking<uint8_t, packRGBA8ToRGB8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
+ break;
+ case AlphaDoPremultiply:
+ doPacking<uint8_t, packRGBA8ToRGB8Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
+ break;
+ case AlphaDoUnmultiply:
+ doPacking<uint8_t, packRGBA8ToRGB8Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
+ break;
+ }
+ break;
+ case RGBA:
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ ASSERT(sourceDataFormat != SourceFormatRGBA8 || sourceUnpackAlignment > 4); // Handled above with fast case.
+ doPacking<uint8_t, packRGBA8ToRGBA8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 4);
+ break;
+ case AlphaDoPremultiply:
+ doPacking<uint8_t, packRGBA8ToRGBA8Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 4);
+ break;
+ case AlphaDoUnmultiply:
+ doPacking<uint8_t, packRGBA8ToRGBA8Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 4);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ break;
+ case ALPHA:
+ // From the desktop OpenGL conversion rules (OpenGL 2.1
+ // specification, Table 3.15), the alpha channel is chosen
+ // from the RGBA data.
+ doPacking<uint8_t, packRGBA8ToA8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case LUMINANCE:
+ // From the desktop OpenGL conversion rules (OpenGL 2.1
+ // specification, Table 3.15), the red channel is chosen
+ // from the RGBA data.
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ doPacking<uint8_t, packRGBA8ToR8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case AlphaDoPremultiply:
+ doPacking<uint8_t, packRGBA8ToR8Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case AlphaDoUnmultiply:
+ doPacking<uint8_t, packRGBA8ToR8Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ }
+ break;
+ case LUMINANCE_ALPHA:
+ // From the desktop OpenGL conversion rules (OpenGL 2.1
+ // specification, Table 3.15), the red and alpha channels
+ // are chosen from the RGBA data.
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ doPacking<uint8_t, packRGBA8ToRA8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
+ break;
+ case AlphaDoPremultiply:
+ doPacking<uint8_t, packRGBA8ToRA8Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
+ break;
+ case AlphaDoUnmultiply:
+ doPacking<uint8_t, packRGBA8ToRA8Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ case UNSIGNED_SHORT_4_4_4_4: {
+ uint16_t* destination = static_cast<uint16_t*>(destinationData);
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ doPacking<uint16_t, packRGBA8ToUnsignedShort4444>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case AlphaDoPremultiply:
+ doPacking<uint16_t, packRGBA8ToUnsignedShort4444Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case AlphaDoUnmultiply:
+ doPacking<uint16_t, packRGBA8ToUnsignedShort4444Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ }
+ break;
+ }
+ case UNSIGNED_SHORT_5_5_5_1: {
+ uint16_t* destination = static_cast<uint16_t*>(destinationData);
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ doPacking<uint16_t, packRGBA8ToUnsignedShort5551>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case AlphaDoPremultiply:
+ doPacking<uint16_t, packRGBA8ToUnsignedShort5551Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case AlphaDoUnmultiply:
+ doPacking<uint16_t, packRGBA8ToUnsignedShort5551Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ }
+ break;
+ }
+ case UNSIGNED_SHORT_5_6_5: {
+ uint16_t* destination = static_cast<uint16_t*>(destinationData);
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ doPacking<uint16_t, packRGBA8ToUnsignedShort565>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case AlphaDoPremultiply:
+ doPacking<uint16_t, packRGBA8ToUnsignedShort565Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case AlphaDoUnmultiply:
+ doPacking<uint16_t, packRGBA8ToUnsignedShort565Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ }
+ break;
+ }
+ case FLOAT: {
+ // OpenGL ES, and therefore WebGL, require that the format and
+ // internalformat be identical, which implies that the source and
+ // destination formats will both be floating-point in this branch -- at
+ // least, until WebKit supports floating-point image formats natively.
+ ASSERT(sourceDataFormat == SourceFormatRGBA32F || sourceDataFormat == SourceFormatRGB32F
+ || sourceDataFormat == SourceFormatRA32F || sourceDataFormat == SourceFormatR32F
+ || sourceDataFormat == SourceFormatA32F);
+ // Because WebKit doesn't use floating-point color channels for anything
+ // internally, there's no chance we have to do a (lossy) unmultiply
+ // operation.
+ ASSERT(alphaOp == AlphaDoNothing || alphaOp == AlphaDoPremultiply);
+ // For the source formats with an even number of channels (RGBA32F,
+ // RA32F) it is guaranteed that the pixel data is tightly packed because
+ // unpack alignment <= sizeof(float) * number of channels.
+ float* destination = static_cast<float*>(destinationData);
+ if (alphaOp == AlphaDoNothing
+ && ((sourceDataFormat == SourceFormatRGBA32F && destinationFormat == RGBA)
+ || (sourceDataFormat == SourceFormatRA32F && destinationFormat == LUMINANCE_ALPHA))) {
+ // No conversion necessary.
+ int numChannels = (sourceDataFormat == SourceFormatRGBA32F ? 4 : 2);
+ memcpy(destinationData, sourceData, width * height * numChannels * sizeof(float));
+ break;
+ }
+ switch (destinationFormat) {
+ case RGB:
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ doFloatingPointPacking<packRGBA32FToRGB32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
+ break;
+ case AlphaDoPremultiply:
+ doFloatingPointPacking<packRGBA32FToRGB32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ break;
+ case RGBA:
+ // AlphaDoNothing is handled above with fast path.
+ ASSERT(alphaOp == AlphaDoPremultiply);
+ doFloatingPointPacking<packRGBA32FToRGBA32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 4);
+ break;
+ case ALPHA:
+ // From the desktop OpenGL conversion rules (OpenGL 2.1
+ // specification, Table 3.15), the alpha channel is chosen
+ // from the RGBA data.
+ doFloatingPointPacking<packRGBA32FToA32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case LUMINANCE:
+ // From the desktop OpenGL conversion rules (OpenGL 2.1
+ // specification, Table 3.15), the red channel is chosen
+ // from the RGBA data.
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ doFloatingPointPacking<packRGBA32FToR32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ case AlphaDoPremultiply:
+ doFloatingPointPacking<packRGBA32FToR32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ break;
+ case LUMINANCE_ALPHA:
+ // From the desktop OpenGL conversion rules (OpenGL 2.1
+ // specification, Table 3.15), the red and alpha channels
+ // are chosen from the RGBA data.
+ switch (alphaOp) {
+ case AlphaDoNothing:
+ doFloatingPointPacking<packRGBA32FToRA32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
+ break;
+ case AlphaDoPremultiply:
+ doFloatingPointPacking<packRGBA32FToRA32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ break;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.h b/Source/WebCore/platform/graphics/GraphicsContext3D.h
new file mode 100644
index 0000000..a0d2778
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GraphicsContext3D.h
@@ -0,0 +1,904 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 GraphicsContext3D_h
+#define GraphicsContext3D_h
+
+#include "IntSize.h"
+#include "GraphicsLayer.h"
+#include "PlatformString.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/Noncopyable.h>
+
+// FIXME: Find a better way to avoid the name confliction for NO_ERROR.
+#if ((PLATFORM(CHROMIUM) && OS(WINDOWS)) || PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS)))
+#undef NO_ERROR
+#elif PLATFORM(GTK)
+// This define is from the X11 headers, but it's used below, so we must undefine it.
+#undef VERSION
+#endif
+
+// GC3D types match the corresponding GL types as defined in OpenGL ES 2.0
+// header file gl2.h from khronos.org.
+typedef unsigned int GC3Denum;
+typedef unsigned char GC3Dboolean;
+typedef unsigned int GC3Dbitfield;
+typedef int GC3Dint;
+typedef int GC3Dsizei;
+typedef unsigned int GC3Duint;
+typedef float GC3Dfloat;
+typedef float GC3Dclampf;
+typedef signed long int GC3Dintptr;
+typedef signed long int GC3Dsizeiptr;
+
+typedef GC3Duint Platform3DObject;
+
+#if PLATFORM(MAC)
+#include "ANGLEWebKitBridge.h"
+#include <OpenGL/OpenGL.h>
+#include <wtf/RetainPtr.h>
+#ifdef __OBJC__
+@class CALayer;
+@class WebGLLayer;
+#else
+typedef void* CALayer;
+typedef void* WebGLLayer;
+#endif
+#elif PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QPainter;
+class QRect;
+QT_END_NAMESPACE
+#elif PLATFORM(GTK)
+typedef unsigned int GLuint;
+#endif
+
+#if PLATFORM(MAC)
+typedef CGLContextObj PlatformGraphicsContext3D;
+#else
+typedef void* PlatformGraphicsContext3D;
+#endif
+
+// These are currently the same among all implementations.
+const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0;
+const Platform3DObject NullPlatform3DObject = 0;
+
+#if PLATFORM(CG)
+#include <CoreGraphics/CGContext.h>
+#endif
+
+namespace WebCore {
+class CanvasRenderingContext;
+class DrawingBuffer;
+class Extensions3D;
+#if PLATFORM(MAC)
+class Extensions3DOpenGL;
+#endif
+class HostWindow;
+class Image;
+class ImageData;
+
+struct ActiveInfo {
+ String name;
+ GC3Denum type;
+ GC3Dint size;
+};
+
+// FIXME: ideally this would be used on all platforms.
+#if PLATFORM(CHROMIUM) || PLATFORM(QT)
+class GraphicsContext3DInternal;
+#endif
+
+class GraphicsContext3D : public RefCounted<GraphicsContext3D> {
+public:
+ enum WebGLEnumType {
+ DEPTH_BUFFER_BIT = 0x00000100,
+ STENCIL_BUFFER_BIT = 0x00000400,
+ COLOR_BUFFER_BIT = 0x00004000,
+ POINTS = 0x0000,
+ LINES = 0x0001,
+ LINE_LOOP = 0x0002,
+ LINE_STRIP = 0x0003,
+ TRIANGLES = 0x0004,
+ TRIANGLE_STRIP = 0x0005,
+ TRIANGLE_FAN = 0x0006,
+ ZERO = 0,
+ ONE = 1,
+ SRC_COLOR = 0x0300,
+ ONE_MINUS_SRC_COLOR = 0x0301,
+ SRC_ALPHA = 0x0302,
+ ONE_MINUS_SRC_ALPHA = 0x0303,
+ DST_ALPHA = 0x0304,
+ ONE_MINUS_DST_ALPHA = 0x0305,
+ DST_COLOR = 0x0306,
+ ONE_MINUS_DST_COLOR = 0x0307,
+ SRC_ALPHA_SATURATE = 0x0308,
+ FUNC_ADD = 0x8006,
+ BLEND_EQUATION = 0x8009,
+ BLEND_EQUATION_RGB = 0x8009,
+ BLEND_EQUATION_ALPHA = 0x883D,
+ FUNC_SUBTRACT = 0x800A,
+ FUNC_REVERSE_SUBTRACT = 0x800B,
+ BLEND_DST_RGB = 0x80C8,
+ BLEND_SRC_RGB = 0x80C9,
+ BLEND_DST_ALPHA = 0x80CA,
+ BLEND_SRC_ALPHA = 0x80CB,
+ CONSTANT_COLOR = 0x8001,
+ ONE_MINUS_CONSTANT_COLOR = 0x8002,
+ CONSTANT_ALPHA = 0x8003,
+ ONE_MINUS_CONSTANT_ALPHA = 0x8004,
+ BLEND_COLOR = 0x8005,
+ ARRAY_BUFFER = 0x8892,
+ ELEMENT_ARRAY_BUFFER = 0x8893,
+ ARRAY_BUFFER_BINDING = 0x8894,
+ ELEMENT_ARRAY_BUFFER_BINDING = 0x8895,
+ STREAM_DRAW = 0x88E0,
+ STATIC_DRAW = 0x88E4,
+ DYNAMIC_DRAW = 0x88E8,
+ BUFFER_SIZE = 0x8764,
+ BUFFER_USAGE = 0x8765,
+ CURRENT_VERTEX_ATTRIB = 0x8626,
+ FRONT = 0x0404,
+ BACK = 0x0405,
+ FRONT_AND_BACK = 0x0408,
+ TEXTURE_2D = 0x0DE1,
+ CULL_FACE = 0x0B44,
+ BLEND = 0x0BE2,
+ DITHER = 0x0BD0,
+ STENCIL_TEST = 0x0B90,
+ DEPTH_TEST = 0x0B71,
+ SCISSOR_TEST = 0x0C11,
+ POLYGON_OFFSET_FILL = 0x8037,
+ SAMPLE_ALPHA_TO_COVERAGE = 0x809E,
+ SAMPLE_COVERAGE = 0x80A0,
+ NO_ERROR = 0,
+ INVALID_ENUM = 0x0500,
+ INVALID_VALUE = 0x0501,
+ INVALID_OPERATION = 0x0502,
+ OUT_OF_MEMORY = 0x0505,
+ CW = 0x0900,
+ CCW = 0x0901,
+ LINE_WIDTH = 0x0B21,
+ ALIASED_POINT_SIZE_RANGE = 0x846D,
+ ALIASED_LINE_WIDTH_RANGE = 0x846E,
+ CULL_FACE_MODE = 0x0B45,
+ FRONT_FACE = 0x0B46,
+ DEPTH_RANGE = 0x0B70,
+ DEPTH_WRITEMASK = 0x0B72,
+ DEPTH_CLEAR_VALUE = 0x0B73,
+ DEPTH_FUNC = 0x0B74,
+ STENCIL_CLEAR_VALUE = 0x0B91,
+ STENCIL_FUNC = 0x0B92,
+ STENCIL_FAIL = 0x0B94,
+ STENCIL_PASS_DEPTH_FAIL = 0x0B95,
+ STENCIL_PASS_DEPTH_PASS = 0x0B96,
+ STENCIL_REF = 0x0B97,
+ STENCIL_VALUE_MASK = 0x0B93,
+ STENCIL_WRITEMASK = 0x0B98,
+ STENCIL_BACK_FUNC = 0x8800,
+ STENCIL_BACK_FAIL = 0x8801,
+ STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802,
+ STENCIL_BACK_PASS_DEPTH_PASS = 0x8803,
+ STENCIL_BACK_REF = 0x8CA3,
+ STENCIL_BACK_VALUE_MASK = 0x8CA4,
+ STENCIL_BACK_WRITEMASK = 0x8CA5,
+ VIEWPORT = 0x0BA2,
+ SCISSOR_BOX = 0x0C10,
+ COLOR_CLEAR_VALUE = 0x0C22,
+ COLOR_WRITEMASK = 0x0C23,
+ UNPACK_ALIGNMENT = 0x0CF5,
+ PACK_ALIGNMENT = 0x0D05,
+ MAX_TEXTURE_SIZE = 0x0D33,
+ MAX_VIEWPORT_DIMS = 0x0D3A,
+ SUBPIXEL_BITS = 0x0D50,
+ RED_BITS = 0x0D52,
+ GREEN_BITS = 0x0D53,
+ BLUE_BITS = 0x0D54,
+ ALPHA_BITS = 0x0D55,
+ DEPTH_BITS = 0x0D56,
+ STENCIL_BITS = 0x0D57,
+ POLYGON_OFFSET_UNITS = 0x2A00,
+ POLYGON_OFFSET_FACTOR = 0x8038,
+ TEXTURE_BINDING_2D = 0x8069,
+ SAMPLE_BUFFERS = 0x80A8,
+ SAMPLES = 0x80A9,
+ SAMPLE_COVERAGE_VALUE = 0x80AA,
+ SAMPLE_COVERAGE_INVERT = 0x80AB,
+ NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2,
+ COMPRESSED_TEXTURE_FORMATS = 0x86A3,
+ DONT_CARE = 0x1100,
+ FASTEST = 0x1101,
+ NICEST = 0x1102,
+ GENERATE_MIPMAP_HINT = 0x8192,
+ BYTE = 0x1400,
+ UNSIGNED_BYTE = 0x1401,
+ SHORT = 0x1402,
+ UNSIGNED_SHORT = 0x1403,
+ INT = 0x1404,
+ UNSIGNED_INT = 0x1405,
+ FLOAT = 0x1406,
+ FIXED = 0x140C,
+ DEPTH_COMPONENT = 0x1902,
+ ALPHA = 0x1906,
+ RGB = 0x1907,
+ RGBA = 0x1908,
+ LUMINANCE = 0x1909,
+ LUMINANCE_ALPHA = 0x190A,
+ UNSIGNED_SHORT_4_4_4_4 = 0x8033,
+ UNSIGNED_SHORT_5_5_5_1 = 0x8034,
+ UNSIGNED_SHORT_5_6_5 = 0x8363,
+ FRAGMENT_SHADER = 0x8B30,
+ VERTEX_SHADER = 0x8B31,
+ MAX_VERTEX_ATTRIBS = 0x8869,
+ MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB,
+ MAX_VARYING_VECTORS = 0x8DFC,
+ MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D,
+ MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C,
+ MAX_TEXTURE_IMAGE_UNITS = 0x8872,
+ MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD,
+ SHADER_TYPE = 0x8B4F,
+ DELETE_STATUS = 0x8B80,
+ LINK_STATUS = 0x8B82,
+ VALIDATE_STATUS = 0x8B83,
+ ATTACHED_SHADERS = 0x8B85,
+ ACTIVE_UNIFORMS = 0x8B86,
+ ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87,
+ ACTIVE_ATTRIBUTES = 0x8B89,
+ ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A,
+ SHADING_LANGUAGE_VERSION = 0x8B8C,
+ CURRENT_PROGRAM = 0x8B8D,
+ NEVER = 0x0200,
+ LESS = 0x0201,
+ EQUAL = 0x0202,
+ LEQUAL = 0x0203,
+ GREATER = 0x0204,
+ NOTEQUAL = 0x0205,
+ GEQUAL = 0x0206,
+ ALWAYS = 0x0207,
+ KEEP = 0x1E00,
+ REPLACE = 0x1E01,
+ INCR = 0x1E02,
+ DECR = 0x1E03,
+ INVERT = 0x150A,
+ INCR_WRAP = 0x8507,
+ DECR_WRAP = 0x8508,
+ VENDOR = 0x1F00,
+ RENDERER = 0x1F01,
+ VERSION = 0x1F02,
+ EXTENSIONS = 0x1F03,
+ NEAREST = 0x2600,
+ LINEAR = 0x2601,
+ NEAREST_MIPMAP_NEAREST = 0x2700,
+ LINEAR_MIPMAP_NEAREST = 0x2701,
+ NEAREST_MIPMAP_LINEAR = 0x2702,
+ LINEAR_MIPMAP_LINEAR = 0x2703,
+ TEXTURE_MAG_FILTER = 0x2800,
+ TEXTURE_MIN_FILTER = 0x2801,
+ TEXTURE_WRAP_S = 0x2802,
+ TEXTURE_WRAP_T = 0x2803,
+ TEXTURE = 0x1702,
+ TEXTURE_CUBE_MAP = 0x8513,
+ TEXTURE_BINDING_CUBE_MAP = 0x8514,
+ TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515,
+ TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516,
+ TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517,
+ TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518,
+ TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519,
+ TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A,
+ MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C,
+ TEXTURE0 = 0x84C0,
+ TEXTURE1 = 0x84C1,
+ TEXTURE2 = 0x84C2,
+ TEXTURE3 = 0x84C3,
+ TEXTURE4 = 0x84C4,
+ TEXTURE5 = 0x84C5,
+ TEXTURE6 = 0x84C6,
+ TEXTURE7 = 0x84C7,
+ TEXTURE8 = 0x84C8,
+ TEXTURE9 = 0x84C9,
+ TEXTURE10 = 0x84CA,
+ TEXTURE11 = 0x84CB,
+ TEXTURE12 = 0x84CC,
+ TEXTURE13 = 0x84CD,
+ TEXTURE14 = 0x84CE,
+ TEXTURE15 = 0x84CF,
+ TEXTURE16 = 0x84D0,
+ TEXTURE17 = 0x84D1,
+ TEXTURE18 = 0x84D2,
+ TEXTURE19 = 0x84D3,
+ TEXTURE20 = 0x84D4,
+ TEXTURE21 = 0x84D5,
+ TEXTURE22 = 0x84D6,
+ TEXTURE23 = 0x84D7,
+ TEXTURE24 = 0x84D8,
+ TEXTURE25 = 0x84D9,
+ TEXTURE26 = 0x84DA,
+ TEXTURE27 = 0x84DB,
+ TEXTURE28 = 0x84DC,
+ TEXTURE29 = 0x84DD,
+ TEXTURE30 = 0x84DE,
+ TEXTURE31 = 0x84DF,
+ ACTIVE_TEXTURE = 0x84E0,
+ REPEAT = 0x2901,
+ CLAMP_TO_EDGE = 0x812F,
+ MIRRORED_REPEAT = 0x8370,
+ FLOAT_VEC2 = 0x8B50,
+ FLOAT_VEC3 = 0x8B51,
+ FLOAT_VEC4 = 0x8B52,
+ INT_VEC2 = 0x8B53,
+ INT_VEC3 = 0x8B54,
+ INT_VEC4 = 0x8B55,
+ BOOL = 0x8B56,
+ BOOL_VEC2 = 0x8B57,
+ BOOL_VEC3 = 0x8B58,
+ BOOL_VEC4 = 0x8B59,
+ FLOAT_MAT2 = 0x8B5A,
+ FLOAT_MAT3 = 0x8B5B,
+ FLOAT_MAT4 = 0x8B5C,
+ SAMPLER_2D = 0x8B5E,
+ SAMPLER_CUBE = 0x8B60,
+ VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622,
+ VERTEX_ATTRIB_ARRAY_SIZE = 0x8623,
+ VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624,
+ VERTEX_ATTRIB_ARRAY_TYPE = 0x8625,
+ VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A,
+ VERTEX_ATTRIB_ARRAY_POINTER = 0x8645,
+ VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F,
+ COMPILE_STATUS = 0x8B81,
+ INFO_LOG_LENGTH = 0x8B84,
+ SHADER_SOURCE_LENGTH = 0x8B88,
+ SHADER_COMPILER = 0x8DFA,
+ SHADER_BINARY_FORMATS = 0x8DF8,
+ NUM_SHADER_BINARY_FORMATS = 0x8DF9,
+ LOW_FLOAT = 0x8DF0,
+ MEDIUM_FLOAT = 0x8DF1,
+ HIGH_FLOAT = 0x8DF2,
+ LOW_INT = 0x8DF3,
+ MEDIUM_INT = 0x8DF4,
+ HIGH_INT = 0x8DF5,
+ FRAMEBUFFER = 0x8D40,
+ RENDERBUFFER = 0x8D41,
+ RGBA4 = 0x8056,
+ RGB5_A1 = 0x8057,
+ RGB565 = 0x8D62,
+ DEPTH_COMPONENT16 = 0x81A5,
+ STENCIL_INDEX = 0x1901,
+ STENCIL_INDEX8 = 0x8D48,
+ DEPTH_STENCIL = 0x84F9,
+ RENDERBUFFER_WIDTH = 0x8D42,
+ RENDERBUFFER_HEIGHT = 0x8D43,
+ RENDERBUFFER_INTERNAL_FORMAT = 0x8D44,
+ RENDERBUFFER_RED_SIZE = 0x8D50,
+ RENDERBUFFER_GREEN_SIZE = 0x8D51,
+ RENDERBUFFER_BLUE_SIZE = 0x8D52,
+ RENDERBUFFER_ALPHA_SIZE = 0x8D53,
+ RENDERBUFFER_DEPTH_SIZE = 0x8D54,
+ RENDERBUFFER_STENCIL_SIZE = 0x8D55,
+ FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0,
+ FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1,
+ FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2,
+ FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3,
+ COLOR_ATTACHMENT0 = 0x8CE0,
+ DEPTH_ATTACHMENT = 0x8D00,
+ STENCIL_ATTACHMENT = 0x8D20,
+ DEPTH_STENCIL_ATTACHMENT = 0x821A,
+ NONE = 0,
+ FRAMEBUFFER_COMPLETE = 0x8CD5,
+ FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6,
+ FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7,
+ FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9,
+ FRAMEBUFFER_UNSUPPORTED = 0x8CDD,
+ FRAMEBUFFER_BINDING = 0x8CA6,
+ RENDERBUFFER_BINDING = 0x8CA7,
+ MAX_RENDERBUFFER_SIZE = 0x84E8,
+ INVALID_FRAMEBUFFER_OPERATION = 0x0506,
+
+ // WebGL-specific enums
+ UNPACK_FLIP_Y_WEBGL = 0x9240,
+ UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241,
+ CONTEXT_LOST_WEBGL = 0x9242,
+ UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243,
+ BROWSER_DEFAULT_WEBGL = 0x9244
+ };
+
+ // Context creation attributes.
+ struct Attributes {
+ Attributes()
+ : alpha(true)
+ , depth(true)
+ , stencil(false)
+ , antialias(true)
+ , premultipliedAlpha(true)
+ , canRecoverFromContextLoss(true)
+ {
+ }
+
+ bool alpha;
+ bool depth;
+ bool stencil;
+ bool antialias;
+ bool premultipliedAlpha;
+ bool canRecoverFromContextLoss;
+ };
+
+ enum RenderStyle {
+ RenderOffscreen,
+ RenderDirectlyToHostWindow
+ };
+
+ static PassRefPtr<GraphicsContext3D> create(Attributes, HostWindow*, RenderStyle = RenderOffscreen);
+ ~GraphicsContext3D();
+
+#if PLATFORM(MAC)
+ PlatformGraphicsContext3D platformGraphicsContext3D() const { return m_contextObj; }
+ Platform3DObject platformTexture() const { return m_texture; }
+ CALayer* platformLayer() const { return static_cast<CALayer*>(m_webGLLayer.get()); }
+#elif PLATFORM(CHROMIUM)
+ PlatformGraphicsContext3D platformGraphicsContext3D() const;
+ Platform3DObject platformTexture() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
+#elif PLATFORM(QT)
+ PlatformGraphicsContext3D platformGraphicsContext3D();
+ Platform3DObject platformTexture() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const { return 0; }
+#endif
+#else
+ PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; }
+ Platform3DObject platformTexture() const { return NullPlatform3DObject; }
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const { return 0; }
+#endif
+#endif
+ void makeContextCurrent();
+
+ PassRefPtr<DrawingBuffer> createDrawingBuffer(const IntSize& = IntSize());
+
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
+ // With multisampling on, blit from multisampleFBO to regular FBO.
+ void prepareTexture();
+#endif
+
+ // Helper to return the size in bytes of OpenGL data types
+ // like GL_FLOAT, GL_INT, etc.
+ unsigned int sizeInBytes(GC3Denum type);
+
+ // Helper to texImage2D with pixel==0 case: pixels are initialized to 0.
+ // Return true if no GL error is synthesized.
+ bool texImage2DResourceSafe(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type);
+
+ bool isGLES2Compliant() const;
+
+ //----------------------------------------------------------------------
+ // Helpers for texture uploading and pixel readback.
+ //
+
+ // Computes the components per pixel and bytes per component
+ // for the given format and type combination. Returns false if
+ // either was an invalid enum.
+ bool computeFormatAndTypeParameters(GC3Denum format,
+ GC3Denum type,
+ unsigned int* componentsPerPixel,
+ unsigned int* bytesPerComponent);
+
+ // Extracts the contents of the given Image into the passed Vector,
+ // packing the pixel data according to the given format and type,
+ // and obeying the flipY, premultiplyAlpha, and ignoreGammaAndColorProfile
+ // flags. Returns true upon success.
+ bool extractImageData(Image* image,
+ GC3Denum format,
+ GC3Denum type,
+ bool flipY,
+ bool premultiplyAlpha,
+ bool ignoreGammaAndColorProfile,
+ Vector<uint8_t>& data);
+
+ // Extracts the contents of the given ImageData into the passed Vector,
+ // packing the pixel data according to the given format and type,
+ // and obeying the flipY and premultiplyAlpha flags. Returns true
+ // upon success.
+ bool extractImageData(ImageData*,
+ GC3Denum format,
+ GC3Denum type,
+ bool flipY,
+ bool premultiplyAlpha,
+ Vector<uint8_t>& data);
+
+ // Helper function which extracts the user-supplied texture
+ // data, applying the flipY and premultiplyAlpha parameters.
+ // If the data is not tightly packed according to the passed
+ // unpackAlignment, the output data will be tightly packed.
+ // Returns true if successful, false if any error occurred.
+ bool extractTextureData(unsigned int width, unsigned int height,
+ GC3Denum format, GC3Denum type,
+ unsigned int unpackAlignment,
+ bool flipY, bool premultiplyAlpha,
+ const void* pixels,
+ Vector<uint8_t>& data);
+
+ // Flips the given image data vertically, in-place.
+ void flipVertically(void* imageData,
+ unsigned int width,
+ unsigned int height,
+ unsigned int bytesPerPixel,
+ unsigned int unpackAlignment);
+
+ // Attempt to enumerate all possible native image formats to
+ // reduce the amount of temporary allocations during texture
+ // uploading. This enum must be public because it is accessed
+ // by non-member functions.
+ enum SourceDataFormat {
+ SourceFormatRGBA8 = 0,
+ SourceFormatRGBA16Little,
+ SourceFormatRGBA16Big,
+ SourceFormatRGBA32F,
+ SourceFormatRGB8,
+ SourceFormatRGB16Little,
+ SourceFormatRGB16Big,
+ SourceFormatRGB32F,
+ SourceFormatBGR8,
+ SourceFormatBGRA8,
+ SourceFormatBGRA16Little,
+ SourceFormatBGRA16Big,
+ SourceFormatARGB8,
+ SourceFormatARGB16Little,
+ SourceFormatARGB16Big,
+ SourceFormatABGR8,
+ SourceFormatRGBA5551,
+ SourceFormatRGBA4444,
+ SourceFormatRGB565,
+ SourceFormatR8,
+ SourceFormatR16Little,
+ SourceFormatR16Big,
+ SourceFormatR32F,
+ SourceFormatRA8,
+ SourceFormatRA16Little,
+ SourceFormatRA16Big,
+ SourceFormatRA32F,
+ SourceFormatAR8,
+ SourceFormatAR16Little,
+ SourceFormatAR16Big,
+ SourceFormatA8,
+ SourceFormatA16Little,
+ SourceFormatA16Big,
+ SourceFormatA32F,
+ SourceFormatNumFormats
+ };
+
+ //----------------------------------------------------------------------
+ // Entry points for WebGL.
+ //
+
+ void activeTexture(GC3Denum texture);
+ void attachShader(Platform3DObject program, Platform3DObject shader);
+ void bindAttribLocation(Platform3DObject, GC3Duint index, const String& name);
+ void bindBuffer(GC3Denum target, Platform3DObject);
+ void bindFramebuffer(GC3Denum target, Platform3DObject);
+ void bindRenderbuffer(GC3Denum target, Platform3DObject);
+ void bindTexture(GC3Denum target, Platform3DObject);
+ void blendColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha);
+ void blendEquation(GC3Denum mode);
+ void blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha);
+ void blendFunc(GC3Denum sfactor, GC3Denum dfactor);
+ void blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha);
+
+ void bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage);
+ void bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage);
+ void bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data);
+
+ GC3Denum checkFramebufferStatus(GC3Denum target);
+ void clear(GC3Dbitfield mask);
+ void clearColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha);
+ void clearDepth(GC3Dclampf depth);
+ void clearStencil(GC3Dint s);
+ void colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha);
+ void compileShader(Platform3DObject);
+
+ // void compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Dsizei imageSize, const void* data);
+ // void compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Dsizei imageSize, const void* data);
+
+ void copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border);
+ void copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height);
+ void cullFace(GC3Denum mode);
+ void depthFunc(GC3Denum func);
+ void depthMask(GC3Dboolean flag);
+ void depthRange(GC3Dclampf zNear, GC3Dclampf zFar);
+ void detachShader(Platform3DObject, Platform3DObject);
+ void disable(GC3Denum cap);
+ void disableVertexAttribArray(GC3Duint index);
+ void drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count);
+ void drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset);
+
+ void enable(GC3Denum cap);
+ void enableVertexAttribArray(GC3Duint index);
+ void finish();
+ void flush();
+ void framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, Platform3DObject);
+ void framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject, GC3Dint level);
+ void frontFace(GC3Denum mode);
+ void generateMipmap(GC3Denum target);
+
+ bool getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo&);
+ bool getActiveUniform(Platform3DObject program, GC3Duint index, ActiveInfo&);
+ void getAttachedShaders(Platform3DObject program, GC3Dsizei maxCount, GC3Dsizei* count, Platform3DObject* shaders);
+ GC3Dint getAttribLocation(Platform3DObject, const String& name);
+ void getBooleanv(GC3Denum pname, GC3Dboolean* value);
+ void getBufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value);
+ Attributes getContextAttributes();
+ GC3Denum getError();
+ void getFloatv(GC3Denum pname, GC3Dfloat* value);
+ void getFramebufferAttachmentParameteriv(GC3Denum target, GC3Denum attachment, GC3Denum pname, GC3Dint* value);
+ void getIntegerv(GC3Denum pname, GC3Dint* value);
+ void getProgramiv(Platform3DObject program, GC3Denum pname, GC3Dint* value);
+ String getProgramInfoLog(Platform3DObject);
+ void getRenderbufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value);
+ void getShaderiv(Platform3DObject, GC3Denum pname, GC3Dint* value);
+ String getShaderInfoLog(Platform3DObject);
+
+ // TBD
+ // void glGetShaderPrecisionFormat (GC3Denum shadertype, GC3Denum precisiontype, GC3Dint* range, GC3Dint* precision);
+
+ String getShaderSource(Platform3DObject);
+ String getString(GC3Denum name);
+ void getTexParameterfv(GC3Denum target, GC3Denum pname, GC3Dfloat* value);
+ void getTexParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value);
+ void getUniformfv(Platform3DObject program, GC3Dint location, GC3Dfloat* value);
+ void getUniformiv(Platform3DObject program, GC3Dint location, GC3Dint* value);
+ GC3Dint getUniformLocation(Platform3DObject, const String& name);
+ void getVertexAttribfv(GC3Duint index, GC3Denum pname, GC3Dfloat* value);
+ void getVertexAttribiv(GC3Duint index, GC3Denum pname, GC3Dint* value);
+ GC3Dsizeiptr getVertexAttribOffset(GC3Duint index, GC3Denum pname);
+
+ void hint(GC3Denum target, GC3Denum mode);
+ GC3Dboolean isBuffer(Platform3DObject);
+ GC3Dboolean isEnabled(GC3Denum cap);
+ GC3Dboolean isFramebuffer(Platform3DObject);
+ GC3Dboolean isProgram(Platform3DObject);
+ GC3Dboolean isRenderbuffer(Platform3DObject);
+ GC3Dboolean isShader(Platform3DObject);
+ GC3Dboolean isTexture(Platform3DObject);
+ void lineWidth(GC3Dfloat);
+ void linkProgram(Platform3DObject);
+ void pixelStorei(GC3Denum pname, GC3Dint param);
+ void polygonOffset(GC3Dfloat factor, GC3Dfloat units);
+
+ void readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data);
+
+ void releaseShaderCompiler();
+
+ void renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height);
+ void sampleCoverage(GC3Dclampf value, GC3Dboolean invert);
+ void scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height);
+ void shaderSource(Platform3DObject, const String& string);
+ void stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask);
+ void stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask);
+ void stencilMask(GC3Duint mask);
+ void stencilMaskSeparate(GC3Denum face, GC3Duint mask);
+ void stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass);
+ void stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass);
+
+ bool texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels);
+ void texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param);
+ void texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param);
+ void texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels);
+
+ // FIXME: change the argument orders to match OpenGL's.
+ void uniform1f(GC3Dint location, GC3Dfloat x);
+ void uniform1fv(GC3Dint location, GC3Dfloat* v, GC3Dsizei size);
+ void uniform1i(GC3Dint location, GC3Dint x);
+ void uniform1iv(GC3Dint location, GC3Dint* v, GC3Dsizei size);
+ void uniform2f(GC3Dint location, GC3Dfloat x, float y);
+ void uniform2fv(GC3Dint location, GC3Dfloat* v, GC3Dsizei size);
+ void uniform2i(GC3Dint location, GC3Dint x, GC3Dint y);
+ void uniform2iv(GC3Dint location, GC3Dint* v, GC3Dsizei size);
+ void uniform3f(GC3Dint location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z);
+ void uniform3fv(GC3Dint location, GC3Dfloat* v, GC3Dsizei size);
+ void uniform3i(GC3Dint location, GC3Dint x, GC3Dint y, GC3Dint z);
+ void uniform3iv(GC3Dint location, GC3Dint* v, GC3Dsizei size);
+ void uniform4f(GC3Dint location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w);
+ void uniform4fv(GC3Dint location, GC3Dfloat* v, GC3Dsizei size);
+ void uniform4i(GC3Dint location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w);
+ void uniform4iv(GC3Dint location, GC3Dint* v, GC3Dsizei size);
+ void uniformMatrix2fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* value, GC3Dsizei size);
+ void uniformMatrix3fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* value, GC3Dsizei size);
+ void uniformMatrix4fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* value, GC3Dsizei size);
+
+ void useProgram(Platform3DObject);
+ void validateProgram(Platform3DObject);
+
+ void vertexAttrib1f(GC3Duint index, GC3Dfloat x);
+ void vertexAttrib1fv(GC3Duint index, GC3Dfloat* values);
+ void vertexAttrib2f(GC3Duint index, GC3Dfloat x, GC3Dfloat y);
+ void vertexAttrib2fv(GC3Duint index, GC3Dfloat* values);
+ void vertexAttrib3f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z);
+ void vertexAttrib3fv(GC3Duint index, GC3Dfloat* values);
+ void vertexAttrib4f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w);
+ void vertexAttrib4fv(GC3Duint index, GC3Dfloat* values);
+ void vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized,
+ GC3Dsizei stride, GC3Dintptr offset);
+
+ void viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height);
+
+ void reshape(int width, int height);
+
+#if PLATFORM(CG)
+ void paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight,
+ int canvasWidth, int canvasHeight, CGContextRef context);
+#endif
+
+ void paintRenderingResultsToCanvas(CanvasRenderingContext* context);
+
+#if PLATFORM(QT)
+ void paint(QPainter* painter, const QRect& rect) const;
+ bool paintsIntoCanvasBuffer() const { return true; }
+#elif PLATFORM(CHROMIUM)
+ bool paintsIntoCanvasBuffer() const;
+#else
+ bool paintsIntoCanvasBuffer() const { return false; }
+#endif
+
+ // Support for buffer creation and deletion
+ Platform3DObject createBuffer();
+ Platform3DObject createFramebuffer();
+ Platform3DObject createProgram();
+ Platform3DObject createRenderbuffer();
+ Platform3DObject createShader(GC3Denum);
+ Platform3DObject createTexture();
+
+ void deleteBuffer(Platform3DObject);
+ void deleteFramebuffer(Platform3DObject);
+ void deleteProgram(Platform3DObject);
+ void deleteRenderbuffer(Platform3DObject);
+ void deleteShader(Platform3DObject);
+ void deleteTexture(Platform3DObject);
+
+ // Synthesizes an OpenGL error which will be returned from a
+ // later call to getError. This is used to emulate OpenGL ES
+ // 2.0 behavior on the desktop and to enforce additional error
+ // checking mandated by WebGL.
+ //
+ // Per the behavior of glGetError, this stores at most one
+ // instance of any given error, and returns them from calls to
+ // getError in the order they were added.
+ void synthesizeGLError(GC3Denum error);
+
+ // Support for extensions. Returns a non-null object, though not
+ // all methods it contains may necessarily be supported on the
+ // current hardware. Must call Extensions3D::supports() to
+ // determine this.
+ Extensions3D* getExtensions();
+
+ IntSize getInternalFramebufferSize();
+
+ private:
+ GraphicsContext3D(Attributes attrs, HostWindow* hostWindow, bool renderDirectlyToHostWindow);
+
+ // Each platform must provide an implementation of this method.
+ //
+ // Gets the data for the given Image into outputVector in the
+ // format specified by the (OpenGL-style) format and type
+ // arguments. Despite the fact that the outputVector contains
+ // uint8_t, if the format and type specify packed pixels, then
+ // it will essentially contain uint16_t after the extraction
+ // process.
+ //
+ // If premultiplyAlpha is true, the alpha channel, if any,
+ // will be multiplied into the color channels during the
+ // extraction process. This premultiplication occurs before
+ // any packing of pixel data.
+ //
+ // If ignoreGammaAndColorProfile is true, gamma correction and ICC
+ // profile won't be applied.
+ //
+ // No vertical flip of the image data is performed by this
+ // method.
+ bool getImageData(Image* image,
+ GC3Denum format,
+ GC3Denum type,
+ bool premultiplyAlpha,
+ bool ignoreGammaAndColorProfile,
+ Vector<uint8_t>& outputVector);
+
+ // Possible alpha operations that may need to occur during
+ // pixel packing. FIXME: kAlphaDoUnmultiply is lossy and must
+ // be removed.
+ enum AlphaOp {
+ AlphaDoNothing = 0,
+ AlphaDoPremultiply = 1,
+ AlphaDoUnmultiply = 2
+ };
+
+ // Helper for getImageData which implements packing of pixel
+ // data into the specified OpenGL destination format and type.
+ // A sourceUnpackAlignment of zero indicates that the source
+ // data is tightly packed. Non-zero values may take a slow path.
+ // Destination data will have no gaps between rows.
+ bool packPixels(const uint8_t* sourceData,
+ SourceDataFormat sourceDataFormat,
+ unsigned int width,
+ unsigned int height,
+ unsigned int sourceUnpackAlignment,
+ unsigned int destinationFormat,
+ unsigned int destinationType,
+ AlphaOp alphaOp,
+ void* destinationData);
+
+#if PLATFORM(MAC)
+ // Take into account the user's requested context creation attributes,
+ // in particular stencil and antialias, and determine which could or
+ // could not be honored based on the capabilities of the OpenGL
+ // implementation.
+ void validateAttributes();
+#endif
+
+ int m_currentWidth, m_currentHeight;
+
+#if PLATFORM(MAC)
+ typedef struct {
+ String source;
+ String log;
+ bool isValid;
+ } ShaderSourceEntry;
+ HashMap<Platform3DObject, ShaderSourceEntry> m_shaderSourceMap;
+
+ ANGLEWebKitBridge m_compiler;
+
+ OwnPtr<Extensions3DOpenGL> m_extensions;
+
+ Attributes m_attrs;
+ Vector<Vector<float> > m_vertexArray;
+
+ CGLContextObj m_contextObj;
+ RetainPtr<WebGLLayer> m_webGLLayer;
+ GC3Duint m_texture;
+ GC3Duint m_fbo;
+ GC3Duint m_depthStencilBuffer;
+
+ // For tracking which FBO is bound
+ GC3Duint m_boundFBO;
+
+ // For multisampling
+ GC3Duint m_multisampleFBO;
+ GC3Duint m_multisampleDepthStencilBuffer;
+ GC3Duint m_multisampleColorBuffer;
+
+ // Errors raised by synthesizeGLError().
+ ListHashSet<GC3Denum> m_syntheticErrors;
+#endif
+
+ // FIXME: ideally this would be used on all platforms.
+#if PLATFORM(CHROMIUM) || PLATFORM(QT)
+ friend class GraphicsContext3DInternal;
+ OwnPtr<GraphicsContext3DInternal> m_internal;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // GraphicsContext3D_h
diff --git a/Source/WebCore/platform/graphics/GraphicsLayer.cpp b/Source/WebCore/platform/graphics/GraphicsLayer.cpp
new file mode 100644
index 0000000..84905a9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GraphicsLayer.cpp
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayer.h"
+
+#include "FloatPoint.h"
+#include "RotateTransformOperation.h"
+#include "TextStream.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+namespace WebCore {
+
+void KeyframeValueList::insert(const AnimationValue* value)
+{
+ for (size_t i = 0; i < m_values.size(); ++i) {
+ const AnimationValue* curValue = m_values[i];
+ if (curValue->keyTime() == value->keyTime()) {
+ ASSERT_NOT_REACHED();
+ // insert after
+ m_values.insert(i + 1, value);
+ return;
+ }
+ if (curValue->keyTime() > value->keyTime()) {
+ // insert before
+ m_values.insert(i, value);
+ return;
+ }
+ }
+
+ m_values.append(value);
+}
+
+GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
+ : m_client(client)
+ , m_anchorPoint(0.5f, 0.5f, 0)
+ , m_opacity(1)
+ , m_zPosition(0)
+ , m_backgroundColorSet(false)
+ , m_contentsOpaque(false)
+ , m_preserves3D(false)
+ , m_backfaceVisibility(true)
+ , m_usingTiledLayer(false)
+ , m_masksToBounds(false)
+ , m_drawsContent(false)
+ , m_acceleratesDrawing(false)
+ , m_paintingPhase(GraphicsLayerPaintAll)
+ , m_contentsOrientation(CompositingCoordinatesTopDown)
+ , m_parent(0)
+ , m_maskLayer(0)
+ , m_replicaLayer(0)
+ , m_replicatedLayer(0)
+ , m_repaintCount(0)
+{
+}
+
+GraphicsLayer::~GraphicsLayer()
+{
+ removeAllChildren();
+ removeFromParent();
+}
+
+bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const
+{
+ for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) {
+ if (curr == ancestor)
+ return true;
+ }
+
+ return false;
+}
+
+bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren)
+{
+ // If the contents of the arrays are the same, nothing to do.
+ if (newChildren == m_children)
+ return false;
+
+ removeAllChildren();
+
+ size_t listSize = newChildren.size();
+ for (size_t i = 0; i < listSize; ++i)
+ addChild(newChildren[i]);
+
+ return true;
+}
+
+void GraphicsLayer::addChild(GraphicsLayer* childLayer)
+{
+ ASSERT(childLayer != this);
+
+ if (childLayer->parent())
+ childLayer->removeFromParent();
+
+ childLayer->setParent(this);
+ m_children.append(childLayer);
+}
+
+void GraphicsLayer::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+ ASSERT(childLayer != this);
+
+ if (childLayer->parent())
+ childLayer->removeFromParent();
+
+ childLayer->setParent(this);
+ m_children.insert(index, childLayer);
+}
+
+void GraphicsLayer::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ ASSERT(childLayer != this);
+ childLayer->removeFromParent();
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i, childLayer);
+ found = true;
+ break;
+ }
+ }
+
+ childLayer->setParent(this);
+
+ if (!found)
+ m_children.append(childLayer);
+}
+
+void GraphicsLayer::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ childLayer->removeFromParent();
+ ASSERT(childLayer != this);
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i+1, childLayer);
+ found = true;
+ break;
+ }
+ }
+
+ childLayer->setParent(this);
+
+ if (!found)
+ m_children.append(childLayer);
+}
+
+bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ ASSERT(!newChild->parent());
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (oldChild == m_children[i]) {
+ m_children[i] = newChild;
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ oldChild->setParent(0);
+
+ newChild->removeFromParent();
+ newChild->setParent(this);
+ return true;
+ }
+ return false;
+}
+
+void GraphicsLayer::removeAllChildren()
+{
+ while (m_children.size()) {
+ GraphicsLayer* curLayer = m_children[0];
+ ASSERT(curLayer->parent());
+ curLayer->removeFromParent();
+ }
+}
+
+void GraphicsLayer::removeFromParent()
+{
+ if (m_parent) {
+ unsigned i;
+ for (i = 0; i < m_parent->m_children.size(); i++) {
+ if (this == m_parent->m_children[i]) {
+ m_parent->m_children.remove(i);
+ break;
+ }
+ }
+
+ setParent(0);
+ }
+}
+
+void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
+{
+ if (layer)
+ layer->setReplicatedLayer(this);
+
+ m_replicaLayer = layer;
+}
+
+void GraphicsLayer::setBackgroundColor(const Color& color)
+{
+ m_backgroundColor = color;
+ m_backgroundColorSet = true;
+}
+
+void GraphicsLayer::clearBackgroundColor()
+{
+ m_backgroundColor = Color();
+ m_backgroundColorSet = false;
+}
+
+void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const IntRect& clip)
+{
+ if (m_client)
+ m_client->paintContents(this, context, m_paintingPhase, clip);
+}
+
+String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property)
+{
+ // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier.
+ return makeString("-|transition", static_cast<char>(property), '-');
+}
+
+void GraphicsLayer::suspendAnimations(double)
+{
+}
+
+void GraphicsLayer::resumeAnimations()
+{
+}
+
+void GraphicsLayer::updateDebugIndicators()
+{
+ if (GraphicsLayer::showDebugBorders()) {
+ if (drawsContent()) {
+ if (m_usingTiledLayer)
+ setDebugBorder(Color(0, 255, 0, 204), 2.0f); // tiled layer: green
+ else
+ setDebugBorder(Color(255, 0, 0, 204), 2.0f); // normal layer: red
+ } else if (masksToBounds()) {
+ setDebugBorder(Color(128, 255, 255, 178), 2.0f); // masking layer: pale blue
+ if (GraphicsLayer::showDebugBorders())
+ setDebugBackgroundColor(Color(128, 255, 255, 52));
+ } else
+ setDebugBorder(Color(255, 255, 0, 204), 2.0f); // container: yellow
+ }
+}
+
+void GraphicsLayer::setZPosition(float position)
+{
+ m_zPosition = position;
+}
+
+float GraphicsLayer::accumulatedOpacity() const
+{
+ if (!preserves3D())
+ return 1;
+
+ return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1);
+}
+
+void GraphicsLayer::distributeOpacity(float accumulatedOpacity)
+{
+ // If this is a transform layer we need to distribute our opacity to all our children
+
+ // Incoming accumulatedOpacity is the contribution from our parent(s). We mutiply this by our own
+ // opacity to get the total contribution
+ accumulatedOpacity *= m_opacity;
+
+ setOpacityInternal(accumulatedOpacity);
+
+ if (preserves3D()) {
+ size_t numChildren = children().size();
+ for (size_t i = 0; i < numChildren; ++i)
+ children()[i]->distributeOpacity(accumulatedOpacity);
+ }
+}
+
+// An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix
+// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is
+// true if the rotation between any two keyframes is >= 180 degrees.
+
+static inline const TransformOperations* operationsAt(const KeyframeValueList& valueList, size_t index)
+{
+ return static_cast<const TransformAnimationValue*>(valueList.at(index))->value();
+}
+
+void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList& valueList, TransformOperationList& list, bool& isValid, bool& hasBigRotation)
+{
+ ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
+
+ list.clear();
+ isValid = false;
+ hasBigRotation = false;
+
+ if (valueList.size() < 2)
+ return;
+
+ // Empty transforms match anything, so find the first non-empty entry as the reference.
+ size_t firstIndex = 0;
+ for ( ; firstIndex < valueList.size(); ++firstIndex) {
+ if (operationsAt(valueList, firstIndex)->operations().size() > 0)
+ break;
+ }
+
+ if (firstIndex >= valueList.size())
+ return;
+
+ const TransformOperations* firstVal = operationsAt(valueList, firstIndex);
+
+ // See if the keyframes are valid.
+ for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
+ const TransformOperations* val = operationsAt(valueList, i);
+
+ // a null transform matches anything
+ if (val->operations().isEmpty())
+ continue;
+
+ if (firstVal->operations().size() != val->operations().size())
+ return;
+
+ for (size_t j = 0; j < firstVal->operations().size(); ++j) {
+ if (!firstVal->operations().at(j)->isSameType(*val->operations().at(j)))
+ return;
+ }
+ }
+
+ // Keyframes are valid, fill in the list.
+ isValid = true;
+
+ double lastRotAngle = 0.0;
+ double maxRotAngle = -1.0;
+
+ list.resize(firstVal->operations().size());
+ for (size_t j = 0; j < firstVal->operations().size(); ++j) {
+ TransformOperation::OperationType type = firstVal->operations().at(j)->getOperationType();
+ list[j] = type;
+
+ // if this is a rotation entry, we need to see if any angle differences are >= 180 deg
+ if (type == TransformOperation::ROTATE_X ||
+ type == TransformOperation::ROTATE_Y ||
+ type == TransformOperation::ROTATE_Z ||
+ type == TransformOperation::ROTATE_3D) {
+ lastRotAngle = static_cast<RotateTransformOperation*>(firstVal->operations().at(j).get())->angle();
+
+ if (maxRotAngle < 0)
+ maxRotAngle = fabs(lastRotAngle);
+
+ for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
+ const TransformOperations* val = operationsAt(valueList, i);
+ double rotAngle = val->operations().isEmpty() ? 0 : (static_cast<RotateTransformOperation*>(val->operations().at(j).get())->angle());
+ double diffAngle = fabs(rotAngle - lastRotAngle);
+ if (diffAngle > maxRotAngle)
+ maxRotAngle = diffAngle;
+ lastRotAngle = rotAngle;
+ }
+ }
+ }
+
+ hasBigRotation = maxRotAngle >= 180.0;
+}
+
+
+static void writeIndent(TextStream& ts, int indent)
+{
+ for (int i = 0; i != indent; ++i)
+ ts << " ";
+}
+
+void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
+{
+ writeIndent(ts, indent);
+ ts << "(" << "GraphicsLayer";
+
+ if (behavior & LayerTreeAsTextDebug) {
+ ts << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this));
+ ts << " \"" << m_name << "\"";
+ }
+
+ ts << "\n";
+ dumpProperties(ts, indent, behavior);
+ writeIndent(ts, indent);
+ ts << ")\n";
+}
+
+void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
+{
+ if (m_position != FloatPoint()) {
+ writeIndent(ts, indent + 1);
+ ts << "(position " << m_position.x() << " " << m_position.y() << ")\n";
+ }
+
+ if (m_anchorPoint != FloatPoint3D(0.5f, 0.5f, 0)) {
+ writeIndent(ts, indent + 1);
+ ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y() << ")\n";
+ }
+
+ if (m_size != IntSize()) {
+ writeIndent(ts, indent + 1);
+ ts << "(bounds " << m_size.width() << " " << m_size.height() << ")\n";
+ }
+
+ if (m_opacity != 1) {
+ writeIndent(ts, indent + 1);
+ ts << "(opacity " << m_opacity << ")\n";
+ }
+
+ if (m_usingTiledLayer) {
+ writeIndent(ts, indent + 1);
+ ts << "(usingTiledLayer " << m_usingTiledLayer << ")\n";
+ }
+
+ if (m_preserves3D) {
+ writeIndent(ts, indent + 1);
+ ts << "(preserves3D " << m_preserves3D << ")\n";
+ }
+
+ if (m_drawsContent) {
+ writeIndent(ts, indent + 1);
+ ts << "(drawsContent " << m_drawsContent << ")\n";
+ }
+
+ if (!m_backfaceVisibility) {
+ writeIndent(ts, indent + 1);
+ ts << "(backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n";
+ }
+
+ if (behavior & LayerTreeAsTextDebug) {
+ writeIndent(ts, indent + 1);
+ ts << "(";
+ if (m_client)
+ ts << "client " << static_cast<void*>(m_client);
+ else
+ ts << "no client";
+ ts << ")\n";
+ }
+
+ if (m_backgroundColorSet) {
+ writeIndent(ts, indent + 1);
+ ts << "(backgroundColor " << m_backgroundColor.name() << ")\n";
+ }
+
+ if (!m_transform.isIdentity()) {
+ writeIndent(ts, indent + 1);
+ ts << "(transform ";
+ ts << "[" << m_transform.m11() << " " << m_transform.m12() << " " << m_transform.m13() << " " << m_transform.m14() << "] ";
+ ts << "[" << m_transform.m21() << " " << m_transform.m22() << " " << m_transform.m23() << " " << m_transform.m24() << "] ";
+ ts << "[" << m_transform.m31() << " " << m_transform.m32() << " " << m_transform.m33() << " " << m_transform.m34() << "] ";
+ ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "])\n";
+ }
+
+ // Avoid dumping the sublayer transform on the root layer, because it's used for geometry flipping, whose behavior
+ // differs between platforms.
+ if (parent() && !m_childrenTransform.isIdentity()) {
+ writeIndent(ts, indent + 1);
+ ts << "(childrenTransform ";
+ ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] ";
+ ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] ";
+ ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] ";
+ ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "])\n";
+ }
+
+ if (m_replicaLayer) {
+ writeIndent(ts, indent + 1);
+ ts << "(replica layer";
+ if (behavior & LayerTreeAsTextDebug)
+ ts << " " << m_replicaLayer;
+ ts << ")\n";
+ m_replicaLayer->dumpLayer(ts, indent + 2, behavior);
+ }
+
+ if (m_replicatedLayer) {
+ writeIndent(ts, indent + 1);
+ ts << "(replicated layer";
+ if (behavior & LayerTreeAsTextDebug)
+ ts << " " << m_replicatedLayer;;
+ ts << ")\n";
+ }
+
+ if (m_children.size()) {
+ writeIndent(ts, indent + 1);
+ ts << "(children " << m_children.size() << "\n";
+
+ unsigned i;
+ for (i = 0; i < m_children.size(); i++)
+ m_children[i]->dumpLayer(ts, indent + 2, behavior);
+ writeIndent(ts, indent + 1);
+ ts << ")\n";
+ }
+}
+
+String GraphicsLayer::layerTreeAsText(LayerTreeAsTextBehavior behavior) const
+{
+ TextStream ts;
+
+ dumpLayer(ts, 0, behavior);
+ return ts.release();
+}
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer)
+{
+ if (!layer)
+ return;
+
+ WTF::String output = layer->layerTreeAsText(LayerTreeAsTextDebug);
+ fprintf(stderr, "%s\n", output.utf8().data());
+}
+#endif
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/GraphicsLayer.h b/Source/WebCore/platform/graphics/GraphicsLayer.h
new file mode 100644
index 0000000..ef3c1bc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GraphicsLayer.h
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 GraphicsLayer_h
+#define GraphicsLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Animation.h"
+#include "Color.h"
+#include "FloatPoint.h"
+#include "FloatPoint3D.h"
+#include "FloatSize.h"
+#include "GraphicsLayerClient.h"
+#include "IntRect.h"
+#include "TransformationMatrix.h"
+#include "TransformOperations.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+#if USE(TEXTURE_MAPPER)
+#include "texmap/TextureMapperPlatformLayer.h"
+#endif
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+@class WebLayer;
+@class CALayer;
+typedef CALayer PlatformLayer;
+#else
+typedef void* PlatformLayer;
+#endif
+#elif PLATFORM(WIN)
+typedef struct _CACFLayer PlatformLayer;
+#elif PLATFORM(QT)
+#if USE(TEXTURE_MAPPER)
+namespace WebCore {
+class TextureMapperPlatformLayer;
+typedef TextureMapperPlatformLayer PlatformLayer;
+};
+#else
+QT_BEGIN_NAMESPACE
+class QGraphicsObject;
+QT_END_NAMESPACE
+namespace WebCore {
+typedef QGraphicsObject PlatformLayer;
+}
+#endif
+#elif PLATFORM(CHROMIUM)
+namespace WebCore {
+class LayerChromium;
+typedef LayerChromium PlatformLayer;
+}
+#elif PLATFORM(ANDROID)
+namespace WebCore {
+class LayerAndroid;
+typedef LayerAndroid PlatformLayer;
+typedef void* NativeLayer;
+}
+#else
+typedef void* PlatformLayer;
+#endif
+
+enum LayerTreeAsTextBehaviorFlags {
+ LayerTreeAsTextBehaviorNormal = 0,
+ LayerTreeAsTextDebug = 1 << 0, // Dump extra debugging info like layer addresses.
+};
+typedef unsigned LayerTreeAsTextBehavior;
+
+namespace WebCore {
+
+class FloatPoint3D;
+class GraphicsContext;
+class Image;
+class TextStream;
+class TimingFunction;
+
+// Base class for animation values (also used for transitions). Here to
+// represent values for properties being animated via the GraphicsLayer,
+// without pulling in style-related data from outside of the platform directory.
+class AnimationValue : public Noncopyable {
+public:
+ AnimationValue(float keyTime, PassRefPtr<TimingFunction> timingFunction = 0)
+ : m_keyTime(keyTime)
+ {
+ if (timingFunction)
+ m_timingFunction = timingFunction;
+ }
+
+ virtual ~AnimationValue() { }
+
+ float keyTime() const { return m_keyTime; }
+ const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
+
+private:
+ float m_keyTime;
+ RefPtr<TimingFunction> m_timingFunction;
+};
+
+// Used to store one float value of an animation.
+class FloatAnimationValue : public AnimationValue {
+public:
+ FloatAnimationValue(float keyTime, float value, PassRefPtr<TimingFunction> timingFunction = 0)
+ : AnimationValue(keyTime, timingFunction)
+ , m_value(value)
+ {
+ }
+
+ float value() const { return m_value; }
+
+private:
+ float m_value;
+};
+
+// Used to store one transform value in a keyframe list.
+class TransformAnimationValue : public AnimationValue {
+public:
+ TransformAnimationValue(float keyTime, const TransformOperations* value = 0, PassRefPtr<TimingFunction> timingFunction = 0)
+ : AnimationValue(keyTime, timingFunction)
+ {
+ if (value)
+ m_value = adoptPtr(new TransformOperations(*value));
+ }
+
+ const TransformOperations* value() const { return m_value.get(); }
+
+private:
+ OwnPtr<TransformOperations> m_value;
+};
+
+// Used to store a series of values in a keyframe list. Values will all be of the same type,
+// which can be inferred from the property.
+class KeyframeValueList : public Noncopyable {
+public:
+
+ KeyframeValueList(AnimatedPropertyID property)
+ : m_property(property)
+ {
+ }
+
+ ~KeyframeValueList()
+ {
+ deleteAllValues(m_values);
+ }
+
+ AnimatedPropertyID property() const { return m_property; }
+
+ size_t size() const { return m_values.size(); }
+ const AnimationValue* at(size_t i) const { return m_values.at(i); }
+
+ // Insert, sorted by keyTime. Takes ownership of the pointer.
+ void insert(const AnimationValue*);
+
+protected:
+ Vector<const AnimationValue*> m_values;
+ AnimatedPropertyID m_property;
+};
+
+
+
+// GraphicsLayer is an abstraction for a rendering surface with backing store,
+// which may have associated transformation and animations.
+
+class GraphicsLayer {
+public:
+
+ static PassOwnPtr<GraphicsLayer> create(GraphicsLayerClient*);
+
+ virtual ~GraphicsLayer();
+
+ GraphicsLayerClient* client() const { return m_client; }
+
+ // Layer name. Only used to identify layers in debug output
+ const String& name() const { return m_name; }
+ virtual void setName(const String& name) { m_name = name; }
+
+ GraphicsLayer* parent() const { return m_parent; };
+ void setParent(GraphicsLayer* layer) { m_parent = layer; } // Internal use only.
+
+ // Returns true if the layer has the given layer as an ancestor (excluding self).
+ bool hasAncestor(GraphicsLayer*) const;
+
+ const Vector<GraphicsLayer*>& children() const { return m_children; }
+ // Returns true if the child list changed.
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
+
+ // Add child layers. If the child is already parented, it will be removed from its old parent.
+ virtual void addChild(GraphicsLayer*);
+ virtual void addChildAtIndex(GraphicsLayer*, int index);
+ virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+
+ void removeAllChildren();
+ virtual void removeFromParent();
+
+ GraphicsLayer* maskLayer() const { return m_maskLayer; }
+ virtual void setMaskLayer(GraphicsLayer* layer) { m_maskLayer = layer; }
+
+ // The given layer will replicate this layer and its children; the replica renders behind this layer.
+ virtual void setReplicatedByLayer(GraphicsLayer*);
+ // Whether this layer is being replicated by another layer.
+ bool isReplicated() const { return m_replicaLayer; }
+ // The layer that replicates this layer (if any).
+ GraphicsLayer* replicaLayer() const { return m_replicaLayer; }
+
+ const FloatPoint& replicatedLayerPosition() const { return m_replicatedLayerPosition; }
+ void setReplicatedLayerPosition(const FloatPoint& p) { m_replicatedLayerPosition = p; }
+
+ // Offset is origin of the renderer minus origin of the graphics layer (so either zero or negative).
+ IntSize offsetFromRenderer() const { return m_offsetFromRenderer; }
+ void setOffsetFromRenderer(const IntSize& offset) { m_offsetFromRenderer = offset; }
+
+ // The position of the layer (the location of its top-left corner in its parent)
+ const FloatPoint& position() const { return m_position; }
+ virtual void setPosition(const FloatPoint& p) { m_position = p; }
+
+ // Anchor point: (0, 0) is top left, (1, 1) is bottom right. The anchor point
+ // affects the origin of the transforms.
+ const FloatPoint3D& anchorPoint() const { return m_anchorPoint; }
+ virtual void setAnchorPoint(const FloatPoint3D& p) { m_anchorPoint = p; }
+
+ // The bounds of the layer
+ const FloatSize& size() const { return m_size; }
+ virtual void setSize(const FloatSize& size) { m_size = size; }
+
+ const TransformationMatrix& transform() const { return m_transform; }
+ virtual void setTransform(const TransformationMatrix& t) { m_transform = t; }
+
+ const TransformationMatrix& childrenTransform() const { return m_childrenTransform; }
+ virtual void setChildrenTransform(const TransformationMatrix& t) { m_childrenTransform = t; }
+
+ bool preserves3D() const { return m_preserves3D; }
+ virtual void setPreserves3D(bool b) { m_preserves3D = b; }
+
+ bool masksToBounds() const { return m_masksToBounds; }
+ virtual void setMasksToBounds(bool b) { m_masksToBounds = b; }
+
+ bool drawsContent() const { return m_drawsContent; }
+ virtual void setDrawsContent(bool b) { m_drawsContent = b; }
+
+ bool acceleratesDrawing() const { return m_acceleratesDrawing; }
+ virtual void setAcceleratesDrawing(bool b) { m_acceleratesDrawing = b; }
+
+ // The color used to paint the layer backgrounds
+ const Color& backgroundColor() const { return m_backgroundColor; }
+ virtual void setBackgroundColor(const Color&);
+ virtual void clearBackgroundColor();
+ bool backgroundColorSet() const { return m_backgroundColorSet; }
+
+ // opaque means that we know the layer contents have no alpha
+ bool contentsOpaque() const { return m_contentsOpaque; }
+ virtual void setContentsOpaque(bool b) { m_contentsOpaque = b; }
+
+ bool backfaceVisibility() const { return m_backfaceVisibility; }
+ virtual void setBackfaceVisibility(bool b) { m_backfaceVisibility = b; }
+
+ float opacity() const { return m_opacity; }
+ virtual void setOpacity(float opacity) { m_opacity = opacity; }
+
+ // Some GraphicsLayers paint only the foreground or the background content
+ GraphicsLayerPaintingPhase paintingPhase() const { return m_paintingPhase; }
+ void setPaintingPhase(GraphicsLayerPaintingPhase phase) { m_paintingPhase = phase; }
+
+ virtual void setNeedsDisplay() = 0;
+ // mark the given rect (in layer coords) as needing dispay. Never goes deep.
+ virtual void setNeedsDisplayInRect(const FloatRect&) = 0;
+
+ virtual void setContentsNeedsDisplay() { };
+
+ // Set that the position/size of the contents (image or video).
+ IntRect contentsRect() const { return m_contentsRect; }
+ virtual void setContentsRect(const IntRect& r) { m_contentsRect = r; }
+
+ // Transitions are identified by a special animation name that cannot clash with a keyframe identifier.
+ static String animationNameForTransition(AnimatedPropertyID);
+
+ // Return true if the animation is handled by the compositing system. If this returns
+ // false, the animation will be run by AnimationController.
+ // These methods handle both transitions and keyframe animations.
+ virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, const String& /*animationName*/, double /*timeOffset*/) { return false; }
+ virtual void pauseAnimation(const String& /*animationName*/, double /*timeOffset*/) { }
+ virtual void removeAnimation(const String& /*animationName*/) { }
+
+ virtual void suspendAnimations(double time);
+ virtual void resumeAnimations();
+
+ // Layer contents
+ virtual void setContentsToImage(Image*) { }
+ virtual void setContentsToMedia(PlatformLayer*) { } // video or plug-in
+ virtual void setContentsBackgroundColor(const Color&) { }
+ virtual void setContentsToCanvas(PlatformLayer*) { }
+ virtual bool hasContentsLayer() const { return false; }
+
+ // Callback from the underlying graphics system to draw layer contents.
+ void paintGraphicsLayerContents(GraphicsContext&, const IntRect& clip);
+ // Callback from the underlying graphics system when the layer has been displayed
+ virtual void layerDidDisplay(PlatformLayer*) { }
+
+ // For hosting this GraphicsLayer in a native layer hierarchy.
+ virtual PlatformLayer* platformLayer() const { return 0; }
+
+ void dumpLayer(TextStream&, int indent = 0, LayerTreeAsTextBehavior = LayerTreeAsTextBehaviorNormal) const;
+
+ int repaintCount() const { return m_repaintCount; }
+ int incrementRepaintCount() { return ++m_repaintCount; }
+
+ enum CompositingCoordinatesOrientation { CompositingCoordinatesTopDown, CompositingCoordinatesBottomUp };
+
+ // Flippedness of the contents of this layer. Does not affect sublayer geometry.
+ virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; }
+ CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; }
+
+ bool showDebugBorders() const { return m_client ? m_client->showDebugBorders() : false; }
+ bool showRepaintCounter() const { return m_client ? m_client->showRepaintCounter() : false; }
+
+ void updateDebugIndicators();
+
+ virtual void setDebugBackgroundColor(const Color&) { }
+ virtual void setDebugBorder(const Color&, float /*borderWidth*/) { }
+ // z-position is the z-equivalent of position(). It's only used for debugging purposes.
+ virtual float zPosition() const { return m_zPosition; }
+ virtual void setZPosition(float);
+
+ virtual void distributeOpacity(float);
+ virtual float accumulatedOpacity() const;
+
+ // Some compositing systems may do internal batching to synchronize compositing updates
+ // with updates drawn into the window. These methods flush internal batched state on this layer
+ // and descendant layers, and this layer only.
+ virtual void syncCompositingState() { }
+ virtual void syncCompositingStateForThisLayerOnly() { }
+
+ // Return a string with a human readable form of the layer tree, If debug is true
+ // pointers for the layers and timing data will be included in the returned string.
+ String layerTreeAsText(LayerTreeAsTextBehavior = LayerTreeAsTextBehaviorNormal) const;
+
+ bool usingTiledLayer() const { return m_usingTiledLayer; }
+
+protected:
+
+ typedef Vector<TransformOperation::OperationType> TransformOperationList;
+ // Given a list of TransformAnimationValues, return an array of transform operations.
+ // On return, if hasBigRotation is true, functions contain rotations of >= 180 degrees
+ static void fetchTransformOperationList(const KeyframeValueList&, TransformOperationList&, bool& isValid, bool& hasBigRotation);
+
+ virtual void setOpacityInternal(float) { }
+
+ // The layer being replicated.
+ GraphicsLayer* replicatedLayer() const { return m_replicatedLayer; }
+ virtual void setReplicatedLayer(GraphicsLayer* layer) { m_replicatedLayer = layer; }
+
+ GraphicsLayer(GraphicsLayerClient*);
+
+ void dumpProperties(TextStream&, int indent, LayerTreeAsTextBehavior) const;
+
+ GraphicsLayerClient* m_client;
+ String m_name;
+
+ // Offset from the owning renderer
+ IntSize m_offsetFromRenderer;
+
+ // Position is relative to the parent GraphicsLayer
+ FloatPoint m_position;
+ FloatPoint3D m_anchorPoint;
+ FloatSize m_size;
+ TransformationMatrix m_transform;
+ TransformationMatrix m_childrenTransform;
+
+ Color m_backgroundColor;
+ float m_opacity;
+ float m_zPosition;
+
+ bool m_backgroundColorSet : 1;
+ bool m_contentsOpaque : 1;
+ bool m_preserves3D: 1;
+ bool m_backfaceVisibility : 1;
+ bool m_usingTiledLayer : 1;
+ bool m_masksToBounds : 1;
+ bool m_drawsContent : 1;
+ bool m_acceleratesDrawing : 1;
+
+ GraphicsLayerPaintingPhase m_paintingPhase;
+ CompositingCoordinatesOrientation m_contentsOrientation; // affects orientation of layer contents
+
+ Vector<GraphicsLayer*> m_children;
+ GraphicsLayer* m_parent;
+
+ GraphicsLayer* m_maskLayer; // Reference to mask layer. We don't own this.
+
+ GraphicsLayer* m_replicaLayer; // A layer that replicates this layer. We only allow one, for now.
+ // The replica is not parented; this is the primary reference to it.
+ GraphicsLayer* m_replicatedLayer; // For a replica layer, a reference to the original layer.
+ FloatPoint m_replicatedLayerPosition; // For a replica layer, the position of the replica.
+
+ IntRect m_contentsRect;
+
+ int m_repaintCount;
+};
+
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer);
+#endif
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayer_h
+
diff --git a/Source/WebCore/platform/graphics/GraphicsLayerClient.h b/Source/WebCore/platform/graphics/GraphicsLayerClient.h
new file mode 100644
index 0000000..afb297d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GraphicsLayerClient.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 GraphicsLayerClient_h
+#define GraphicsLayerClient_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+namespace WebCore {
+
+class GraphicsContext;
+class GraphicsLayer;
+class IntPoint;
+class IntRect;
+class FloatPoint;
+
+enum GraphicsLayerPaintingPhase {
+ GraphicsLayerPaintBackground = (1 << 0),
+ GraphicsLayerPaintForeground = (1 << 1),
+ GraphicsLayerPaintMask = (1 << 2),
+ GraphicsLayerPaintAll = (GraphicsLayerPaintBackground | GraphicsLayerPaintForeground | GraphicsLayerPaintMask)
+};
+
+enum AnimatedPropertyID {
+ AnimatedPropertyInvalid,
+ AnimatedPropertyWebkitTransform,
+ AnimatedPropertyOpacity,
+ AnimatedPropertyBackgroundColor
+};
+
+class GraphicsLayerClient {
+public:
+ virtual ~GraphicsLayerClient() {}
+
+ // Callback for when hardware-accelerated animation started.
+ virtual void notifyAnimationStarted(const GraphicsLayer*, double time) = 0;
+
+ // Notification that a layer property changed that requires a subsequent call to syncCompositingState()
+ // to appear on the screen.
+ virtual void notifySyncRequired(const GraphicsLayer*) = 0;
+
+ virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) = 0;
+
+ virtual bool showDebugBorders() const = 0;
+ virtual bool showRepaintCounter() const = 0;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayerClient_h
diff --git a/Source/WebCore/platform/graphics/GraphicsTypes.cpp b/Source/WebCore/platform/graphics/GraphicsTypes.cpp
new file mode 100644
index 0000000..dd52ba9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GraphicsTypes.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GraphicsTypes.h"
+
+#include "PlatformString.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+static const char* const compositeOperatorNames[] = {
+ "clear",
+ "copy",
+ "source-over",
+ "source-in",
+ "source-out",
+ "source-atop",
+ "destination-over",
+ "destination-in",
+ "destination-out",
+ "destination-atop",
+ "xor",
+ "darker",
+ "highlight",
+ "lighter"
+};
+const int numCompositeOperatorNames = WTF_ARRAY_LENGTH(compositeOperatorNames);
+
+bool parseCompositeOperator(const String& s, CompositeOperator& op)
+{
+ for (int i = 0; i < numCompositeOperatorNames; i++)
+ if (s == compositeOperatorNames[i]) {
+ op = static_cast<CompositeOperator>(i);
+ return true;
+ }
+ return false;
+}
+
+String compositeOperatorName(CompositeOperator op)
+{
+ ASSERT(op >= 0);
+ ASSERT(op < numCompositeOperatorNames);
+ return compositeOperatorNames[op];
+}
+
+bool parseLineCap(const String& s, LineCap& cap)
+{
+ if (s == "butt") {
+ cap = ButtCap;
+ return true;
+ }
+ if (s == "round") {
+ cap = RoundCap;
+ return true;
+ }
+ if (s == "square") {
+ cap = SquareCap;
+ return true;
+ }
+ return false;
+}
+
+String lineCapName(LineCap cap)
+{
+ ASSERT(cap >= 0);
+ ASSERT(cap < 3);
+ const char* const names[3] = { "butt", "round", "square" };
+ return names[cap];
+}
+
+bool parseLineJoin(const String& s, LineJoin& join)
+{
+ if (s == "miter") {
+ join = MiterJoin;
+ return true;
+ }
+ if (s == "round") {
+ join = RoundJoin;
+ return true;
+ }
+ if (s == "bevel") {
+ join = BevelJoin;
+ return true;
+ }
+ return false;
+}
+
+String lineJoinName(LineJoin join)
+{
+ ASSERT(join >= 0);
+ ASSERT(join < 3);
+ const char* const names[3] = { "miter", "round", "bevel" };
+ return names[join];
+}
+
+String textAlignName(TextAlign align)
+{
+ ASSERT(align >= 0);
+ ASSERT(align < 5);
+ const char* const names[5] = { "start", "end", "left", "center", "right" };
+ return names[align];
+}
+
+bool parseTextAlign(const String& s, TextAlign& align)
+{
+ if (s == "start") {
+ align = StartTextAlign;
+ return true;
+ }
+ if (s == "end") {
+ align = EndTextAlign;
+ return true;
+ }
+ if (s == "left") {
+ align = LeftTextAlign;
+ return true;
+ }
+ if (s == "center") {
+ align = CenterTextAlign;
+ return true;
+ }
+ if (s == "right") {
+ align = RightTextAlign;
+ return true;
+ }
+ return false;
+}
+
+String textBaselineName(TextBaseline baseline)
+{
+ ASSERT(baseline >= 0);
+ ASSERT(baseline < 6);
+ const char* const names[6] = { "alphabetic", "top", "middle", "bottom", "ideographic", "hanging" };
+ return names[baseline];
+}
+
+bool parseTextBaseline(const String& s, TextBaseline& baseline)
+{
+ if (s == "alphabetic") {
+ baseline = AlphabeticTextBaseline;
+ return true;
+ }
+ if (s == "top") {
+ baseline = TopTextBaseline;
+ return true;
+ }
+ if (s == "middle") {
+ baseline = MiddleTextBaseline;
+ return true;
+ }
+ if (s == "bottom") {
+ baseline = BottomTextBaseline;
+ return true;
+ }
+ if (s == "ideographic") {
+ baseline = IdeographicTextBaseline;
+ return true;
+ }
+ if (s == "hanging") {
+ baseline = HangingTextBaseline;
+ return true;
+ }
+ return false;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/GraphicsTypes.h b/Source/WebCore/platform/graphics/GraphicsTypes.h
new file mode 100644
index 0000000..1e73f25
--- /dev/null
+++ b/Source/WebCore/platform/graphics/GraphicsTypes.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 GraphicsTypes_h
+#define GraphicsTypes_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+ // Note: These constants exactly match the NSCompositeOperator constants of
+ // AppKit on Mac OS X Tiger. If these ever change, we'll need to change the
+ // Mac OS X Tiger platform code to map one to the other.
+ enum CompositeOperator {
+ CompositeClear,
+ CompositeCopy,
+ CompositeSourceOver,
+ CompositeSourceIn,
+ CompositeSourceOut,
+ CompositeSourceAtop,
+ CompositeDestinationOver,
+ CompositeDestinationIn,
+ CompositeDestinationOut,
+ CompositeDestinationAtop,
+ CompositeXOR,
+ CompositePlusDarker,
+ CompositeHighlight,
+ CompositePlusLighter
+ };
+
+ // FIXME: Currently these constants have to match the values used in the SVG
+ // DOM API. That's a mistake. We need to make cut that dependency.
+ enum GradientSpreadMethod {
+ SpreadMethodPad = 1,
+ SpreadMethodReflect = 2,
+ SpreadMethodRepeat = 3
+ };
+
+ enum LineCap { ButtCap, RoundCap, SquareCap };
+
+ enum LineJoin { MiterJoin, RoundJoin, BevelJoin };
+
+ enum HorizontalAlignment { AlignLeft, AlignRight, AlignHCenter };
+
+ enum TextBaseline { AlphabeticTextBaseline, TopTextBaseline, MiddleTextBaseline, BottomTextBaseline, IdeographicTextBaseline, HangingTextBaseline };
+
+ enum TextAlign { StartTextAlign, EndTextAlign, LeftTextAlign, CenterTextAlign, RightTextAlign };
+
+ String compositeOperatorName(CompositeOperator);
+ bool parseCompositeOperator(const String&, CompositeOperator&);
+
+ String lineCapName(LineCap);
+ bool parseLineCap(const String&, LineCap&);
+
+ String lineJoinName(LineJoin);
+ bool parseLineJoin(const String&, LineJoin&);
+
+ String textAlignName(TextAlign);
+ bool parseTextAlign(const String&, TextAlign&);
+
+ String textBaselineName(TextBaseline);
+ bool parseTextBaseline(const String&, TextBaseline&);
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/Icon.h b/Source/WebCore/platform/graphics/Icon.h
new file mode 100644
index 0000000..c83685f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Icon.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Icon_h
+#define Icon_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+#include <wtf/RetainPtr.h>
+#ifdef __OBJC__
+@class NSImage;
+#else
+class NSImage;
+#endif
+#elif PLATFORM(WIN)
+typedef struct HICON__* HICON;
+#elif PLATFORM(QT)
+#include <QIcon>
+#elif PLATFORM(GTK)
+typedef struct _GdkPixbuf GdkPixbuf;
+#elif PLATFORM(EFL)
+typedef struct _Evas_Object Evas_Object;
+#elif PLATFORM(CHROMIUM)
+#include "PlatformIcon.h"
+#endif
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntRect;
+
+class Icon : public RefCounted<Icon> {
+public:
+ static PassRefPtr<Icon> createIconForFiles(const Vector<String>& filenames);
+
+ ~Icon();
+
+ void paint(GraphicsContext*, const IntRect&);
+
+#if PLATFORM(WIN)
+ static PassRefPtr<Icon> create(HICON hIcon) { return adoptRef(new Icon(hIcon)); }
+#endif
+
+private:
+#if PLATFORM(MAC)
+ Icon(NSImage*);
+ RetainPtr<NSImage> m_nsImage;
+#elif PLATFORM(WIN)
+ Icon(HICON);
+ HICON m_hIcon;
+#elif PLATFORM(QT)
+ Icon();
+ QIcon m_icon;
+#elif PLATFORM(GTK)
+ Icon();
+ GdkPixbuf* m_icon;
+#elif PLATFORM(EFL)
+ Icon();
+ Evas_Object* m_icon;
+#elif PLATFORM(CHROMIUM)
+ Icon(const PlatformIcon&);
+ PlatformIcon m_icon;
+#endif
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/Image.cpp b/Source/WebCore/platform/graphics/Image.cpp
new file mode 100644
index 0000000..3096680
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Image.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "MIMETypeRegistry.h"
+#include "SharedBuffer.h"
+#include <math.h>
+#include <wtf/StdLibExtras.h>
+
+#if PLATFORM(CG)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace WebCore {
+
+Image::Image(ImageObserver* observer)
+ : m_imageObserver(observer)
+{
+}
+
+Image::~Image()
+{
+}
+
+Image* Image::nullImage()
+{
+ ASSERT(isMainThread());
+ DEFINE_STATIC_LOCAL(RefPtr<Image>, nullImage, (BitmapImage::create()));;
+ return nullImage.get();
+}
+
+bool Image::supportsType(const String& type)
+{
+ return MIMETypeRegistry::isSupportedImageResourceMIMEType(type);
+}
+
+bool Image::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived)
+{
+ m_data = data;
+ if (!m_data.get())
+ return true;
+
+ int length = m_data->size();
+ if (!length)
+ return true;
+
+ return dataChanged(allDataReceived);
+}
+
+void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ if (color.alpha() <= 0)
+ return;
+
+ CompositeOperator previousOperator = ctxt->compositeOperation();
+ ctxt->setCompositeOperation(!color.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op);
+ ctxt->fillRect(dstRect, color, styleColorSpace);
+ ctxt->setCompositeOperation(previousOperator);
+}
+
+static inline FloatSize calculatePatternScale(const FloatRect& dstRect, const FloatRect& srcRect, Image::TileRule hRule, Image::TileRule vRule)
+{
+ float scaleX = 1.0f, scaleY = 1.0f;
+
+ if (hRule == Image::StretchTile)
+ scaleX = dstRect.width() / srcRect.width();
+ if (vRule == Image::StretchTile)
+ scaleY = dstRect.height() / srcRect.height();
+
+ if (hRule == Image::RepeatTile)
+ scaleX = scaleY;
+ if (vRule == Image::RepeatTile)
+ scaleY = scaleX;
+
+ return FloatSize(scaleX, scaleY);
+}
+
+
+void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+ FloatSize intrinsicTileSize = size();
+ if (hasRelativeWidth())
+ intrinsicTileSize.setWidth(scaledTileSize.width());
+ if (hasRelativeHeight())
+ intrinsicTileSize.setHeight(scaledTileSize.height());
+
+ FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(),
+ scaledTileSize.height() / intrinsicTileSize.height());
+
+ FloatRect oneTileRect;
+ oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width()));
+ oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), scaledTileSize.height()) - scaledTileSize.height(), scaledTileSize.height()));
+ oneTileRect.setSize(scaledTileSize);
+
+ // Check and see if a single draw of the image can cover the entire area we are supposed to tile.
+ if (oneTileRect.contains(destRect)) {
+ FloatRect visibleSrcRect;
+ visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width());
+ visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height());
+ visibleSrcRect.setWidth(destRect.width() / scale.width());
+ visibleSrcRect.setHeight(destRect.height() / scale.height());
+ draw(ctxt, destRect, visibleSrcRect, styleColorSpace, op);
+ return;
+ }
+
+ AffineTransform patternTransform = AffineTransform().scaleNonUniform(scale.width(), scale.height());
+ FloatRect tileRect(FloatPoint(), intrinsicTileSize);
+ drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), styleColorSpace, op, destRect);
+
+ startAnimation();
+}
+
+// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things.
+void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+ // FIXME: We do not support 'round' yet. For now just map it to 'repeat'.
+ if (hRule == RoundTile)
+ hRule = RepeatTile;
+ if (vRule == RoundTile)
+ vRule = RepeatTile;
+
+ FloatSize scale = calculatePatternScale(dstRect, srcRect, hRule, vRule);
+ AffineTransform patternTransform = AffineTransform().scaleNonUniform(scale.width(), scale.height());
+
+ // We want to construct the phase such that the pattern is centered (when stretch is not
+ // set for a particular rule).
+ float hPhase = scale.width() * srcRect.x();
+ float vPhase = scale.height() * srcRect.y();
+ if (hRule == Image::RepeatTile)
+ hPhase -= fmodf(dstRect.width(), scale.width() * srcRect.width()) / 2.0f;
+ if (vRule == Image::RepeatTile)
+ vPhase -= fmodf(dstRect.height(), scale.height() * srcRect.height()) / 2.0f;
+ FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase);
+
+ drawPattern(ctxt, srcRect, patternTransform, patternPhase, styleColorSpace, op, dstRect);
+
+ startAnimation();
+}
+
+
+}
diff --git a/Source/WebCore/platform/graphics/Image.h b/Source/WebCore/platform/graphics/Image.h
new file mode 100644
index 0000000..3c5e7fd
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Image.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 Image_h
+#define Image_h
+
+#include "Color.h"
+#include "ColorSpace.h"
+#include "GraphicsTypes.h"
+#include "ImageSource.h"
+#include "IntRect.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+@class NSImage;
+#else
+class NSImage;
+#endif
+#endif
+
+#if PLATFORM(CG)
+struct CGContext;
+#endif
+
+#if PLATFORM(WIN)
+typedef struct tagSIZE SIZE;
+typedef SIZE* LPSIZE;
+typedef struct HBITMAP__ *HBITMAP;
+#endif
+
+#if PLATFORM(QT)
+#include <QPixmap>
+#endif
+
+#if PLATFORM(GTK)
+typedef struct _GdkPixbuf GdkPixbuf;
+#endif
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatRect;
+class FloatSize;
+class GraphicsContext;
+class SharedBuffer;
+class AffineTransform;
+
+// This class gets notified when an image creates or destroys decoded frames and when it advances animation frames.
+class ImageObserver;
+
+class Image : public RefCounted<Image> {
+ friend class GeneratedImage;
+ friend class GraphicsContext;
+
+public:
+ virtual ~Image();
+
+ static PassRefPtr<Image> create(ImageObserver* = 0);
+ static PassRefPtr<Image> loadPlatformResource(const char* name);
+ static bool supportsType(const String&);
+
+ virtual bool isBitmapImage() const { return false; }
+
+ // Derived classes should override this if they can assure that
+ // the image contains only resources from its own security origin.
+ virtual bool hasSingleSecurityOrigin() const { return false; }
+
+ static Image* nullImage();
+ bool isNull() const { return size().isEmpty(); }
+
+ // These are only used for SVGImage right now
+ virtual void setContainerSize(const IntSize&) { }
+ virtual bool usesContainerSize() const { return false; }
+ virtual bool hasRelativeWidth() const { return false; }
+ virtual bool hasRelativeHeight() const { return false; }
+
+ virtual IntSize size() const = 0;
+ IntRect rect() const { return IntRect(IntPoint(), size()); }
+ int width() const { return size().width(); }
+ int height() const { return size().height(); }
+ virtual bool getHotSpot(IntPoint&) const { return false; }
+
+ bool setData(PassRefPtr<SharedBuffer> data, bool allDataReceived);
+ virtual bool dataChanged(bool /*allDataReceived*/) { return false; }
+
+ virtual String filenameExtension() const { return String(); } // null string if unknown
+
+ virtual void destroyDecodedData(bool destroyAll = true) = 0;
+ virtual unsigned decodedSize() const = 0;
+
+ SharedBuffer* data() { return m_data.get(); }
+
+ // Animation begins whenever someone draws the image, so startAnimation() is not normally called.
+ // It will automatically pause once all observers no longer want to render the image anywhere.
+ virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) { }
+ virtual void stopAnimation() {}
+ virtual void resetAnimation() {}
+
+ // Typically the CachedImage that owns us.
+ ImageObserver* imageObserver() const { return m_imageObserver; }
+
+ enum TileRule { StretchTile, RoundTile, RepeatTile };
+
+ virtual NativeImagePtr nativeImageForCurrentFrame() { return 0; }
+
+#if PLATFORM(MAC)
+ // Accessors for native image formats.
+ virtual NSImage* getNSImage() { return 0; }
+ virtual CFDataRef getTIFFRepresentation() { return 0; }
+#endif
+
+#if PLATFORM(CG)
+ virtual CGImageRef getCGImageRef() { return 0; }
+#endif
+
+#if PLATFORM(WIN)
+ virtual bool getHBITMAP(HBITMAP) { return false; }
+ virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE) { return false; }
+#endif
+
+#if PLATFORM(ANDROID)
+ virtual void setURL(const String& str) {}
+#endif
+
+#if PLATFORM(GTK)
+ virtual GdkPixbuf* getGdkPixbuf() { return 0; }
+ static PassRefPtr<Image> loadPlatformThemeIcon(const char* name, int size);
+#endif
+
+ virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect);
+
+protected:
+ Image(ImageObserver* = 0);
+
+ static void fillWithSolidColor(GraphicsContext*, const FloatRect& dstRect, const Color&, ColorSpace styleColorSpace, CompositeOperator);
+
+ // The ColorSpace parameter will only be used for untagged images.
+#if PLATFORM(WIN)
+ virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator) { }
+#endif
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator) = 0;
+ void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize, ColorSpace styleColorSpace, CompositeOperator);
+ void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator);
+
+ // Supporting tiled drawing
+ virtual bool mayFillWithSolidColor() { return false; }
+ virtual Color solidColor() const { return Color(); }
+
+private:
+ RefPtr<SharedBuffer> m_data; // The encoded raw data for the image.
+ ImageObserver* m_imageObserver;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/ImageBuffer.cpp b/Source/WebCore/platform/graphics/ImageBuffer.cpp
new file mode 100644
index 0000000..4a76be4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ImageBuffer.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#if !PLATFORM(CG)
+
+#include <math.h>
+
+namespace WebCore {
+
+void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace)
+{
+ if (srcColorSpace == dstColorSpace)
+ return;
+
+ // only sRGB <-> linearRGB are supported at the moment
+ if ((srcColorSpace != ColorSpaceLinearRGB && srcColorSpace != ColorSpaceDeviceRGB)
+ || (dstColorSpace != ColorSpaceLinearRGB && dstColorSpace != ColorSpaceDeviceRGB))
+ return;
+
+ if (dstColorSpace == ColorSpaceLinearRGB) {
+ if (m_linearRgbLUT.isEmpty()) {
+ for (unsigned i = 0; i < 256; i++) {
+ float color = i / 255.0f;
+ color = (color <= 0.04045f ? color / 12.92f : pow((color + 0.055f) / 1.055f, 2.4f));
+ color = std::max(0.0f, color);
+ color = std::min(1.0f, color);
+ m_linearRgbLUT.append(static_cast<int>(color * 255));
+ }
+ }
+ platformTransformColorSpace(m_linearRgbLUT);
+ } else if (dstColorSpace == ColorSpaceDeviceRGB) {
+ if (m_deviceRgbLUT.isEmpty()) {
+ for (unsigned i = 0; i < 256; i++) {
+ float color = i / 255.0f;
+ color = (powf(color, 1.0f / 2.4f) * 1.055f) - 0.055f;
+ color = std::max(0.0f, color);
+ color = std::min(1.0f, color);
+ m_deviceRgbLUT.append(static_cast<int>(color * 255));
+ }
+ }
+ platformTransformColorSpace(m_deviceRgbLUT);
+ }
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/ImageBuffer.h b/Source/WebCore/platform/graphics/ImageBuffer.h
new file mode 100644
index 0000000..338e3f8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ImageBuffer.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ImageBuffer_h
+#define ImageBuffer_h
+
+#include "AffineTransform.h"
+#include "ColorSpace.h"
+#include "FloatRect.h"
+#include "Image.h"
+#include "IntSize.h"
+#include "ImageBufferData.h"
+#include <wtf/ByteArray.h>
+#include <wtf/Forward.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+
+#if (PLATFORM(MAC) && PLATFORM(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD))
+#define WTF_USE_IOSURFACE_CANVAS_BACKING_STORE 1
+#endif
+
+namespace WebCore {
+
+ class GraphicsContext;
+ class ImageData;
+ class IntPoint;
+ class IntRect;
+
+ enum Multiply {
+ Premultiplied,
+ Unmultiplied
+ };
+
+ enum RenderingMode {
+ Unaccelerated,
+ Accelerated
+ };
+
+ class ImageBuffer : public Noncopyable {
+ public:
+ // Will return a null pointer on allocation failure.
+ static PassOwnPtr<ImageBuffer> create(const IntSize& size, ColorSpace colorSpace = ColorSpaceDeviceRGB, RenderingMode renderingMode = Unaccelerated)
+ {
+ bool success = false;
+ OwnPtr<ImageBuffer> buf(new ImageBuffer(size, colorSpace, renderingMode, success));
+ if (success)
+ return buf.release();
+ return 0;
+ }
+
+ ~ImageBuffer();
+
+ const IntSize& size() const { return m_size; }
+ int width() const { return m_size.width(); }
+ int height() const { return m_size.height(); }
+
+ GraphicsContext* context() const;
+
+ bool drawsUsingCopy() const; // If the image buffer has to render using a copied image, it will return true.
+ PassRefPtr<Image> copyImage() const; // Return a new image that is a copy of the buffer.
+
+ PassRefPtr<ByteArray> getUnmultipliedImageData(const IntRect&) const;
+ PassRefPtr<ByteArray> getPremultipliedImageData(const IntRect&) const;
+
+ void putUnmultipliedImageData(ByteArray*, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint);
+ void putPremultipliedImageData(ByteArray*, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint);
+
+ String toDataURL(const String& mimeType, const double* quality = 0) const;
+#if !PLATFORM(CG)
+ AffineTransform baseTransform() const { return AffineTransform(); }
+ void transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace);
+ void platformTransformColorSpace(const Vector<int>&);
+#else
+ AffineTransform baseTransform() const { return AffineTransform(1, 0, 0, -1, 0, m_size.height()); }
+#endif
+
+ private:
+ void clip(GraphicsContext*, const FloatRect&) const;
+
+ // The draw method draws the contents of the buffer without copying it.
+ void draw(GraphicsContext*, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1),
+ CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect);
+ friend class GraphicsContext;
+ friend class GeneratedImage;
+
+ private:
+ ImageBufferData m_data;
+
+ IntSize m_size;
+ bool m_accelerateRendering;
+ OwnPtr<GraphicsContext> m_context;
+
+#if !PLATFORM(CG)
+ Vector<int> m_linearRgbLUT;
+ Vector<int> m_deviceRgbLUT;
+#endif
+
+ // This constructor will place its success into the given out-variable
+ // so that create() knows when it should return failure.
+ ImageBuffer(const IntSize&, ColorSpace colorSpace, RenderingMode renderingMode, bool& success);
+ };
+
+} // namespace WebCore
+
+#endif // ImageBuffer_h
diff --git a/Source/WebCore/platform/graphics/ImageObserver.h b/Source/WebCore/platform/graphics/ImageObserver.h
new file mode 100644
index 0000000..8b693d9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ImageObserver.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ImageObserver_h
+#define ImageObserver_h
+
+namespace WebCore {
+
+class Image;
+class IntRect;
+
+// Interface for notification about changes to an image, including decoding,
+// drawing, and animating.
+class ImageObserver {
+protected:
+ virtual ~ImageObserver() {}
+public:
+ virtual void decodedSizeChanged(const Image*, int delta) = 0;
+ virtual void didDraw(const Image*) = 0;
+
+ virtual bool shouldPauseAnimation(const Image*) = 0;
+ virtual void animationAdvanced(const Image*) = 0;
+
+ virtual void changedInRect(const Image*, const IntRect&) = 0;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/ImageSource.cpp b/Source/WebCore/platform/graphics/ImageSource.cpp
new file mode 100644
index 0000000..92553c5
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ImageSource.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
+ * Copyright (C) 2008, Google Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ImageSource.h"
+
+#if PLATFORM(QT)
+#include "ImageDecoderQt.h"
+#else
+#include "ImageDecoder.h"
+#endif
+
+namespace WebCore {
+
+#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
+unsigned ImageSource::s_maxPixelsPerDecodedImage = 1024 * 1024;
+#endif
+
+ImageSource::ImageSource(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
+ : m_decoder(0)
+ , m_alphaOption(alphaOption)
+ , m_gammaAndColorProfileOption(gammaAndColorProfileOption)
+{
+}
+
+ImageSource::~ImageSource()
+{
+ clear(true);
+}
+
+void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
+{
+ if (!destroyAll) {
+ if (m_decoder)
+ m_decoder->clearFrameBufferCache(clearBeforeFrame);
+ return;
+ }
+
+ delete m_decoder;
+ m_decoder = 0;
+ if (data)
+ setData(data, allDataReceived);
+}
+
+bool ImageSource::initialized() const
+{
+ return m_decoder;
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+ // Make the decoder by sniffing the bytes.
+ // This method will examine the data and instantiate an instance of the appropriate decoder plugin.
+ // If insufficient bytes are available to determine the image type, no decoder plugin will be
+ // made.
+ if (!m_decoder) {
+ m_decoder = static_cast<NativeImageSourcePtr>(ImageDecoder::create(*data, m_alphaOption, m_gammaAndColorProfileOption));
+#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
+ if (m_decoder && s_maxPixelsPerDecodedImage)
+ m_decoder->setMaxNumPixels(s_maxPixelsPerDecodedImage);
+#endif
+ }
+
+ if (m_decoder)
+ m_decoder->setData(data, allDataReceived);
+}
+
+String ImageSource::filenameExtension() const
+{
+ return m_decoder ? m_decoder->filenameExtension() : String();
+}
+
+bool ImageSource::isSizeAvailable()
+{
+ return m_decoder && m_decoder->isSizeAvailable();
+}
+
+IntSize ImageSource::size() const
+{
+ return m_decoder ? m_decoder->size() : IntSize();
+}
+
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
+{
+ return m_decoder ? m_decoder->frameSizeAtIndex(index) : IntSize();
+}
+
+bool ImageSource::getHotSpot(IntPoint&) const
+{
+ return false;
+}
+
+int ImageSource::repetitionCount()
+{
+ return m_decoder ? m_decoder->repetitionCount() : cAnimationNone;
+}
+
+size_t ImageSource::frameCount() const
+{
+ return m_decoder ? m_decoder->frameCount() : 0;
+}
+
+NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
+{
+ if (!m_decoder)
+ return 0;
+
+ RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ return 0;
+
+ // Zero-height images can cause problems for some ports. If we have an
+ // empty image dimension, just bail.
+ if (size().isEmpty())
+ return 0;
+
+ // Return the buffer contents as a native image. For some ports, the data
+ // is already in a native container, and this just increments its refcount.
+ return buffer->asNewNativeImage();
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ if (!m_decoder)
+ return 0;
+
+ RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ return 0;
+
+ // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
+ // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
+ // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
+ // for more information.
+ const float duration = buffer->duration() / 1000.0f;
+ if (duration < 0.011f)
+ return 0.100f;
+ return duration;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t index)
+{
+ // When a frame has not finished decoding, always mark it as having alpha.
+ // Ports that check the result of this function to determine their
+ // compositing op need this in order to not draw the undecoded portion as
+ // black.
+ // TODO: Perhaps we should ensure that each individual decoder returns true
+ // in this case.
+ return !frameIsCompleteAtIndex(index)
+ || m_decoder->frameBufferAtIndex(index)->hasAlpha();
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ if (!m_decoder)
+ return false;
+
+ RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
+ return buffer && buffer->status() == RGBA32Buffer::FrameComplete;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/ImageSource.h b/Source/WebCore/platform/graphics/ImageSource.h
new file mode 100644
index 0000000..29c1be3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ImageSource.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ImageSource_h
+#define ImageSource_h
+
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(WX)
+class wxBitmap;
+class wxGraphicsBitmap;
+#elif PLATFORM(CG)
+typedef struct CGImageSource* CGImageSourceRef;
+typedef struct CGImage* CGImageRef;
+typedef const struct __CFData* CFDataRef;
+#elif PLATFORM(QT)
+#include <qglobal.h>
+QT_BEGIN_NAMESPACE
+class QPixmap;
+QT_END_NAMESPACE
+#elif PLATFORM(CAIRO)
+struct _cairo_surface;
+typedef struct _cairo_surface cairo_surface_t;
+#elif PLATFORM(SKIA)
+#if PLATFORM(ANDROID)
+#include "SkString.h"
+class SkBitmapRef;
+class PrivateAndroidImageSourceRec;
+#else
+namespace WebCore {
+class NativeImageSkia;
+}
+#endif
+#elif PLATFORM(HAIKU)
+class BBitmap;
+#elif OS(WINCE)
+#include "SharedBitmap.h"
+#endif
+
+namespace WebCore {
+
+class IntPoint;
+class IntSize;
+class SharedBuffer;
+
+#if PLATFORM(CG)
+#if USE(WEBKIT_IMAGE_DECODERS)
+class ImageDecoder;
+typedef ImageDecoder* NativeImageSourcePtr;
+#else
+typedef CGImageSourceRef NativeImageSourcePtr;
+#endif
+typedef CGImageRef NativeImagePtr;
+#elif PLATFORM(OPENVG)
+class ImageDecoder;
+class TiledImageOpenVG;
+typedef ImageDecoder* NativeImageSourcePtr;
+typedef TiledImageOpenVG* NativeImagePtr;
+#elif PLATFORM(QT)
+class ImageDecoderQt;
+typedef ImageDecoderQt* NativeImageSourcePtr;
+typedef QPixmap* NativeImagePtr;
+#elif PLATFORM(SKIA) && PLATFORM(ANDROID)
+#ifdef ANDROID_ANIMATED_GIF
+class ImageDecoder;
+#endif
+struct NativeImageSourcePtr {
+ SkString m_url;
+ PrivateAndroidImageSourceRec* m_image;
+#ifdef ANDROID_ANIMATED_GIF
+ ImageDecoder* m_gifDecoder;
+#endif
+};
+typedef const Vector<char>* NativeBytePtr;
+typedef SkBitmapRef* NativeImagePtr;
+#else
+class ImageDecoder;
+typedef ImageDecoder* NativeImageSourcePtr;
+#if PLATFORM(WX)
+#if USE(WXGC)
+typedef wxGraphicsBitmap* NativeImagePtr;
+#else
+typedef wxBitmap* NativeImagePtr;
+#endif
+#elif PLATFORM(CAIRO)
+typedef cairo_surface_t* NativeImagePtr;
+#elif PLATFORM(SKIA)
+typedef WebCore::NativeImageSkia* NativeImagePtr;
+#elif PLATFORM(HAIKU)
+typedef BBitmap* NativeImagePtr;
+#elif OS(WINCE)
+typedef RefPtr<SharedBitmap> NativeImagePtr;
+#endif
+#endif
+
+// Right now GIFs are the only recognized image format that supports animation.
+// The animation system and the constants below are designed with this in mind.
+// GIFs have an optional 16-bit unsigned loop count that describes how an
+// animated GIF should be cycled. If the loop count is absent, the animation
+// cycles once; if it is 0, the animation cycles infinitely; otherwise the
+// animation plays n + 1 cycles (where n is the specified loop count). If the
+// GIF decoder defaults to cAnimationLoopOnce in the absence of any loop count
+// and translates an explicit "0" loop count to cAnimationLoopInfinite, then we
+// get a couple of nice side effects:
+// * By making cAnimationLoopOnce be 0, we allow the animation cycling code in
+// BitmapImage.cpp to avoid special-casing it, and simply treat all
+// non-negative loop counts identically.
+// * By making the other two constants negative, we avoid conflicts with any
+// real loop count values.
+const int cAnimationLoopOnce = 0;
+const int cAnimationLoopInfinite = -1;
+const int cAnimationNone = -2;
+
+class ImageSource : public Noncopyable {
+public:
+ enum AlphaOption {
+ AlphaPremultiplied,
+ AlphaNotPremultiplied
+ };
+
+ enum GammaAndColorProfileOption {
+ GammaAndColorProfileApplied,
+ GammaAndColorProfileIgnored
+ };
+
+ ImageSource(AlphaOption alphaOption = AlphaPremultiplied, GammaAndColorProfileOption gammaAndColorProfileOption = GammaAndColorProfileApplied);
+ ~ImageSource();
+
+ // Tells the ImageSource that the Image no longer cares about decoded frame
+ // data -- at all (if |destroyAll| is true), or before frame
+ // |clearBeforeFrame| (if |destroyAll| is false). The ImageSource should
+ // delete cached decoded data for these frames where possible to keep memory
+ // usage low. When |destroyAll| is true, the ImageSource should also reset
+ // any local state so that decoding can begin again.
+ //
+ // Implementations that delete less than what's specified above waste
+ // memory. Implementations that delete more may burn CPU re-decoding frames
+ // that could otherwise have been cached, or encounter errors if they're
+ // asked to decode frames they can't decode due to the loss of previous
+ // decoded frames.
+ //
+ // Callers should not call clear(false, n) and subsequently call
+ // createFrameAtIndex(m) with m < n, unless they first call clear(true).
+ // This ensures that stateful ImageSources/decoders will work properly.
+ //
+ // The |data| and |allDataReceived| parameters should be supplied by callers
+ // who set |destroyAll| to true if they wish to be able to continue using
+ // the ImageSource. This way implementations which choose to destroy their
+ // decoders in some cases can reconstruct them correctly.
+ void clear(bool destroyAll,
+ size_t clearBeforeFrame = 0,
+ SharedBuffer* data = NULL,
+ bool allDataReceived = false);
+
+ bool initialized() const;
+
+ void setData(SharedBuffer* data, bool allDataReceived);
+ String filenameExtension() const;
+
+ bool isSizeAvailable();
+ IntSize size() const;
+ IntSize frameSizeAtIndex(size_t) const;
+ bool getHotSpot(IntPoint&) const;
+
+ int repetitionCount();
+
+ size_t frameCount() const;
+
+ // Callers should not call this after calling clear() with a higher index;
+ // see comments on clear() above.
+ NativeImagePtr createFrameAtIndex(size_t);
+
+ float frameDurationAtIndex(size_t);
+ bool frameHasAlphaAtIndex(size_t); // Whether or not the frame actually used any alpha.
+ bool frameIsCompleteAtIndex(size_t); // Whether or not the frame is completely decoded.
+
+#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
+ static unsigned maxPixelsPerDecodedImage() { return s_maxPixelsPerDecodedImage; }
+ static void setMaxPixelsPerDecodedImage(unsigned maxPixels) { s_maxPixelsPerDecodedImage = maxPixels; }
+#endif
+
+#if PLATFORM(ANDROID)
+ void clearURL();
+ void setURL(const String& url);
+#endif
+
+private:
+#if PLATFORM(ANDROID)
+ // FIXME: This is protected only to allow ImageSourceSkia to set ICO decoder
+ // with a preferred size. See ImageSourceSkia.h for discussion.
+protected:
+#endif
+ NativeImageSourcePtr m_decoder;
+ AlphaOption m_alphaOption;
+ GammaAndColorProfileOption m_gammaAndColorProfileOption;
+#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
+ static unsigned s_maxPixelsPerDecodedImage;
+#endif
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/IntPoint.h b/Source/WebCore/platform/graphics/IntPoint.h
new file mode 100644
index 0000000..cd5e4d4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/IntPoint.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 IntPoint_h
+#define IntPoint_h
+
+#include "IntSize.h"
+
+#if PLATFORM(QT)
+#include <QDataStream>
+#endif
+
+#if PLATFORM(CG)
+typedef struct CGPoint CGPoint;
+#endif
+
+
+#if PLATFORM(MAC)
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGPoint NSPoint;
+#else
+typedef struct _NSPoint NSPoint;
+#endif
+#endif
+
+#if PLATFORM(WIN)
+typedef struct tagPOINT POINT;
+typedef struct tagPOINTS POINTS;
+#elif PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QPoint;
+QT_END_NAMESPACE
+#elif PLATFORM(GTK)
+typedef struct _GdkPoint GdkPoint;
+#elif PLATFORM(HAIKU)
+class BPoint;
+#elif PLATFORM(EFL)
+typedef struct _Evas_Point Evas_Point;
+#endif
+
+#if PLATFORM(WX)
+class wxPoint;
+#endif
+
+#if PLATFORM(BREWMP)
+typedef struct _point AEEPoint;
+#endif
+
+#if PLATFORM(SKIA)
+struct SkPoint;
+struct SkIPoint;
+#endif
+
+namespace WebCore {
+
+class IntPoint {
+public:
+ IntPoint() : m_x(0), m_y(0) { }
+ IntPoint(int x, int y) : m_x(x), m_y(y) { }
+ explicit IntPoint(const IntSize& size) : m_x(size.width()), m_y(size.height()) { }
+
+ static IntPoint zero() { return IntPoint(); }
+
+ int x() const { return m_x; }
+ int y() const { return m_y; }
+
+ void setX(int x) { m_x = x; }
+ void setY(int y) { m_y = y; }
+
+ void move(const IntSize& s) { move(s.width(), s.height()); }
+ void move(int dx, int dy) { m_x += dx; m_y += dy; }
+
+ IntPoint expandedTo(const IntPoint& other) const
+ {
+ return IntPoint(m_x > other.m_x ? m_x : other.m_x,
+ m_y > other.m_y ? m_y : other.m_y);
+ }
+
+ IntPoint shrunkTo(const IntPoint& other) const
+ {
+ return IntPoint(m_x < other.m_x ? m_x : other.m_x,
+ m_y < other.m_y ? m_y : other.m_y);
+ }
+
+ void clampNegativeToZero()
+ {
+ *this = expandedTo(zero());
+ }
+
+ IntPoint transposedPoint() const
+ {
+ return IntPoint(m_y, m_x);
+ }
+
+#if PLATFORM(CG)
+ explicit IntPoint(const CGPoint&); // don't do this implicitly since it's lossy
+ operator CGPoint() const;
+#endif
+
+#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
+ explicit IntPoint(const NSPoint&); // don't do this implicitly since it's lossy
+ operator NSPoint() const;
+#endif
+
+#if PLATFORM(WIN)
+ IntPoint(const POINT&);
+ operator POINT() const;
+ IntPoint(const POINTS&);
+ operator POINTS() const;
+#elif PLATFORM(QT)
+ IntPoint(const QPoint&);
+ operator QPoint() const;
+#elif PLATFORM(GTK)
+ IntPoint(const GdkPoint&);
+ operator GdkPoint() const;
+#elif PLATFORM(HAIKU)
+ explicit IntPoint(const BPoint&);
+ operator BPoint() const;
+#elif PLATFORM(EFL)
+ explicit IntPoint(const Evas_Point&);
+ operator Evas_Point() const;
+#endif
+
+#if PLATFORM(WX)
+ IntPoint(const wxPoint&);
+ operator wxPoint() const;
+#endif
+
+#if PLATFORM(BREWMP)
+ IntPoint(const AEEPoint&);
+ operator AEEPoint() const;
+#endif
+
+#if PLATFORM(SKIA)
+ IntPoint(const SkIPoint&);
+ operator SkIPoint() const;
+ operator SkPoint() const;
+#endif
+
+private:
+ int m_x, m_y;
+};
+
+inline IntPoint& operator+=(IntPoint& a, const IntSize& b)
+{
+ a.move(b.width(), b.height());
+ return a;
+}
+
+inline IntPoint& operator-=(IntPoint& a, const IntSize& b)
+{
+ a.move(-b.width(), -b.height());
+ return a;
+}
+
+inline IntPoint operator+(const IntPoint& a, const IntSize& b)
+{
+ return IntPoint(a.x() + b.width(), a.y() + b.height());
+}
+
+inline IntSize operator-(const IntPoint& a, const IntPoint& b)
+{
+ return IntSize(a.x() - b.x(), a.y() - b.y());
+}
+
+inline IntPoint operator-(const IntPoint& a, const IntSize& b)
+{
+ return IntPoint(a.x() - b.width(), a.y() - b.height());
+}
+
+inline bool operator==(const IntPoint& a, const IntPoint& b)
+{
+ return a.x() == b.x() && a.y() == b.y();
+}
+
+inline bool operator!=(const IntPoint& a, const IntPoint& b)
+{
+ return a.x() != b.x() || a.y() != b.y();
+}
+
+inline IntPoint toPoint(const IntSize& size)
+{
+ return IntPoint(size.width(), size.height());
+}
+
+#if PLATFORM(QT)
+inline QDataStream& operator<<(QDataStream& stream, const IntPoint& point)
+{
+ stream << point.x() << point.y();
+ return stream;
+}
+
+inline QDataStream& operator>>(QDataStream& stream, IntPoint& point)
+{
+ int x, y;
+ stream >> x >> y;
+ point.setX(x);
+ point.setY(y);
+ return stream;
+}
+#endif
+
+} // namespace WebCore
+
+#endif // IntPoint_h
diff --git a/Source/WebCore/platform/graphics/IntPointHash.h b/Source/WebCore/platform/graphics/IntPointHash.h
new file mode 100644
index 0000000..bf25b14
--- /dev/null
+++ b/Source/WebCore/platform/graphics/IntPointHash.h
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef IntPointHash_h
+#define IntPointHash_h
+
+#include "IntPoint.h"
+#include <wtf/HashFunctions.h>
+#include <wtf/HashTraits.h>
+
+namespace WTF {
+
+// The empty value is (0, INT_MIN), the deleted value is (INT_MIN, 0)
+struct IntPointHash {
+ static unsigned hash(const WebCore::IntPoint& p) { return WTF::intHash(static_cast<uint64_t>(p.x()) << 32 | p.y()); }
+ static bool equal(const WebCore::IntPoint& a, const WebCore::IntPoint& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+template<> struct HashTraits<WebCore::IntPoint> : GenericHashTraits<WebCore::IntPoint> {
+ static const bool needsDestruction = false;
+ static WebCore::IntPoint emptyValue() { return WebCore::IntPoint(0, std::numeric_limits<int>::min()); }
+
+ static void constructDeletedValue(WebCore::IntPoint& slot) { slot = WebCore::IntPoint(std::numeric_limits<int>::min(), 0); }
+ static bool isDeletedValue(const WebCore::IntPoint& slot) { return slot == WebCore::IntPoint(std::numeric_limits<int>::min(), 0); }
+};
+template<> struct DefaultHash<WebCore::IntPoint> {
+ typedef IntPointHash Hash;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/IntRect.cpp b/Source/WebCore/platform/graphics/IntRect.cpp
new file mode 100644
index 0000000..188b5f9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/IntRect.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2003, 2006, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include "FloatRect.h"
+#include <algorithm>
+
+using std::max;
+using std::min;
+
+namespace WebCore {
+
+IntRect::IntRect(const FloatRect& r)
+ : m_location(IntPoint(static_cast<int>(r.x()), static_cast<int>(r.y())))
+ , m_size(IntSize(static_cast<int>(r.width()), static_cast<int>(r.height())))
+{
+}
+
+bool IntRect::intersects(const IntRect& other) const
+{
+ // Checking emptiness handles negative widths as well as zero.
+ return !isEmpty() && !other.isEmpty()
+ && x() < other.right() && other.x() < right()
+ && y() < other.bottom() && other.y() < bottom();
+}
+
+bool IntRect::contains(const IntRect& other) const
+{
+ return x() <= other.x() && right() >= other.right()
+ && y() <= other.y() && bottom() >= other.bottom();
+}
+
+void IntRect::intersect(const IntRect& other)
+{
+ int l = max(x(), other.x());
+ int t = max(y(), other.y());
+ int r = min(right(), other.right());
+ int b = min(bottom(), other.bottom());
+
+ // Return a clean empty rectangle for non-intersecting cases.
+ if (l >= r || t >= b) {
+ l = 0;
+ t = 0;
+ r = 0;
+ b = 0;
+ }
+
+ m_location.setX(l);
+ m_location.setY(t);
+ m_size.setWidth(r - l);
+ m_size.setHeight(b - t);
+}
+
+void IntRect::unite(const IntRect& other)
+{
+ // Handle empty special cases first.
+ if (other.isEmpty())
+ return;
+ if (isEmpty()) {
+ *this = other;
+ return;
+ }
+
+ int l = min(x(), other.x());
+ int t = min(y(), other.y());
+ int r = max(right(), other.right());
+ int b = max(bottom(), other.bottom());
+
+ m_location.setX(l);
+ m_location.setY(t);
+ m_size.setWidth(r - l);
+ m_size.setHeight(b - t);
+}
+
+void IntRect::scale(float s)
+{
+ m_location.setX((int)(x() * s));
+ m_location.setY((int)(y() * s));
+ m_size.setWidth((int)(width() * s));
+ m_size.setHeight((int)(height() * s));
+}
+
+IntRect unionRect(const Vector<IntRect>& rects)
+{
+ IntRect result;
+
+ size_t count = rects.size();
+ for (size_t i = 0; i < count; ++i)
+ result.unite(rects[i]);
+
+ return result;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/IntRect.h b/Source/WebCore/platform/graphics/IntRect.h
new file mode 100644
index 0000000..638db75
--- /dev/null
+++ b/Source/WebCore/platform/graphics/IntRect.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2003, 2006, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 IntRect_h
+#define IntRect_h
+
+#include "IntPoint.h"
+#include <wtf/Vector.h>
+
+#if PLATFORM(CG)
+typedef struct CGRect CGRect;
+#endif
+
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGRect NSRect;
+#else
+typedef struct _NSRect NSRect;
+#endif
+#endif
+
+#if PLATFORM(WIN)
+typedef struct tagRECT RECT;
+#elif PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QRect;
+QT_END_NAMESPACE
+#elif PLATFORM(GTK)
+#ifdef GTK_API_VERSION_2
+typedef struct _GdkRectangle GdkRectangle;
+#else
+typedef struct _cairo_rectangle_int cairo_rectangle_int_t;
+typedef cairo_rectangle_int_t GdkRectangle;
+#endif
+#elif PLATFORM(HAIKU)
+class BRect;
+#elif PLATFORM(EFL)
+typedef struct _Eina_Rectangle Eina_Rectangle;
+#endif
+
+#if PLATFORM(WX)
+class wxRect;
+#endif
+
+#if PLATFORM(SKIA)
+struct SkRect;
+struct SkIRect;
+#endif
+
+namespace WebCore {
+
+class FloatRect;
+
+class IntRect {
+public:
+ IntRect() { }
+ IntRect(const IntPoint& location, const IntSize& size)
+ : m_location(location), m_size(size) { }
+ IntRect(int x, int y, int width, int height)
+ : m_location(IntPoint(x, y)), m_size(IntSize(width, height)) { }
+
+ explicit IntRect(const FloatRect& rect); // don't do this implicitly since it's lossy
+
+ IntPoint location() const { return m_location; }
+ IntSize size() const { return m_size; }
+
+ void setLocation(const IntPoint& location) { m_location = location; }
+ void setSize(const IntSize& size) { m_size = size; }
+
+ int x() const { return m_location.x(); }
+ int y() const { return m_location.y(); }
+ int width() const { return m_size.width(); }
+ int height() const { return m_size.height(); }
+
+ void setX(int x) { m_location.setX(x); }
+ void setY(int y) { m_location.setY(y); }
+ void setWidth(int width) { m_size.setWidth(width); }
+ void setHeight(int height) { m_size.setHeight(height); }
+
+ // Be careful with these functions. The point is considered to be to the right and below. These are not
+ // substitutes for right() and bottom().
+ IntPoint topLeft() const { return m_location; }
+ IntPoint topRight() const { return IntPoint(right() - 1, y()); }
+ IntPoint bottomLeft() const { return IntPoint(x(), bottom() - 1); }
+ IntPoint bottomRight() const { return IntPoint(right() - 1, bottom() - 1); }
+
+ bool isEmpty() const { return m_size.isEmpty(); }
+
+ int right() const { return x() + width(); }
+ int bottom() const { return y() + height(); }
+
+ // NOTE: The result is rounded to integer values, and thus may be not the exact
+ // center point.
+ IntPoint center() const { return IntPoint(x() + width() / 2, y() + height() / 2); }
+
+ void move(const IntSize& s) { m_location += s; }
+ void move(int dx, int dy) { m_location.move(dx, dy); }
+
+ void shiftLeftEdgeTo(int edge)
+ {
+ int delta = edge - x();
+ setX(edge);
+ setWidth(std::max(0, width() - delta));
+ }
+ void shiftRightEdgeTo(int edge)
+ {
+ int delta = edge - right();
+ setWidth(std::max(0, width() + delta));
+ }
+ void shiftTopEdgeTo(int edge)
+ {
+ int delta = edge - y();
+ setY(edge);
+ setHeight(std::max(0, height() - delta));
+ }
+ void shiftBottomEdgeTo(int edge)
+ {
+ int delta = edge - bottom();
+ setHeight(std::max(0, height() + delta));
+ }
+
+ bool intersects(const IntRect&) const;
+ bool contains(const IntRect&) const;
+
+ // This checks to see if the rect contains x,y in the traditional sense.
+ // Equivalent to checking if the rect contains a 1x1 rect below and to the right of (px,py).
+ bool contains(int px, int py) const
+ { return px >= x() && px < right() && py >= y() && py < bottom(); }
+ bool contains(const IntPoint& point) const { return contains(point.x(), point.y()); }
+
+ void intersect(const IntRect&);
+ void unite(const IntRect&);
+
+ void inflateX(int dx)
+ {
+ m_location.setX(m_location.x() - dx);
+ m_size.setWidth(m_size.width() + dx + dx);
+ }
+ void inflateY(int dy)
+ {
+ m_location.setY(m_location.y() - dy);
+ m_size.setHeight(m_size.height() + dy + dy);
+ }
+ void inflate(int d) { inflateX(d); inflateY(d); }
+ void scale(float s);
+
+ IntRect transposedRect() const { return IntRect(m_location.transposedPoint(), m_size.transposedSize()); }
+
+#if PLATFORM(WX)
+ IntRect(const wxRect&);
+ operator wxRect() const;
+#endif
+
+#if PLATFORM(WIN)
+ IntRect(const RECT&);
+ operator RECT() const;
+#elif PLATFORM(QT)
+ IntRect(const QRect&);
+ operator QRect() const;
+#elif PLATFORM(GTK)
+ IntRect(const GdkRectangle&);
+ operator GdkRectangle() const;
+#elif PLATFORM(HAIKU)
+ explicit IntRect(const BRect&);
+ operator BRect() const;
+#elif PLATFORM(EFL)
+ explicit IntRect(const Eina_Rectangle&);
+ operator Eina_Rectangle() const;
+#endif
+
+#if PLATFORM(CG)
+ operator CGRect() const;
+#endif
+
+#if PLATFORM(SKIA)
+ IntRect(const SkIRect&);
+ operator SkRect() const;
+ operator SkIRect() const;
+#endif
+
+#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
+ operator NSRect() const;
+#endif
+
+private:
+ IntPoint m_location;
+ IntSize m_size;
+};
+
+inline IntRect intersection(const IntRect& a, const IntRect& b)
+{
+ IntRect c = a;
+ c.intersect(b);
+ return c;
+}
+
+inline IntRect unionRect(const IntRect& a, const IntRect& b)
+{
+ IntRect c = a;
+ c.unite(b);
+ return c;
+}
+
+IntRect unionRect(const Vector<IntRect>&);
+
+inline bool operator==(const IntRect& a, const IntRect& b)
+{
+ return a.location() == b.location() && a.size() == b.size();
+}
+
+inline bool operator!=(const IntRect& a, const IntRect& b)
+{
+ return a.location() != b.location() || a.size() != b.size();
+}
+
+#if PLATFORM(CG)
+IntRect enclosingIntRect(const CGRect&);
+#endif
+
+#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
+IntRect enclosingIntRect(const NSRect&);
+#endif
+
+} // namespace WebCore
+
+#endif // IntRect_h
diff --git a/Source/WebCore/platform/graphics/IntSize.h b/Source/WebCore/platform/graphics/IntSize.h
new file mode 100644
index 0000000..9db2224
--- /dev/null
+++ b/Source/WebCore/platform/graphics/IntSize.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 IntSize_h
+#define IntSize_h
+
+#if PLATFORM(CG)
+typedef struct CGSize CGSize;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGSize NSSize;
+#else
+typedef struct _NSSize NSSize;
+#endif
+#endif
+
+#if PLATFORM(WIN)
+typedef struct tagSIZE SIZE;
+#elif PLATFORM(QT)
+#include <qglobal.h>
+QT_BEGIN_NAMESPACE
+class QSize;
+QT_END_NAMESPACE
+#elif PLATFORM(HAIKU)
+class BSize;
+#endif
+
+#if PLATFORM(WX)
+class wxSize;
+#endif
+
+#if PLATFORM(BREWMP)
+typedef struct AEESize AEESize;
+#endif
+
+namespace WebCore {
+
+class IntSize {
+public:
+ IntSize() : m_width(0), m_height(0) { }
+ IntSize(int width, int height) : m_width(width), m_height(height) { }
+
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+
+ void setWidth(int width) { m_width = width; }
+ void setHeight(int height) { m_height = height; }
+
+ bool isEmpty() const { return m_width <= 0 || m_height <= 0; }
+ bool isZero() const { return !m_width && !m_height; }
+
+ float aspectRatio() const { return static_cast<float>(m_width) / static_cast<float>(m_height); }
+
+ void expand(int width, int height)
+ {
+ m_width += width;
+ m_height += height;
+ }
+
+ void scale(float scale)
+ {
+ m_width = static_cast<int>(static_cast<float>(m_width) * scale);
+ m_height = static_cast<int>(static_cast<float>(m_height) * scale);
+ }
+
+ IntSize expandedTo(const IntSize& other) const
+ {
+ return IntSize(m_width > other.m_width ? m_width : other.m_width,
+ m_height > other.m_height ? m_height : other.m_height);
+ }
+
+ IntSize shrunkTo(const IntSize& other) const
+ {
+ return IntSize(m_width < other.m_width ? m_width : other.m_width,
+ m_height < other.m_height ? m_height : other.m_height);
+ }
+
+ void clampNegativeToZero()
+ {
+ *this = expandedTo(IntSize());
+ }
+
+ IntSize transposedSize() const
+ {
+ return IntSize(m_height, m_width);
+ }
+
+#if PLATFORM(CG)
+ explicit IntSize(const CGSize&); // don't do this implicitly since it's lossy
+ operator CGSize() const;
+#endif
+
+#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
+ explicit IntSize(const NSSize &); // don't do this implicitly since it's lossy
+ operator NSSize() const;
+#endif
+
+#if PLATFORM(WIN)
+ IntSize(const SIZE&);
+ operator SIZE() const;
+#endif
+
+#if PLATFORM(QT)
+ IntSize(const QSize&);
+ operator QSize() const;
+#endif
+
+#if PLATFORM(HAIKU)
+ explicit IntSize(const BSize&);
+ operator BSize() const;
+#endif
+
+#if PLATFORM(WX)
+ IntSize(const wxSize&);
+ operator wxSize() const;
+#endif
+
+#if PLATFORM(BREWMP)
+ IntSize(const AEESize&);
+ operator AEESize() const;
+#endif
+
+private:
+ int m_width, m_height;
+};
+
+inline IntSize& operator+=(IntSize& a, const IntSize& b)
+{
+ a.setWidth(a.width() + b.width());
+ a.setHeight(a.height() + b.height());
+ return a;
+}
+
+inline IntSize& operator-=(IntSize& a, const IntSize& b)
+{
+ a.setWidth(a.width() - b.width());
+ a.setHeight(a.height() - b.height());
+ return a;
+}
+
+inline IntSize operator+(const IntSize& a, const IntSize& b)
+{
+ return IntSize(a.width() + b.width(), a.height() + b.height());
+}
+
+inline IntSize operator-(const IntSize& a, const IntSize& b)
+{
+ return IntSize(a.width() - b.width(), a.height() - b.height());
+}
+
+inline IntSize operator-(const IntSize& size)
+{
+ return IntSize(-size.width(), -size.height());
+}
+
+inline bool operator==(const IntSize& a, const IntSize& b)
+{
+ return a.width() == b.width() && a.height() == b.height();
+}
+
+inline bool operator!=(const IntSize& a, const IntSize& b)
+{
+ return a.width() != b.width() || a.height() != b.height();
+}
+
+} // namespace WebCore
+
+#endif // IntSize_h
diff --git a/Source/WebCore/platform/graphics/IntSizeHash.h b/Source/WebCore/platform/graphics/IntSizeHash.h
new file mode 100644
index 0000000..ad6eac3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/IntSizeHash.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef IntSizeHash_h
+#define IntSizeHash_h
+
+#include "IntSize.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+
+using WebCore::IntSize;
+
+namespace WTF {
+
+ template<> struct IntHash<IntSize> {
+ static unsigned hash(const IntSize& key) { return intHash((static_cast<uint64_t>(key.width()) << 32 | key.height())); }
+ static bool equal(const IntSize& a, const IntSize& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+ template<> struct DefaultHash<IntSize> { typedef IntHash<IntSize> Hash; };
+
+ template<> struct HashTraits<IntSize> : GenericHashTraits<IntSize> {
+ static const bool emptyValueIsZero = true;
+ static const bool needsDestruction = false;
+ static void constructDeletedValue(IntSize& slot) { new (&slot) IntSize(-1, -1); }
+ static bool isDeletedValue(const IntSize& value) { return value.width() == -1 && value.height() == -1; }
+ };
+} // namespace WTF
+
+#endif
diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp
new file mode 100644
index 0000000..4a39e9e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp
@@ -0,0 +1,780 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+#include "MediaPlayer.h"
+
+#include "ContentType.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "IntRect.h"
+#include "MIMETypeRegistry.h"
+#include "MediaPlayerPrivate.h"
+#include "TimeRanges.h"
+
+#if PLATFORM(QT)
+#include <QtGlobal>
+#endif
+
+#if USE(GSTREAMER)
+#include "MediaPlayerPrivateGStreamer.h"
+#endif
+
+#if PLATFORM(MAC)
+#include "MediaPlayerPrivateQTKit.h"
+#define PlatformMediaEngineClassName MediaPlayerPrivateQTKit
+#elif OS(WINCE) && !PLATFORM(QT)
+#include "MediaPlayerPrivateWinCE.h"
+#define PlatformMediaEngineClassName MediaPlayerPrivate
+#elif PLATFORM(WIN)
+#include "MediaPlayerPrivateQuickTimeVisualContext.h"
+#define PlatformMediaEngineClassName MediaPlayerPrivateQuickTimeVisualContext
+#elif PLATFORM(QT)
+#if USE(QT_MULTIMEDIA) && !USE(GSTREAMER)
+#include "MediaPlayerPrivateQt.h"
+#define PlatformMediaEngineClassName MediaPlayerPrivateQt
+#elif !USE(GSTREAMER)
+#include "MediaPlayerPrivatePhonon.h"
+#define PlatformMediaEngineClassName MediaPlayerPrivatePhonon
+#endif
+#elif PLATFORM(CHROMIUM)
+#include "MediaPlayerPrivateChromium.h"
+#define PlatformMediaEngineClassName MediaPlayerPrivate
+#elif PLATFORM(ANDROID)
+#include "MediaPlayerPrivateAndroid.h"
+#define PlatformMediaEngineClassName MediaPlayerPrivate
+#endif
+
+namespace WebCore {
+
+const PlatformMedia NoPlatformMedia = { PlatformMedia::None, {0} };
+
+// a null player to make MediaPlayer logic simpler
+
+class NullMediaPlayerPrivate : public MediaPlayerPrivateInterface {
+public:
+ NullMediaPlayerPrivate(MediaPlayer*) { }
+
+ virtual void load(const String&) { }
+ virtual void cancelLoad() { }
+
+ virtual void prepareToPlay() { }
+ virtual void play() { }
+ virtual void pause() { }
+
+ virtual PlatformMedia platformMedia() const { return NoPlatformMedia; }
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
+
+ virtual IntSize naturalSize() const { return IntSize(0, 0); }
+
+ virtual bool hasVideo() const { return false; }
+ virtual bool hasAudio() const { return false; }
+
+ virtual void setVisible(bool) { }
+
+ virtual float duration() const { return 0; }
+
+ virtual float currentTime() const { return 0; }
+ virtual void seek(float) { }
+ virtual bool seeking() const { return false; }
+
+ virtual void setRate(float) { }
+ virtual void setPreservesPitch(bool) { }
+ virtual bool paused() const { return false; }
+
+ virtual void setVolume(float) { }
+
+ virtual bool supportsMuting() const { return false; }
+ virtual void setMuted(bool) { }
+
+ virtual bool hasClosedCaptions() const { return false; }
+ virtual void setClosedCaptionsVisible(bool) { };
+
+ virtual MediaPlayer::NetworkState networkState() const { return MediaPlayer::Empty; }
+ virtual MediaPlayer::ReadyState readyState() const { return MediaPlayer::HaveNothing; }
+
+ virtual float maxTimeSeekable() const { return 0; }
+ virtual PassRefPtr<TimeRanges> buffered() const { return TimeRanges::create(); }
+
+ virtual unsigned totalBytes() const { return 0; }
+ virtual unsigned bytesLoaded() const { return 0; }
+
+ virtual void setSize(const IntSize&) { }
+
+ virtual void paint(GraphicsContext*, const IntRect&) { }
+
+ virtual bool canLoadPoster() const { return false; }
+ virtual void setPoster(const String&) { }
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ virtual void deliverNotification(MediaPlayerProxyNotificationType) { }
+ virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) { }
+ virtual void setControls(bool) { }
+#endif
+
+ virtual bool hasSingleSecurityOrigin() const { return true; }
+};
+
+static MediaPlayerPrivateInterface* createNullMediaPlayer(MediaPlayer* player)
+{
+ return new NullMediaPlayerPrivate(player);
+}
+
+
+// engine support
+
+struct MediaPlayerFactory : Noncopyable {
+ MediaPlayerFactory(CreateMediaEnginePlayer constructor, MediaEngineSupportedTypes getSupportedTypes, MediaEngineSupportsType supportsTypeAndCodecs)
+ : constructor(constructor)
+ , getSupportedTypes(getSupportedTypes)
+ , supportsTypeAndCodecs(supportsTypeAndCodecs)
+ {
+ }
+
+ CreateMediaEnginePlayer constructor;
+ MediaEngineSupportedTypes getSupportedTypes;
+ MediaEngineSupportsType supportsTypeAndCodecs;
+};
+
+static void addMediaEngine(CreateMediaEnginePlayer, MediaEngineSupportedTypes, MediaEngineSupportsType);
+static MediaPlayerFactory* bestMediaEngineForTypeAndCodecs(const String& type, const String& codecs, MediaPlayerFactory* current = 0);
+static MediaPlayerFactory* nextMediaEngine(MediaPlayerFactory* current);
+
+static Vector<MediaPlayerFactory*>& installedMediaEngines()
+{
+ DEFINE_STATIC_LOCAL(Vector<MediaPlayerFactory*>, installedEngines, ());
+ static bool enginesQueried = false;
+
+ if (!enginesQueried) {
+ enginesQueried = true;
+
+#if USE(GSTREAMER)
+ MediaPlayerPrivateGStreamer::registerMediaEngine(addMediaEngine);
+#endif
+
+#if !PLATFORM(GTK) && !PLATFORM(EFL) && !(PLATFORM(QT) && USE(GSTREAMER))
+ PlatformMediaEngineClassName::registerMediaEngine(addMediaEngine);
+#endif
+ }
+
+ return installedEngines;
+}
+
+static void addMediaEngine(CreateMediaEnginePlayer constructor, MediaEngineSupportedTypes getSupportedTypes, MediaEngineSupportsType supportsType)
+{
+ ASSERT(constructor);
+ ASSERT(getSupportedTypes);
+ ASSERT(supportsType);
+ installedMediaEngines().append(new MediaPlayerFactory(constructor, getSupportedTypes, supportsType));
+}
+
+static const AtomicString& applicationOctetStream()
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, applicationOctetStream, ("application/octet-stream"));
+ return applicationOctetStream;
+}
+
+static const AtomicString& textPlain()
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, textPlain, ("text/plain"));
+ return textPlain;
+}
+
+static const AtomicString& codecs()
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, codecs, ("codecs"));
+ return codecs;
+}
+
+static MediaPlayerFactory* bestMediaEngineForTypeAndCodecs(const String& type, const String& codecs, MediaPlayerFactory* current)
+{
+ if (type.isEmpty())
+ return 0;
+
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+ if (engines.isEmpty())
+ return 0;
+
+ // 4.8.10.3 MIME types - In the absence of a specification to the contrary, the MIME type "application/octet-stream"
+ // when used with parameters, e.g. "application/octet-stream;codecs=theora", is a type that the user agent knows
+ // it cannot render.
+ if (type == applicationOctetStream()) {
+ if (!codecs.isEmpty())
+ return 0;
+ }
+
+ MediaPlayerFactory* engine = 0;
+ MediaPlayer::SupportsType supported = MediaPlayer::IsNotSupported;
+ unsigned count = engines.size();
+ for (unsigned ndx = 0; ndx < count; ndx++) {
+ if (current) {
+ if (current == engines[ndx])
+ current = 0;
+ continue;
+ }
+ MediaPlayer::SupportsType engineSupport = engines[ndx]->supportsTypeAndCodecs(type, codecs);
+ if (engineSupport > supported) {
+ supported = engineSupport;
+ engine = engines[ndx];
+ }
+ }
+
+ return engine;
+}
+
+static MediaPlayerFactory* nextMediaEngine(MediaPlayerFactory* current)
+{
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+ if (engines.isEmpty())
+ return 0;
+
+ if (!current)
+ return engines.first();
+
+ size_t currentIndex = engines.find(current);
+ if (currentIndex == WTF::notFound || currentIndex == engines.size())
+ return 0;
+
+ return engines[currentIndex + 1];
+}
+
+// media player
+
+MediaPlayer::MediaPlayer(MediaPlayerClient* client)
+ : m_mediaPlayerClient(client)
+ , m_reloadTimer(this, &MediaPlayer::reloadTimerFired)
+ , m_private(createNullMediaPlayer(this))
+ , m_currentMediaEngine(0)
+ , m_frameView(0)
+ , m_preload(Auto)
+ , m_visible(false)
+ , m_rate(1.0f)
+ , m_volume(1.0f)
+ , m_muted(false)
+ , m_preservesPitch(true)
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ , m_playerProxy(0)
+#endif
+#if PLATFORM(ANDROID)
+ , m_mediaElementType(Video)
+#endif
+{
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+ if (!engines.isEmpty()) {
+ m_currentMediaEngine = engines[0];
+ m_private.clear();
+ m_private.set(engines[0]->constructor(this));
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerEngineUpdated(this);
+ }
+#endif
+}
+
+MediaPlayer::~MediaPlayer()
+{
+ m_mediaPlayerClient = 0;
+}
+
+void MediaPlayer::load(const String& url, const ContentType& contentType)
+{
+ String type = contentType.type().lower();
+ String typeCodecs = contentType.parameter(codecs());
+
+ // If the MIME type is missing or is not meaningful, try to figure it out from the URL.
+ if (type.isEmpty() || type == applicationOctetStream() || type == textPlain()) {
+ if (protocolIs(url, "data"))
+ type = mimeTypeFromDataURL(url);
+ else {
+ size_t pos = url.reverseFind('.');
+ if (pos != notFound) {
+ String extension = url.substring(pos + 1);
+ String mediaType = MIMETypeRegistry::getMediaMIMETypeForExtension(extension);
+ if (!mediaType.isEmpty())
+ type = mediaType;
+ }
+ }
+ }
+
+ m_url = url;
+ m_contentMIMEType = type;
+ m_contentTypeCodecs = typeCodecs;
+ loadWithNextMediaEngine(0);
+}
+
+void MediaPlayer::loadWithNextMediaEngine(MediaPlayerFactory* current)
+{
+ MediaPlayerFactory* engine;
+
+ // If no MIME type is specified, just use the next engine.
+ if (m_contentMIMEType.isEmpty())
+ engine = nextMediaEngine(current);
+ else
+ engine = bestMediaEngineForTypeAndCodecs(m_contentMIMEType, m_contentTypeCodecs, current);
+
+ // Don't delete and recreate the player unless it comes from a different engine.
+ if (!engine) {
+ m_currentMediaEngine = engine;
+ m_private.clear();
+ } else if (m_currentMediaEngine != engine) {
+ m_currentMediaEngine = engine;
+ m_private.clear();
+ m_private.set(engine->constructor(this));
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerEngineUpdated(this);
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ m_private->setMediaPlayerProxy(m_playerProxy);
+#endif
+ m_private->setPreload(m_preload);
+ m_private->setPreservesPitch(preservesPitch());
+ }
+
+ if (m_private)
+ m_private->load(m_url);
+ else {
+ m_private.set(createNullMediaPlayer(this));
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerEngineUpdated(this);
+ }
+}
+
+bool MediaPlayer::hasAvailableVideoFrame() const
+{
+ return m_private->hasAvailableVideoFrame();
+}
+
+void MediaPlayer::prepareForRendering()
+{
+ return m_private->prepareForRendering();
+}
+
+bool MediaPlayer::canLoadPoster() const
+{
+ return m_private->canLoadPoster();
+}
+
+void MediaPlayer::setPoster(const String& url)
+{
+ m_private->setPoster(url);
+}
+
+void MediaPlayer::cancelLoad()
+{
+ m_private->cancelLoad();
+}
+
+void MediaPlayer::prepareToPlay()
+{
+ m_private->prepareToPlay();
+}
+
+void MediaPlayer::play()
+{
+ m_private->play();
+}
+
+void MediaPlayer::pause()
+{
+ m_private->pause();
+}
+
+float MediaPlayer::duration() const
+{
+ return m_private->duration();
+}
+
+float MediaPlayer::startTime() const
+{
+ return m_private->startTime();
+}
+
+float MediaPlayer::currentTime() const
+{
+ return m_private->currentTime();
+}
+
+void MediaPlayer::seek(float time)
+{
+ m_private->seek(time);
+}
+
+bool MediaPlayer::paused() const
+{
+ return m_private->paused();
+}
+
+bool MediaPlayer::seeking() const
+{
+ return m_private->seeking();
+}
+
+bool MediaPlayer::supportsFullscreen() const
+{
+ return m_private->supportsFullscreen();
+}
+
+bool MediaPlayer::supportsSave() const
+{
+ return m_private->supportsSave();
+}
+
+IntSize MediaPlayer::naturalSize()
+{
+ return m_private->naturalSize();
+}
+
+bool MediaPlayer::hasVideo() const
+{
+ return m_private->hasVideo();
+}
+
+bool MediaPlayer::hasAudio() const
+{
+ return m_private->hasAudio();
+}
+
+bool MediaPlayer::inMediaDocument()
+{
+ Frame* frame = m_frameView ? m_frameView->frame() : 0;
+ Document* document = frame ? frame->document() : 0;
+
+ return document && document->isMediaDocument();
+}
+
+PlatformMedia MediaPlayer::platformMedia() const
+{
+ return m_private->platformMedia();
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayer::platformLayer() const
+{
+ return m_private->platformLayer();
+}
+#endif
+
+MediaPlayer::NetworkState MediaPlayer::networkState()
+{
+ return m_private->networkState();
+}
+
+MediaPlayer::ReadyState MediaPlayer::readyState()
+{
+ return m_private->readyState();
+}
+
+float MediaPlayer::volume() const
+{
+ return m_volume;
+}
+
+void MediaPlayer::setVolume(float volume)
+{
+ m_volume = volume;
+
+ if (m_private->supportsMuting() || !m_muted)
+ m_private->setVolume(volume);
+}
+
+bool MediaPlayer::muted() const
+{
+ return m_muted;
+}
+
+void MediaPlayer::setMuted(bool muted)
+{
+ m_muted = muted;
+
+ if (m_private->supportsMuting())
+ m_private->setMuted(muted);
+ else
+ m_private->setVolume(muted ? 0 : m_volume);
+}
+
+bool MediaPlayer::hasClosedCaptions() const
+{
+ return m_private->hasClosedCaptions();
+}
+
+void MediaPlayer::setClosedCaptionsVisible(bool closedCaptionsVisible)
+{
+ m_private->setClosedCaptionsVisible(closedCaptionsVisible);
+}
+
+float MediaPlayer::rate() const
+{
+ return m_rate;
+}
+
+void MediaPlayer::setRate(float rate)
+{
+ m_rate = rate;
+ m_private->setRate(rate);
+}
+
+bool MediaPlayer::preservesPitch() const
+{
+ return m_preservesPitch;
+}
+
+void MediaPlayer::setPreservesPitch(bool preservesPitch)
+{
+ m_preservesPitch = preservesPitch;
+ m_private->setPreservesPitch(preservesPitch);
+}
+
+PassRefPtr<TimeRanges> MediaPlayer::buffered()
+{
+ return m_private->buffered();
+}
+
+float MediaPlayer::maxTimeSeekable()
+{
+ return m_private->maxTimeSeekable();
+}
+
+unsigned MediaPlayer::bytesLoaded()
+{
+ return m_private->bytesLoaded();
+}
+
+void MediaPlayer::setSize(const IntSize& size)
+{
+ m_size = size;
+ m_private->setSize(size);
+}
+
+bool MediaPlayer::visible() const
+{
+ return m_visible;
+}
+
+void MediaPlayer::setVisible(bool b)
+{
+ m_visible = b;
+ m_private->setVisible(b);
+}
+
+MediaPlayer::Preload MediaPlayer::preload() const
+{
+ return m_preload;
+}
+
+void MediaPlayer::setPreload(MediaPlayer::Preload preload)
+{
+ m_preload = preload;
+ m_private->setPreload(preload);
+}
+
+void MediaPlayer::paint(GraphicsContext* p, const IntRect& r)
+{
+ m_private->paint(p, r);
+}
+
+void MediaPlayer::paintCurrentFrameInContext(GraphicsContext* p, const IntRect& r)
+{
+ m_private->paintCurrentFrameInContext(p, r);
+}
+
+MediaPlayer::SupportsType MediaPlayer::supportsType(const ContentType& contentType)
+{
+ String type = contentType.type().lower();
+ String typeCodecs = contentType.parameter(codecs());
+
+ // 4.8.10.3 MIME types - The canPlayType(type) method must return the empty string if type is a type that the
+ // user agent knows it cannot render or is the type "application/octet-stream"
+ if (type == applicationOctetStream())
+ return IsNotSupported;
+
+ MediaPlayerFactory* engine = bestMediaEngineForTypeAndCodecs(type, typeCodecs);
+ if (!engine)
+ return IsNotSupported;
+
+ return engine->supportsTypeAndCodecs(type, typeCodecs);
+}
+
+void MediaPlayer::getSupportedTypes(HashSet<String>& types)
+{
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+ if (engines.isEmpty())
+ return;
+
+ unsigned count = engines.size();
+ for (unsigned ndx = 0; ndx < count; ndx++)
+ engines[ndx]->getSupportedTypes(types);
+}
+
+bool MediaPlayer::isAvailable()
+{
+ return !installedMediaEngines().isEmpty();
+}
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+void MediaPlayer::deliverNotification(MediaPlayerProxyNotificationType notification)
+{
+ m_private->deliverNotification(notification);
+}
+
+void MediaPlayer::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
+{
+ m_playerProxy = proxy;
+ m_private->setMediaPlayerProxy(proxy);
+}
+
+void MediaPlayer::setControls(bool controls)
+{
+ m_private->setControls(controls);
+}
+
+void MediaPlayer::enterFullscreen()
+{
+ m_private->enterFullscreen();
+}
+
+void MediaPlayer::exitFullscreen()
+{
+ m_private->exitFullscreen();
+}
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+void MediaPlayer::acceleratedRenderingStateChanged()
+{
+ m_private->acceleratedRenderingStateChanged();
+}
+
+bool MediaPlayer::supportsAcceleratedRendering() const
+{
+ return m_private->supportsAcceleratedRendering();
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+bool MediaPlayer::hasSingleSecurityOrigin() const
+{
+ return m_private->hasSingleSecurityOrigin();
+}
+
+MediaPlayer::MovieLoadType MediaPlayer::movieLoadType() const
+{
+ return m_private->movieLoadType();
+}
+
+float MediaPlayer::mediaTimeForTimeValue(float timeValue) const
+{
+ return m_private->mediaTimeForTimeValue(timeValue);
+}
+
+double MediaPlayer::maximumDurationToCacheMediaTime() const
+{
+ return m_private->maximumDurationToCacheMediaTime();
+}
+
+void MediaPlayer::reloadTimerFired(Timer<MediaPlayer>*)
+{
+ m_private->cancelLoad();
+ loadWithNextMediaEngine(m_currentMediaEngine);
+}
+
+
+// Client callbacks.
+void MediaPlayer::networkStateChanged()
+{
+ // If more than one media engine is installed and this one failed before finding metadata,
+ // let the next engine try.
+ if (m_private->networkState() >= FormatError
+ && m_private->readyState() < HaveMetadata
+ && installedMediaEngines().size() > 1
+ && bestMediaEngineForTypeAndCodecs(m_contentMIMEType, m_contentTypeCodecs, m_currentMediaEngine)) {
+ m_reloadTimer.startOneShot(0);
+ return;
+ }
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerNetworkStateChanged(this);
+}
+
+void MediaPlayer::readyStateChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerReadyStateChanged(this);
+}
+
+void MediaPlayer::volumeChanged(float newVolume)
+{
+ m_volume = newVolume;
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerVolumeChanged(this);
+}
+
+void MediaPlayer::muteChanged(bool newMuted)
+{
+ m_muted = newMuted;
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerMuteChanged(this);
+}
+
+void MediaPlayer::timeChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerTimeChanged(this);
+}
+
+void MediaPlayer::sizeChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerSizeChanged(this);
+}
+
+void MediaPlayer::repaint()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerRepaint(this);
+}
+
+void MediaPlayer::durationChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerDurationChanged(this);
+}
+
+void MediaPlayer::rateChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerRateChanged(this);
+}
+
+void MediaPlayer::playbackStateChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerPlaybackStateChanged(this);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/MediaPlayer.h b/Source/WebCore/platform/graphics/MediaPlayer.h
new file mode 100644
index 0000000..6525ca6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/MediaPlayer.h
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 MediaPlayer_h
+#define MediaPlayer_h
+
+#if ENABLE(VIDEO)
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "MediaPlayerProxy.h"
+#endif
+
+#include "Document.h"
+#include "IntRect.h"
+#include <wtf/Forward.h>
+#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/StringHash.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayer.h"
+#endif
+
+#ifdef __OBJC__
+@class QTMovie;
+#else
+class QTMovie;
+#endif
+class QTMovieGWorld;
+class QTMovieVisualContext;
+
+namespace WebCore {
+
+class GStreamerGWorld;
+class MediaPlayerPrivateInterface;
+
+// Structure that will hold every native
+// types supported by the current media player.
+// We have to do that has multiple media players
+// backend can live at runtime.
+struct PlatformMedia {
+ enum {
+ None,
+ QTMovieType,
+ QTMovieGWorldType,
+ QTMovieVisualContextType,
+ GStreamerGWorldType,
+ ChromiumMediaPlayerType,
+ QtMediaPlayerType,
+ } type;
+
+ union {
+ QTMovie* qtMovie;
+ QTMovieGWorld* qtMovieGWorld;
+ QTMovieVisualContext* qtMovieVisualContext;
+ GStreamerGWorld* gstreamerGWorld;
+ MediaPlayerPrivateInterface* chromiumMediaPlayer;
+ MediaPlayerPrivateInterface* qtMediaPlayer;
+ } media;
+};
+
+extern const PlatformMedia NoPlatformMedia;
+
+class ContentType;
+class FrameView;
+class GraphicsContext;
+class IntRect;
+class IntSize;
+class MediaPlayer;
+struct MediaPlayerFactory;
+class TimeRanges;
+
+class MediaPlayerClient {
+public:
+ virtual ~MediaPlayerClient() { }
+
+ // Get the document which the media player is owned by
+ virtual Document* mediaPlayerOwningDocument() { return 0; }
+
+ // the network state has changed
+ virtual void mediaPlayerNetworkStateChanged(MediaPlayer*) { }
+
+ // the ready state has changed
+ virtual void mediaPlayerReadyStateChanged(MediaPlayer*) { }
+
+ // the volume state has changed
+ virtual void mediaPlayerVolumeChanged(MediaPlayer*) { }
+
+ // the mute state has changed
+ virtual void mediaPlayerMuteChanged(MediaPlayer*) { }
+
+ // time has jumped, eg. not as a result of normal playback
+ virtual void mediaPlayerTimeChanged(MediaPlayer*) { }
+
+ // the media file duration has changed, or is now known
+ virtual void mediaPlayerDurationChanged(MediaPlayer*) { }
+
+ // the playback rate has changed
+ virtual void mediaPlayerRateChanged(MediaPlayer*) { }
+
+ // the play/pause status changed
+ virtual void mediaPlayerPlaybackStateChanged(MediaPlayer*) { }
+
+ // The MediaPlayer has found potentially problematic media content.
+ // This is used internally to trigger swapping from a <video>
+ // element to an <embed> in standalone documents
+ virtual void mediaPlayerSawUnsupportedTracks(MediaPlayer*) { }
+
+// Presentation-related methods
+ // a new frame of video is available
+ virtual void mediaPlayerRepaint(MediaPlayer*) { }
+
+ // the movie size has changed
+ virtual void mediaPlayerSizeChanged(MediaPlayer*) { }
+
+ virtual void mediaPlayerEngineUpdated(MediaPlayer*) { }
+
+#if USE(ACCELERATED_COMPOSITING)
+ // whether the rendering system can accelerate the display of this MediaPlayer.
+ virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*) { return false; }
+
+ // called when the media player's rendering mode changed, which indicates a change in the
+ // availability of the platformLayer().
+ virtual void mediaPlayerRenderingModeChanged(MediaPlayer*) { }
+#endif
+};
+
+class MediaPlayer : public Noncopyable {
+public:
+
+ static PassOwnPtr<MediaPlayer> create(MediaPlayerClient* client)
+ {
+ return adoptPtr(new MediaPlayer(client));
+ }
+ virtual ~MediaPlayer();
+
+ // media engine support
+ enum SupportsType { IsNotSupported, IsSupported, MayBeSupported };
+ static MediaPlayer::SupportsType supportsType(const ContentType&);
+ static void getSupportedTypes(HashSet<String>&);
+ static bool isAvailable();
+
+ bool supportsFullscreen() const;
+ bool supportsSave() const;
+ PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
+
+ IntSize naturalSize();
+ bool hasVideo() const;
+ bool hasAudio() const;
+#if PLATFORM(ANDROID)
+ enum MediaElementType { Video, Audio };
+ void setMediaElementType(MediaElementType type) { m_mediaElementType = type; }
+ MediaElementType mediaElementType() { return m_mediaElementType; }
+#endif
+
+ void setFrameView(FrameView* frameView) { m_frameView = frameView; }
+ FrameView* frameView() { return m_frameView; }
+ bool inMediaDocument();
+
+ IntSize size() const { return m_size; }
+ void setSize(const IntSize& size);
+
+ void load(const String& url, const ContentType&);
+ void cancelLoad();
+
+ bool visible() const;
+ void setVisible(bool);
+
+ void prepareToPlay();
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float time);
+
+ float startTime() const;
+
+ float rate() const;
+ void setRate(float);
+
+ bool preservesPitch() const;
+ void setPreservesPitch(bool);
+
+ PassRefPtr<TimeRanges> buffered();
+ float maxTimeSeekable();
+
+ unsigned bytesLoaded();
+
+ float volume() const;
+ void setVolume(float);
+
+ bool muted() const;
+ void setMuted(bool);
+
+ bool hasClosedCaptions() const;
+ void setClosedCaptionsVisible(bool closedCaptionsVisible);
+
+ bool autoplay() const;
+ void setAutoplay(bool);
+
+ void paint(GraphicsContext*, const IntRect&);
+ void paintCurrentFrameInContext(GraphicsContext*, const IntRect&);
+
+ enum NetworkState { Empty, Idle, Loading, Loaded, FormatError, NetworkError, DecodeError };
+ NetworkState networkState();
+
+ enum ReadyState { HaveNothing, HaveMetadata, HaveCurrentData, HaveFutureData, HaveEnoughData };
+ ReadyState readyState();
+
+ enum MovieLoadType { Unknown, Download, StoredStream, LiveStream };
+ MovieLoadType movieLoadType() const;
+
+ enum Preload { None, MetaData, Auto };
+ Preload preload() const;
+ void setPreload(Preload);
+
+ void networkStateChanged();
+ void readyStateChanged();
+ void volumeChanged(float);
+ void muteChanged(bool);
+ void timeChanged();
+ void sizeChanged();
+ void rateChanged();
+ void playbackStateChanged();
+ void durationChanged();
+
+ void repaint();
+
+ MediaPlayerClient* mediaPlayerClient() const { return m_mediaPlayerClient; }
+
+ bool hasAvailableVideoFrame() const;
+ void prepareForRendering();
+
+ bool canLoadPoster() const;
+ void setPoster(const String&);
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ void deliverNotification(MediaPlayerProxyNotificationType notification);
+ void setMediaPlayerProxy(WebMediaPlayerProxy* proxy);
+ void setControls(bool);
+ void enterFullscreen();
+ void exitFullscreen();
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+ // whether accelerated rendering is supported by the media engine for the current media.
+ bool supportsAcceleratedRendering() const;
+ // called when the rendering system flips the into or out of accelerated rendering mode.
+ void acceleratedRenderingStateChanged();
+#endif
+
+ bool hasSingleSecurityOrigin() const;
+
+ float mediaTimeForTimeValue(float) const;
+
+ double maximumDurationToCacheMediaTime() const;
+
+private:
+ MediaPlayer(MediaPlayerClient*);
+ void loadWithNextMediaEngine(MediaPlayerFactory*);
+ void reloadTimerFired(Timer<MediaPlayer>*);
+
+ static void initializeMediaEngines();
+
+ MediaPlayerClient* m_mediaPlayerClient;
+ Timer<MediaPlayer> m_reloadTimer;
+ OwnPtr<MediaPlayerPrivateInterface*> m_private;
+ MediaPlayerFactory* m_currentMediaEngine;
+ String m_url;
+ String m_contentMIMEType;
+ String m_contentTypeCodecs;
+ FrameView* m_frameView;
+ IntSize m_size;
+ Preload m_preload;
+ bool m_visible;
+ float m_rate;
+ float m_volume;
+ bool m_muted;
+ bool m_preservesPitch;
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ WebMediaPlayerProxy* m_playerProxy; // not owned or used, passed to m_private
+#endif
+#if PLATFORM(ANDROID)
+ MediaElementType m_mediaElementType;
+#endif
+};
+
+typedef MediaPlayerPrivateInterface* (*CreateMediaEnginePlayer)(MediaPlayer*);
+typedef void (*MediaEngineSupportedTypes)(HashSet<String>& types);
+typedef MediaPlayer::SupportsType (*MediaEngineSupportsType)(const String& type, const String& codecs);
+
+typedef void (*MediaEngineRegistrar)(CreateMediaEnginePlayer, MediaEngineSupportedTypes, MediaEngineSupportsType);
+
+
+}
+
+#endif // ENABLE(VIDEO)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/MediaPlayerPrivate.h b/Source/WebCore/platform/graphics/MediaPlayerPrivate.h
new file mode 100644
index 0000000..d956286
--- /dev/null
+++ b/Source/WebCore/platform/graphics/MediaPlayerPrivate.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 MediaPlayerPrivate_h
+#define MediaPlayerPrivate_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayer.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class IntRect;
+class IntSize;
+
+class MediaPlayerPrivateInterface : public Noncopyable {
+public:
+ virtual ~MediaPlayerPrivateInterface() { }
+
+ virtual void load(const String& url) = 0;
+ virtual void cancelLoad() = 0;
+
+ virtual void prepareToPlay() { }
+ virtual PlatformMedia platformMedia() const { return NoPlatformMedia; }
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
+
+ virtual void play() = 0;
+ virtual void pause() = 0;
+
+ virtual bool supportsFullscreen() const { return false; }
+ virtual bool supportsSave() const { return false; }
+
+ virtual IntSize naturalSize() const = 0;
+
+ virtual bool hasVideo() const = 0;
+ virtual bool hasAudio() const = 0;
+
+ virtual void setVisible(bool) = 0;
+
+ virtual float duration() const = 0;
+
+ virtual float currentTime() const = 0;
+ virtual void seek(float time) = 0;
+ virtual bool seeking() const = 0;
+
+ virtual float startTime() const { return 0; }
+
+ virtual void setRate(float) = 0;
+ virtual void setPreservesPitch(bool) { }
+
+ virtual bool paused() const = 0;
+
+ virtual void setVolume(float) = 0;
+
+ virtual bool supportsMuting() const { return false; }
+ virtual void setMuted(bool) { }
+
+ virtual bool hasClosedCaptions() const { return false; }
+ virtual void setClosedCaptionsVisible(bool) { }
+
+ virtual MediaPlayer::NetworkState networkState() const = 0;
+ virtual MediaPlayer::ReadyState readyState() const = 0;
+
+ virtual float maxTimeSeekable() const = 0;
+ virtual PassRefPtr<TimeRanges> buffered() const = 0;
+
+ virtual unsigned bytesLoaded() const = 0;
+
+ virtual void setSize(const IntSize&) = 0;
+
+ virtual void paint(GraphicsContext*, const IntRect&) = 0;
+
+ virtual void paintCurrentFrameInContext(GraphicsContext* c, const IntRect& r) { paint(c, r); }
+
+ virtual void setPreload(MediaPlayer::Preload) { };
+
+ virtual bool hasAvailableVideoFrame() const { return readyState() >= MediaPlayer::HaveCurrentData; }
+
+ virtual bool canLoadPoster() const { return false; }
+ virtual void setPoster(const String&) { }
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ virtual void deliverNotification(MediaPlayerProxyNotificationType) = 0;
+ virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) = 0;
+ virtual void setControls(bool) { }
+ virtual void enterFullscreen() { }
+ virtual void exitFullscreen() { }
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+ // whether accelerated rendering is supported by the media engine for the current media.
+ virtual bool supportsAcceleratedRendering() const { return false; }
+ // called when the rendering system flips the into or out of accelerated rendering mode.
+ virtual void acceleratedRenderingStateChanged() { }
+#endif
+
+ virtual bool hasSingleSecurityOrigin() const { return false; }
+
+ virtual MediaPlayer::MovieLoadType movieLoadType() const { return MediaPlayer::Unknown; }
+
+ virtual void prepareForRendering() { }
+
+ // Time value in the movie's time scale. It is only necessary to override this if the media
+ // engine uses rational numbers to represent media time.
+ virtual float mediaTimeForTimeValue(float timeValue) const { return timeValue; }
+
+ // Overide this if it is safe for HTMLMediaElement to cache movie time and report
+ // 'currentTime' as [cached time + elapsed wall time]. Returns the maximum wall time
+ // it is OK to calculate movie time before refreshing the cached time.
+ virtual double maximumDurationToCacheMediaTime() const { return 0; }
+
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/platform/graphics/Path.cpp b/Source/WebCore/platform/graphics/Path.cpp
new file mode 100644
index 0000000..55760b1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Path.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * 2006 Rob Buis <buis@kde.org>
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+
+#include "config.h"
+#include "Path.h"
+
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "PathTraversalState.h"
+#include <math.h>
+#include <wtf/MathExtras.h>
+
+// Approximation of control point positions on a bezier to simulate a quarter of a circle.
+static const float gCircleControlPoint = 0.448f;
+
+namespace WebCore {
+
+#if !PLATFORM(OPENVG) && !PLATFORM(QT)
+static void pathLengthApplierFunction(void* info, const PathElement* element)
+{
+ PathTraversalState& traversalState = *static_cast<PathTraversalState*>(info);
+ if (traversalState.m_success)
+ return;
+ traversalState.m_previous = traversalState.m_current;
+ FloatPoint* points = element->points;
+ float segmentLength = 0;
+ switch (element->type) {
+ case PathElementMoveToPoint:
+ segmentLength = traversalState.moveTo(points[0]);
+ break;
+ case PathElementAddLineToPoint:
+ segmentLength = traversalState.lineTo(points[0]);
+ break;
+ case PathElementAddQuadCurveToPoint:
+ segmentLength = traversalState.quadraticBezierTo(points[0], points[1]);
+ break;
+ case PathElementAddCurveToPoint:
+ segmentLength = traversalState.cubicBezierTo(points[0], points[1], points[2]);
+ break;
+ case PathElementCloseSubpath:
+ segmentLength = traversalState.closeSubpath();
+ break;
+ }
+ traversalState.m_totalLength += segmentLength;
+ if ((traversalState.m_action == PathTraversalState::TraversalPointAtLength ||
+ traversalState.m_action == PathTraversalState::TraversalNormalAngleAtLength) &&
+ (traversalState.m_totalLength >= traversalState.m_desiredLength)) {
+ FloatSize change = traversalState.m_current - traversalState.m_previous;
+ float slope = atan2f(change.height(), change.width());
+
+ if (traversalState.m_action == PathTraversalState::TraversalPointAtLength) {
+ float offset = traversalState.m_desiredLength - traversalState.m_totalLength;
+ traversalState.m_current.move(offset * cosf(slope), offset * sinf(slope));
+ } else
+ traversalState.m_normalAngle = rad2deg(slope);
+
+ traversalState.m_success = true;
+ }
+}
+
+float Path::length()
+{
+ PathTraversalState traversalState(PathTraversalState::TraversalTotalLength);
+ apply(&traversalState, pathLengthApplierFunction);
+ return traversalState.m_totalLength;
+}
+
+FloatPoint Path::pointAtLength(float length, bool& ok)
+{
+ PathTraversalState traversalState(PathTraversalState::TraversalPointAtLength);
+ traversalState.m_desiredLength = length;
+ apply(&traversalState, pathLengthApplierFunction);
+ ok = traversalState.m_success;
+ return traversalState.m_current;
+}
+
+float Path::normalAngleAtLength(float length, bool& ok)
+{
+ PathTraversalState traversalState(PathTraversalState::TraversalNormalAngleAtLength);
+ traversalState.m_desiredLength = length;
+ apply(&traversalState, pathLengthApplierFunction);
+ ok = traversalState.m_success;
+ return traversalState.m_normalAngle;
+}
+#endif
+
+void Path::addRoundedRect(const FloatRect& rect, const FloatSize& roundingRadii)
+{
+ if (rect.isEmpty())
+ return;
+
+ FloatSize radius(roundingRadii);
+ FloatSize halfSize(rect.width() / 2, rect.height() / 2);
+
+ // If rx is greater than half of the width of the rectangle
+ // then set rx to half of the width (required in SVG spec)
+ if (radius.width() > halfSize.width())
+ radius.setWidth(halfSize.width());
+
+ // If ry is greater than half of the height of the rectangle
+ // then set ry to half of the height (required in SVG spec)
+ if (radius.height() > halfSize.height())
+ radius.setHeight(halfSize.height());
+
+ moveTo(FloatPoint(rect.x() + radius.width(), rect.y()));
+
+ if (radius.width() < halfSize.width())
+ addLineTo(FloatPoint(rect.x() + rect.width() - roundingRadii.width(), rect.y()));
+
+ addBezierCurveTo(FloatPoint(rect.x() + rect.width() - radius.width() * gCircleControlPoint, rect.y()), FloatPoint(rect.x() + rect.width(), rect.y() + radius.height() * gCircleControlPoint), FloatPoint(rect.x() + rect.width(), rect.y() + radius.height()));
+
+ if (radius.height() < halfSize.height())
+ addLineTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - radius.height()));
+
+ addBezierCurveTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - radius.height() * gCircleControlPoint), FloatPoint(rect.x() + rect.width() - radius.width() * gCircleControlPoint, rect.y() + rect.height()), FloatPoint(rect.x() + rect.width() - radius.width(), rect.y() + rect.height()));
+
+ if (radius.width() < halfSize.width())
+ addLineTo(FloatPoint(rect.x() + radius.width(), rect.y() + rect.height()));
+
+ addBezierCurveTo(FloatPoint(rect.x() + radius.width() * gCircleControlPoint, rect.y() + rect.height()), FloatPoint(rect.x(), rect.y() + rect.height() - radius.height() * gCircleControlPoint), FloatPoint(rect.x(), rect.y() + rect.height() - radius.height()));
+
+ if (radius.height() < halfSize.height())
+ addLineTo(FloatPoint(rect.x(), rect.y() + radius.height()));
+
+ addBezierCurveTo(FloatPoint(rect.x(), rect.y() + radius.height() * gCircleControlPoint), FloatPoint(rect.x() + radius.width() * gCircleControlPoint, rect.y()), FloatPoint(rect.x() + radius.width(), rect.y()));
+
+ closeSubpath();
+}
+
+void Path::addRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius)
+{
+ if (rect.isEmpty())
+ return;
+
+ if (rect.width() < topLeftRadius.width() + topRightRadius.width()
+ || rect.width() < bottomLeftRadius.width() + bottomRightRadius.width()
+ || rect.height() < topLeftRadius.height() + bottomLeftRadius.height()
+ || rect.height() < topRightRadius.height() + bottomRightRadius.height()) {
+ // If all the radii cannot be accommodated, return a rect.
+ addRect(rect);
+ return;
+ }
+
+ moveTo(FloatPoint(rect.x() + topLeftRadius.width(), rect.y()));
+
+ addLineTo(FloatPoint(rect.x() + rect.width() - topRightRadius.width(), rect.y()));
+ addBezierCurveTo(FloatPoint(rect.x() + rect.width() - topRightRadius.width() * gCircleControlPoint, rect.y()),
+ FloatPoint(rect.x() + rect.width(), rect.y() + topRightRadius.height() * gCircleControlPoint),
+ FloatPoint(rect.x() + rect.width(), rect.y() + topRightRadius.height()));
+ addLineTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - bottomRightRadius.height()));
+ addBezierCurveTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - bottomRightRadius.height() * gCircleControlPoint),
+ FloatPoint(rect.x() + rect.width() - bottomRightRadius.width() * gCircleControlPoint, rect.y() + rect.height()),
+ FloatPoint(rect.x() + rect.width() - bottomRightRadius.width(), rect.y() + rect.height()));
+ addLineTo(FloatPoint(rect.x() + bottomLeftRadius.width(), rect.y() + rect.height()));
+ addBezierCurveTo(FloatPoint(rect.x() + bottomLeftRadius.width() * gCircleControlPoint, rect.y() + rect.height()),
+ FloatPoint(rect.x(), rect.y() + rect.height() - bottomLeftRadius.height() * gCircleControlPoint),
+ FloatPoint(rect.x(), rect.y() + rect.height() - bottomLeftRadius.height()));
+ addLineTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height()));
+ addBezierCurveTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height() * gCircleControlPoint),
+ FloatPoint(rect.x() + topLeftRadius.width() * gCircleControlPoint, rect.y()),
+ FloatPoint(rect.x() + topLeftRadius.width(), rect.y()));
+
+ closeSubpath();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/Path.h b/Source/WebCore/platform/graphics/Path.h
new file mode 100644
index 0000000..423a792
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Path.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2003, 2006, 2009 Apple Inc. All rights reserved.
+ * 2006 Rob Buis <buis@kde.org>
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 Path_h
+#define Path_h
+
+#include <wtf/FastAllocBase.h>
+#include <wtf/Forward.h>
+
+#if PLATFORM(CG)
+typedef struct CGPath PlatformPath;
+#elif PLATFORM(OPENVG)
+namespace WebCore {
+class PlatformPathOpenVG;
+}
+typedef WebCore::PlatformPathOpenVG PlatformPath;
+#elif PLATFORM(QT)
+#include <qpainterpath.h>
+typedef QPainterPath PlatformPath;
+#elif PLATFORM(WX) && USE(WXGC)
+class wxGraphicsPath;
+typedef wxGraphicsPath PlatformPath;
+#elif PLATFORM(CAIRO)
+namespace WebCore {
+class CairoPath;
+}
+typedef WebCore::CairoPath PlatformPath;
+#elif PLATFORM(SKIA)
+class SkPath;
+typedef SkPath PlatformPath;
+#elif PLATFORM(HAIKU)
+class BRegion;
+typedef BRegion PlatformPath;
+#elif OS(WINCE)
+namespace WebCore {
+ class PlatformPath;
+}
+typedef WebCore::PlatformPath PlatformPath;
+#else
+typedef void PlatformPath;
+#endif
+
+#if PLATFORM(QT)
+/* QPainterPath is valued based */
+typedef PlatformPath PlatformPathPtr;
+#else
+typedef PlatformPath* PlatformPathPtr;
+#endif
+
+namespace WebCore {
+
+ class AffineTransform;
+ class FloatPoint;
+ class FloatRect;
+ class FloatSize;
+ class GraphicsContext;
+ class StrokeStyleApplier;
+
+ enum WindRule {
+ RULE_NONZERO = 0,
+ RULE_EVENODD = 1
+ };
+
+ enum PathElementType {
+ PathElementMoveToPoint,
+ PathElementAddLineToPoint,
+ PathElementAddQuadCurveToPoint,
+ PathElementAddCurveToPoint,
+ PathElementCloseSubpath
+ };
+
+ struct PathElement {
+ PathElementType type;
+ FloatPoint* points;
+ };
+
+ typedef void (*PathApplierFunction)(void* info, const PathElement*);
+
+ class Path : public FastAllocBase {
+ public:
+ Path();
+ ~Path();
+
+ Path(const Path&);
+ Path& operator=(const Path&);
+
+ bool contains(const FloatPoint&, WindRule rule = RULE_NONZERO) const;
+ bool strokeContains(StrokeStyleApplier*, const FloatPoint&) const;
+ FloatRect boundingRect() const;
+ FloatRect strokeBoundingRect(StrokeStyleApplier* = 0);
+
+ float length();
+ FloatPoint pointAtLength(float length, bool& ok);
+ float normalAngleAtLength(float length, bool& ok);
+
+ void clear();
+ bool isEmpty() const;
+ // Gets the current point of the current path, which is conceptually the final point reached by the path so far.
+ // Note the Path can be empty (isEmpty() == true) and still have a current point.
+ bool hasCurrentPoint() const;
+ FloatPoint currentPoint() const;
+
+ void moveTo(const FloatPoint&);
+ void addLineTo(const FloatPoint&);
+ void addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& endPoint);
+ void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& endPoint);
+ void addArcTo(const FloatPoint&, const FloatPoint&, float radius);
+ void closeSubpath();
+
+ void addArc(const FloatPoint&, float radius, float startAngle, float endAngle, bool anticlockwise);
+ void addRect(const FloatRect&);
+ void addEllipse(const FloatRect&);
+ void addRoundedRect(const FloatRect&, const FloatSize& roundingRadii);
+ void addRoundedRect(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius);
+
+ void translate(const FloatSize&);
+
+ PlatformPathPtr platformPath() const { return m_path; }
+
+ void apply(void* info, PathApplierFunction) const;
+ void transform(const AffineTransform&);
+
+ private:
+ PlatformPathPtr m_path;
+ };
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/PathTraversalState.cpp b/Source/WebCore/platform/graphics/PathTraversalState.cpp
new file mode 100644
index 0000000..ecdcb1b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/PathTraversalState.cpp
@@ -0,0 +1,207 @@
+/*
+ * This file is part of the WebKit open source project.
+ *
+ * Copyright (C) 2006, 2007 Eric Seidel (eric@webkit.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "PathTraversalState.h"
+
+#include "Path.h"
+
+#include <math.h>
+
+namespace WebCore {
+
+static const float kPathSegmentLengthTolerance = 0.00001f;
+
+static inline FloatPoint midPoint(const FloatPoint& first, const FloatPoint& second)
+{
+ return FloatPoint((first.x() + second.x()) / 2.0f, (first.y() + second.y()) / 2.0f);
+}
+
+static inline float distanceLine(const FloatPoint& start, const FloatPoint& end)
+{
+ return sqrtf((end.x() - start.x()) * (end.x() - start.x()) + (end.y() - start.y()) * (end.y() - start.y()));
+}
+
+struct QuadraticBezier {
+ QuadraticBezier() { }
+ QuadraticBezier(const FloatPoint& s, const FloatPoint& c, const FloatPoint& e)
+ : start(s)
+ , control(c)
+ , end(e)
+ {
+ }
+
+ float approximateDistance() const
+ {
+ return distanceLine(start, control) + distanceLine(control, end);
+ }
+
+ void split(QuadraticBezier& left, QuadraticBezier& right) const
+ {
+ left.control = midPoint(start, control);
+ right.control = midPoint(control, end);
+
+ FloatPoint leftControlToRightControl = midPoint(left.control, right.control);
+ left.end = leftControlToRightControl;
+ right.start = leftControlToRightControl;
+
+ left.start = start;
+ right.end = end;
+ }
+
+ FloatPoint start;
+ FloatPoint control;
+ FloatPoint end;
+};
+
+struct CubicBezier {
+ CubicBezier() { }
+ CubicBezier(const FloatPoint& s, const FloatPoint& c1, const FloatPoint& c2, const FloatPoint& e)
+ : start(s)
+ , control1(c1)
+ , control2(c2)
+ , end(e)
+ {
+ }
+
+ float approximateDistance() const
+ {
+ return distanceLine(start, control1) + distanceLine(control1, control2) + distanceLine(control2, end);
+ }
+
+ void split(CubicBezier& left, CubicBezier& right) const
+ {
+ FloatPoint startToControl1 = midPoint(control1, control2);
+
+ left.start = start;
+ left.control1 = midPoint(start, control1);
+ left.control2 = midPoint(left.control1, startToControl1);
+
+ right.control2 = midPoint(control2, end);
+ right.control1 = midPoint(right.control2, startToControl1);
+ right.end = end;
+
+ FloatPoint leftControl2ToRightControl1 = midPoint(left.control2, right.control1);
+ left.end = leftControl2ToRightControl1;
+ right.start = leftControl2ToRightControl1;
+ }
+
+ FloatPoint start;
+ FloatPoint control1;
+ FloatPoint control2;
+ FloatPoint end;
+};
+
+// FIXME: This function is possibly very slow due to the ifs required for proper path measuring
+// A simple speed-up would be to use an additional boolean template parameter to control whether
+// to use the "fast" version of this function with no PathTraversalState updating, vs. the slow
+// version which does update the PathTraversalState. We'll have to shark it to see if that's necessary.
+// Another check which is possible up-front (to send us down the fast path) would be to check if
+// approximateDistance() + current total distance > desired distance
+template<class CurveType>
+static float curveLength(PathTraversalState& traversalState, CurveType curve)
+{
+ Vector<CurveType> curveStack;
+ curveStack.append(curve);
+
+ float totalLength = 0.0f;
+ do {
+ float length = curve.approximateDistance();
+ if ((length - distanceLine(curve.start, curve.end)) > kPathSegmentLengthTolerance) {
+ CurveType left, right;
+ curve.split(left, right);
+ curve = left;
+ curveStack.append(right);
+ } else {
+ totalLength += length;
+ if (traversalState.m_action == PathTraversalState::TraversalPointAtLength
+ || traversalState.m_action == PathTraversalState::TraversalNormalAngleAtLength) {
+ traversalState.m_previous = curve.start;
+ traversalState.m_current = curve.end;
+ if (traversalState.m_totalLength + totalLength > traversalState.m_desiredLength)
+ return totalLength;
+ }
+ curve = curveStack.last();
+ curveStack.removeLast();
+ }
+ } while (!curveStack.isEmpty());
+
+ return totalLength;
+}
+
+PathTraversalState::PathTraversalState(PathTraversalAction action)
+ : m_action(action)
+ , m_success(false)
+ , m_totalLength(0.0f)
+ , m_segmentIndex(0)
+ , m_desiredLength(0.0f)
+ , m_normalAngle(0.0f)
+{
+}
+
+float PathTraversalState::closeSubpath()
+{
+ float distance = distanceLine(m_current, m_start);
+ m_current = m_control1 = m_control2 = m_start;
+ return distance;
+}
+
+float PathTraversalState::moveTo(const FloatPoint& point)
+{
+ m_current = m_start = m_control1 = m_control2 = point;
+ return 0.0f;
+}
+
+float PathTraversalState::lineTo(const FloatPoint& point)
+{
+ float distance = distanceLine(m_current, point);
+ m_current = m_control1 = m_control2 = point;
+ return distance;
+}
+
+float PathTraversalState::quadraticBezierTo(const FloatPoint& newControl, const FloatPoint& newEnd)
+{
+ float distance = curveLength<QuadraticBezier>(*this, QuadraticBezier(m_current, newControl, newEnd));
+
+ m_control1 = newControl;
+ m_control2 = newEnd;
+
+ if (m_action != TraversalPointAtLength && m_action != TraversalNormalAngleAtLength)
+ m_current = newEnd;
+
+ return distance;
+}
+
+float PathTraversalState::cubicBezierTo(const FloatPoint& newControl1, const FloatPoint& newControl2, const FloatPoint& newEnd)
+{
+ float distance = curveLength<CubicBezier>(*this, CubicBezier(m_current, newControl1, newControl2, newEnd));
+
+ m_control1 = newEnd;
+ m_control2 = newControl2;
+
+ if (m_action != TraversalPointAtLength && m_action != TraversalNormalAngleAtLength)
+ m_current = newEnd;
+
+ return distance;
+}
+
+}
+
diff --git a/Source/WebCore/platform/graphics/PathTraversalState.h b/Source/WebCore/platform/graphics/PathTraversalState.h
new file mode 100644
index 0000000..5b75767
--- /dev/null
+++ b/Source/WebCore/platform/graphics/PathTraversalState.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006, 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 PathTraversalState_h
+#define PathTraversalState_h
+
+#include "FloatPoint.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class Path;
+
+ class PathTraversalState {
+ public:
+ enum PathTraversalAction {
+ TraversalTotalLength,
+ TraversalPointAtLength,
+ TraversalSegmentAtLength,
+ TraversalNormalAngleAtLength
+ };
+
+ PathTraversalState(PathTraversalAction);
+
+ float closeSubpath();
+ float moveTo(const FloatPoint&);
+ float lineTo(const FloatPoint&);
+ float quadraticBezierTo(const FloatPoint& newControl, const FloatPoint& newEnd);
+ float cubicBezierTo(const FloatPoint& newControl1, const FloatPoint& newControl2, const FloatPoint& newEnd);
+
+ public:
+ PathTraversalAction m_action;
+ bool m_success;
+
+ FloatPoint m_current;
+ FloatPoint m_start;
+ FloatPoint m_control1;
+ FloatPoint m_control2;
+
+ float m_totalLength;
+ unsigned m_segmentIndex;
+ float m_desiredLength;
+
+ // For normal calculations
+ FloatPoint m_previous;
+ float m_normalAngle; // degrees
+ };
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/Pattern.cpp b/Source/WebCore/platform/graphics/Pattern.cpp
new file mode 100644
index 0000000..82d0a24
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Pattern.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Pattern.h"
+
+#include "Image.h"
+
+namespace WebCore {
+
+Pattern::Pattern(PassRefPtr<Image> image, bool repeatX, bool repeatY)
+ : m_tileImage(image)
+ , m_repeatX(repeatX)
+ , m_repeatY(repeatY)
+#if PLATFORM(SKIA)
+ , m_pattern(0)
+#endif
+{
+ ASSERT(m_tileImage);
+}
+
+Pattern::~Pattern()
+{
+ platformDestroy();
+}
+
+void Pattern::setPatternSpaceTransform(const AffineTransform& patternSpaceTransformation)
+{
+ m_patternSpaceTransformation = patternSpaceTransformation;
+ setPlatformPatternSpaceTransform();
+}
+
+#if !PLATFORM(SKIA)
+void Pattern::platformDestroy()
+{
+}
+
+void Pattern::setPlatformPatternSpaceTransform()
+{
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/Pattern.h b/Source/WebCore/platform/graphics/Pattern.h
new file mode 100644
index 0000000..e215f3d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Pattern.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 Pattern_h
+#define Pattern_h
+
+#include "AffineTransform.h"
+#include "Image.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if PLATFORM(CG)
+typedef struct CGPattern* CGPatternRef;
+typedef CGPatternRef PlatformPatternPtr;
+#elif PLATFORM(CAIRO)
+#include <cairo.h>
+typedef cairo_pattern_t* PlatformPatternPtr;
+#elif PLATFORM(SKIA)
+class SkShader;
+typedef SkShader* PlatformPatternPtr;
+#elif PLATFORM(QT)
+#include <QBrush>
+typedef QBrush PlatformPatternPtr;
+#elif PLATFORM(WX)
+#if USE(WXGC)
+class wxGraphicsBrush;
+typedef wxGraphicsBrush* PlatformPatternPtr;
+#else
+class wxBrush;
+typedef wxBrush* PlatformPatternPtr;
+#endif // USE(WXGC)
+#elif PLATFORM(HAIKU)
+#include <interface/GraphicsDefs.h>
+typedef pattern* PlatformPatternPtr;
+#elif OS(WINCE)
+typedef void* PlatformPatternPtr;
+#endif
+
+namespace WebCore {
+
+class AffineTransform;
+
+class Pattern : public RefCounted<Pattern> {
+public:
+ static PassRefPtr<Pattern> create(PassRefPtr<Image> tileImage, bool repeatX, bool repeatY)
+ {
+ return adoptRef(new Pattern(tileImage, repeatX, repeatY));
+ }
+ virtual ~Pattern();
+
+ Image* tileImage() const { return m_tileImage.get(); }
+
+ void platformDestroy();
+
+ // Pattern space is an abstract space that maps to the default user space by the transformation 'userSpaceTransformation'
+#if PLATFORM(SKIA)
+ PlatformPatternPtr platformPattern(const AffineTransform& userSpaceTransformation);
+#else
+ PlatformPatternPtr createPlatformPattern(const AffineTransform& userSpaceTransformation) const;
+#endif
+ void setPatternSpaceTransform(const AffineTransform& patternSpaceTransformation);
+ void setPlatformPatternSpaceTransform();
+
+ bool repeatX() const { return m_repeatX; }
+ bool repeatY() const { return m_repeatY; }
+
+private:
+ Pattern(PassRefPtr<Image>, bool repeatX, bool repeatY);
+
+ RefPtr<Image> m_tileImage;
+ bool m_repeatX;
+ bool m_repeatY;
+ AffineTransform m_patternSpaceTransformation;
+ PlatformPatternPtr m_pattern;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/WebCore/platform/graphics/Pen.cpp b/Source/WebCore/platform/graphics/Pen.cpp
new file mode 100644
index 0000000..a3dcb86
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Pen.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Pen.h"
+
+namespace WebCore {
+
+Pen::Pen(const Color &color, unsigned width, PenStyle style) : m_style(style), m_width(width), m_color(color)
+{
+}
+
+const Color &Pen::color() const
+{
+ return m_color;
+}
+
+unsigned Pen::width() const
+{
+ return m_width;
+}
+
+Pen::PenStyle Pen::style() const
+{
+ return m_style;
+}
+
+void Pen::setColor(const Color &color)
+{
+ m_color = color;
+}
+
+void Pen::setWidth(unsigned width)
+{
+ m_width = width;
+}
+
+void Pen::setStyle(PenStyle style)
+{
+ m_style = style;
+}
+
+bool Pen::operator==(const Pen &compareTo) const
+{
+ return (m_width == compareTo.m_width) &&
+ (m_style == compareTo.m_style) &&
+ (m_color == compareTo.m_color);
+}
+
+bool Pen::operator!=(const Pen &compareTo) const
+{
+ return !(*this == compareTo);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/Pen.h b/Source/WebCore/platform/graphics/Pen.h
new file mode 100644
index 0000000..cb45a2e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Pen.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2003-6 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 Pen_h
+#define Pen_h
+
+#include "Color.h"
+
+#if PLATFORM(WX)
+class wxPen;
+#endif
+
+namespace WebCore {
+
+class Pen {
+public:
+ enum PenStyle {
+ NoPen,
+ SolidLine,
+ DotLine,
+ DashLine
+ };
+
+ Pen(const Color &c = Color::black, unsigned w = 0, PenStyle ps = SolidLine);
+
+ const Color &color() const;
+ unsigned width() const;
+ PenStyle style() const;
+
+ void setColor(const Color &);
+ void setWidth(unsigned);
+ void setStyle(PenStyle);
+
+ bool operator==(const Pen &) const;
+ bool operator!=(const Pen &) const;
+
+#if PLATFORM(WX)
+ Pen(const wxPen&);
+ operator wxPen() const;
+#endif
+
+private:
+ PenStyle m_style;
+ unsigned m_width;
+ Color m_color;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/SegmentedFontData.cpp b/Source/WebCore/platform/graphics/SegmentedFontData.cpp
new file mode 100644
index 0000000..7e10040
--- /dev/null
+++ b/Source/WebCore/platform/graphics/SegmentedFontData.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2008, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "SegmentedFontData.h"
+
+#include "PlatformString.h"
+#include "SimpleFontData.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+SegmentedFontData::~SegmentedFontData()
+{
+}
+
+const SimpleFontData* SegmentedFontData::fontDataForCharacter(UChar32 c) const
+{
+ Vector<FontDataRange>::const_iterator end = m_ranges.end();
+ for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) {
+ if (it->from() <= c && it->to() >= c)
+ return it->fontData();
+ }
+ return m_ranges[0].fontData();
+}
+
+bool SegmentedFontData::containsCharacter(UChar32 c) const
+{
+ Vector<FontDataRange>::const_iterator end = m_ranges.end();
+ for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) {
+ if (c >= it->from() && c <= it->to())
+ return true;
+ }
+ return false;
+}
+
+bool SegmentedFontData::containsCharacters(const UChar* characters, int length) const
+{
+ UChar32 c;
+ for (int i = 0; i < length; ) {
+ U16_NEXT(characters, i, length, c)
+ if (!containsCharacter(c))
+ return false;
+ }
+ return true;
+}
+
+bool SegmentedFontData::isCustomFont() const
+{
+ // All segmented fonts are custom fonts.
+ return true;
+}
+
+bool SegmentedFontData::isLoading() const
+{
+ Vector<FontDataRange>::const_iterator end = m_ranges.end();
+ for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) {
+ if (it->fontData()->isLoading())
+ return true;
+ }
+ return false;
+}
+
+bool SegmentedFontData::isSegmented() const
+{
+ return true;
+}
+
+#ifndef NDEBUG
+String SegmentedFontData::description() const
+{
+ return "[segmented font]";
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/SegmentedFontData.h b/Source/WebCore/platform/graphics/SegmentedFontData.h
new file mode 100644
index 0000000..645dc0d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/SegmentedFontData.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 SegmentedFontData_h
+#define SegmentedFontData_h
+
+#include "FontData.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class SimpleFontData;
+
+struct FontDataRange {
+ FontDataRange(UChar32 from, UChar32 to, const SimpleFontData* fontData)
+ : m_from(from)
+ , m_to(to)
+ , m_fontData(fontData)
+ {
+ }
+
+ UChar32 from() const { return m_from; }
+ UChar32 to() const { return m_to; }
+ const SimpleFontData* fontData() const { return m_fontData; }
+
+private:
+ UChar32 m_from;
+ UChar32 m_to;
+ const SimpleFontData* m_fontData;
+};
+
+class SegmentedFontData : public FontData {
+public:
+ virtual ~SegmentedFontData();
+
+ void appendRange(const FontDataRange& range) { m_ranges.append(range); }
+ unsigned numRanges() const { return m_ranges.size(); }
+ const FontDataRange& rangeAt(unsigned i) const { return m_ranges[i]; }
+
+#ifndef NDEBUG
+ virtual String description() const;
+#endif
+
+private:
+ virtual const SimpleFontData* fontDataForCharacter(UChar32) const;
+ virtual bool containsCharacters(const UChar*, int length) const;
+
+ virtual bool isCustomFont() const;
+ virtual bool isLoading() const;
+ virtual bool isSegmented() const;
+
+ bool containsCharacter(UChar32) const;
+
+ Vector<FontDataRange, 1> m_ranges;
+};
+
+} // namespace WebCore
+
+#endif // SegmentedFontData_h
diff --git a/Source/WebCore/platform/graphics/SimpleFontData.cpp b/Source/WebCore/platform/graphics/SimpleFontData.cpp
new file mode 100644
index 0000000..e773880
--- /dev/null
+++ b/Source/WebCore/platform/graphics/SimpleFontData.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2005, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "Font.h"
+#include "FontCache.h"
+
+#if ENABLE(SVG_FONTS)
+#include "SVGFontData.h"
+#include "SVGFontElement.h"
+#include "SVGFontFaceElement.h"
+#include "SVGGlyphElement.h"
+#endif
+
+#include <wtf/MathExtras.h>
+#include <wtf/UnusedParam.h>
+
+using namespace std;
+
+namespace WebCore {
+
+SimpleFontData::SimpleFontData(const FontPlatformData& platformData, bool isCustomFont, bool isLoading)
+ : m_maxCharWidth(-1)
+ , m_avgCharWidth(-1)
+ , m_unitsPerEm(defaultUnitsPerEm)
+ , m_orientation(platformData.orientation())
+ , m_platformData(platformData)
+ , m_treatAsFixedPitch(false)
+ , m_isCustomFont(isCustomFont)
+ , m_isLoading(isLoading)
+ , m_isBrokenIdeographFont(false)
+{
+ platformInit();
+ platformGlyphInit();
+ platformCharWidthInit();
+}
+
+#if ENABLE(SVG_FONTS)
+SimpleFontData::SimpleFontData(PassOwnPtr<SVGFontData> svgFontData, int size, bool syntheticBold, bool syntheticItalic)
+ : m_orientation(Horizontal)
+ , m_platformData(FontPlatformData(size, syntheticBold, syntheticItalic))
+ , m_treatAsFixedPitch(false)
+ , m_svgFontData(svgFontData)
+ , m_isCustomFont(true)
+ , m_isLoading(false)
+ , m_isBrokenIdeographFont(false)
+{
+ SVGFontFaceElement* svgFontFaceElement = m_svgFontData->svgFontFaceElement();
+ m_unitsPerEm = svgFontFaceElement->unitsPerEm();
+
+ double scale = size;
+ if (m_unitsPerEm)
+ scale /= m_unitsPerEm;
+
+ m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale);
+ m_descent = static_cast<int>(svgFontFaceElement->descent() * scale);
+ m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale);
+ m_lineGap = 0.1f * size;
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
+
+ Vector<SVGGlyphIdentifier> spaceGlyphs;
+ associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs);
+ m_spaceWidth = spaceGlyphs.isEmpty() ? m_xHeight : static_cast<float>(spaceGlyphs.first().horizontalAdvanceX * scale);
+
+ Vector<SVGGlyphIdentifier> numeralZeroGlyphs;
+ associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs);
+ m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : static_cast<float>(numeralZeroGlyphs.first().horizontalAdvanceX * scale);
+
+ Vector<SVGGlyphIdentifier> letterWGlyphs;
+ associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs);
+ m_maxCharWidth = letterWGlyphs.isEmpty() ? m_ascent : static_cast<float>(letterWGlyphs.first().horizontalAdvanceX * scale);
+
+ // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above?
+ m_spaceGlyph = 0;
+ m_zeroWidthSpaceGlyph = 0;
+ determinePitch();
+ m_adjustedSpaceWidth = roundf(m_spaceWidth);
+ m_missingGlyphData.fontData = this;
+ m_missingGlyphData.glyph = 0;
+}
+#endif
+
+#if !PLATFORM(QT)
+// Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font.
+void SimpleFontData::initCharWidths()
+{
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+
+ // Treat the width of a '0' as the avgCharWidth.
+ if (m_avgCharWidth <= 0.f && glyphPageZero) {
+ static const UChar32 digitZeroChar = '0';
+ Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph;
+ if (digitZeroGlyph)
+ m_avgCharWidth = widthForGlyph(digitZeroGlyph);
+ }
+
+ // If we can't retrieve the width of a '0', fall back to the x height.
+ if (m_avgCharWidth <= 0.f)
+ m_avgCharWidth = m_xHeight;
+
+ if (m_maxCharWidth <= 0.f)
+ m_maxCharWidth = max<float>(m_avgCharWidth, m_ascent);
+}
+
+void SimpleFontData::platformGlyphInit()
+{
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+ if (!glyphPageZero) {
+ LOG_ERROR("Failed to get glyph page zero.");
+ m_spaceGlyph = 0;
+ m_spaceWidth = 0;
+ m_adjustedSpaceWidth = 0;
+ determinePitch();
+ m_zeroWidthSpaceGlyph = 0;
+ m_missingGlyphData.fontData = this;
+ m_missingGlyphData.glyph = 0;
+ return;
+ }
+
+ m_zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph;
+
+ // Nasty hack to determine if we should round or ceil space widths.
+ // If the font is monospace or fake monospace we ceil to ensure that
+ // every character and the space are the same width. Otherwise we round.
+ m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
+ float width = widthForGlyph(m_spaceGlyph);
+ m_spaceWidth = width;
+ determinePitch();
+ m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
+
+ // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE.
+ // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph.
+ // See <http://bugs.webkit.org/show_bug.cgi?id=13178>
+ // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
+ // are mapped to the ZERO WIDTH SPACE glyph.
+ if (m_zeroWidthSpaceGlyph == m_spaceGlyph) {
+ m_zeroWidthSpaceGlyph = 0;
+ LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. Glyph width will not be overridden.");
+ }
+
+ m_missingGlyphData.fontData = this;
+ m_missingGlyphData.glyph = 0;
+}
+#endif
+
+SimpleFontData::~SimpleFontData()
+{
+#if ENABLE(SVG_FONTS)
+ if (!m_svgFontData || !m_svgFontData->svgFontFaceElement())
+#endif
+ platformDestroy();
+
+ if (!isCustomFont())
+ GlyphPageTreeNode::pruneTreeFontData(this);
+}
+
+const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
+{
+ return this;
+}
+
+bool SimpleFontData::isSegmented() const
+{
+ return false;
+}
+
+SimpleFontData* SimpleFontData::brokenIdeographFontData() const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->brokenIdeograph) {
+ m_derivedFontData->brokenIdeograph = new SimpleFontData(m_platformData, isCustomFont(), false);
+ m_derivedFontData->brokenIdeograph->m_orientation = Vertical;
+ m_derivedFontData->brokenIdeograph->m_isBrokenIdeographFont = true;
+ }
+ return m_derivedFontData->brokenIdeograph.get();
+}
+
+#ifndef NDEBUG
+String SimpleFontData::description() const
+{
+ if (isSVGFont())
+ return "[SVG font]";
+ if (isCustomFont())
+ return "[custom font]";
+
+ return platformData().description();
+}
+#endif
+
+PassOwnPtr<SimpleFontData::DerivedFontData> SimpleFontData::DerivedFontData::create(bool forCustomFont)
+{
+ return adoptPtr(new DerivedFontData(forCustomFont));
+}
+
+SimpleFontData::DerivedFontData::~DerivedFontData()
+{
+ if (!forCustomFont)
+ return;
+
+ if (smallCaps)
+ GlyphPageTreeNode::pruneTreeCustomFontData(smallCaps.get());
+ if (emphasisMark)
+ GlyphPageTreeNode::pruneTreeCustomFontData(emphasisMark.get());
+ if (brokenIdeograph)
+ GlyphPageTreeNode::pruneTreeCustomFontData(brokenIdeograph.get());
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/SimpleFontData.h b/Source/WebCore/platform/graphics/SimpleFontData.h
new file mode 100644
index 0000000..90713af
--- /dev/null
+++ b/Source/WebCore/platform/graphics/SimpleFontData.h
@@ -0,0 +1,339 @@
+/*
+ * This file is part of the internal font implementation.
+ *
+ * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SimpleFontData_h
+#define SimpleFontData_h
+
+#include "FontBaseline.h"
+#include "FontData.h"
+#include "FontPlatformData.h"
+#include "FloatRect.h"
+#include "GlyphMetricsMap.h"
+#include "GlyphPageTreeNode.h"
+#include "TypesettingFeatures.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+#if USE(ATSUI)
+typedef struct OpaqueATSUStyle* ATSUStyle;
+#endif
+
+#if PLATFORM(MAC) || USE(CORE_TEXT)
+#include <wtf/RetainPtr.h>
+#endif
+
+#if (PLATFORM(WIN) && !OS(WINCE)) \
+ || (OS(WINDOWS) && PLATFORM(WX))
+#include <usp10.h>
+#endif
+
+#if PLATFORM(CAIRO)
+#include <cairo.h>
+#endif
+
+#if PLATFORM(QT)
+#include <QFont>
+#endif
+
+#if PLATFORM(HAIKU)
+#include <Font.h>
+#endif
+
+namespace WebCore {
+
+class FontDescription;
+class SharedBuffer;
+class SVGFontData;
+
+enum FontDataVariant { AutoVariant, NormalVariant, SmallCapsVariant, EmphasisMarkVariant };
+enum Pitch { UnknownPitch, FixedPitch, VariablePitch };
+
+class SimpleFontData : public FontData {
+public:
+ SimpleFontData(const FontPlatformData&, bool isCustomFont = false, bool isLoading = false);
+#if ENABLE(SVG_FONTS)
+ SimpleFontData(PassOwnPtr<SVGFontData>, int size, bool syntheticBold, bool syntheticItalic);
+#endif
+ virtual ~SimpleFontData();
+
+ const FontPlatformData& platformData() const { return m_platformData; }
+
+ SimpleFontData* smallCapsFontData(const FontDescription&) const;
+ SimpleFontData* emphasisMarkFontData(const FontDescription&) const;
+
+ SimpleFontData* variantFontData(const FontDescription& description, FontDataVariant variant) const
+ {
+ switch (variant) {
+ case SmallCapsVariant:
+ return smallCapsFontData(description);
+ case EmphasisMarkVariant:
+ return emphasisMarkFontData(description);
+ case AutoVariant:
+ case NormalVariant:
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ return const_cast<SimpleFontData*>(this);
+ }
+
+ SimpleFontData* brokenIdeographFontData() const;
+
+ // FIXME: Use the actual metrics for fonts with vertical tables instead of just hard-coding. If the font is horizontally oriented or
+ // a broken ideographic font, then just hard-code to split ascent/descent down the middle. Otherwise we should actually use the metrics
+ // from the font itself.
+ int ascent(FontBaseline baselineType = AlphabeticBaseline) const { return baselineType == AlphabeticBaseline ? m_ascent : height() - height() / 2; }
+ int descent(FontBaseline baselineType = AlphabeticBaseline) const { return baselineType == AlphabeticBaseline ? m_descent : height() / 2; }
+ int height() const { return m_ascent + m_descent; }
+ int lineSpacing() const { return m_lineSpacing; }
+ int lineGap() const { return m_lineGap; }
+ float maxCharWidth() const { return m_maxCharWidth; }
+ float avgCharWidth() const { return m_avgCharWidth; }
+ float xHeight() const { return m_xHeight; }
+ unsigned unitsPerEm() const { return m_unitsPerEm; }
+
+ FloatRect boundsForGlyph(Glyph) const;
+ float widthForGlyph(Glyph glyph) const;
+ FloatRect platformBoundsForGlyph(Glyph) const;
+ float platformWidthForGlyph(Glyph) const;
+
+ float spaceWidth() const { return m_spaceWidth; }
+ float adjustedSpaceWidth() const { return m_adjustedSpaceWidth; }
+
+#if PLATFORM(CG) || PLATFORM(CAIRO) || PLATFORM(WX)
+ float syntheticBoldOffset() const { return m_syntheticBoldOffset; }
+#endif
+
+ Glyph spaceGlyph() const { return m_spaceGlyph; }
+ bool isZeroWidthSpaceGlyph(Glyph glyph) const { return glyph == m_zeroWidthSpaceGlyph && glyph; }
+
+ virtual const SimpleFontData* fontDataForCharacter(UChar32) const;
+ virtual bool containsCharacters(const UChar*, int length) const;
+
+ void determinePitch();
+ Pitch pitch() const { return m_treatAsFixedPitch ? FixedPitch : VariablePitch; }
+
+#if ENABLE(SVG_FONTS)
+ SVGFontData* svgFontData() const { return m_svgFontData.get(); }
+ bool isSVGFont() const { return m_svgFontData; }
+#else
+ bool isSVGFont() const { return false; }
+#endif
+
+ virtual bool isCustomFont() const { return m_isCustomFont; }
+ virtual bool isLoading() const { return m_isLoading; }
+ virtual bool isSegmented() const;
+
+ bool isBrokenIdeographFont() const { return m_isBrokenIdeographFont; }
+
+ const GlyphData& missingGlyphData() const { return m_missingGlyphData; }
+
+#ifndef NDEBUG
+ virtual String description() const;
+#endif
+
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
+ NSFont* getNSFont() const { return m_platformData.font(); }
+#elif (PLATFORM(WX) && OS(DARWIN))
+ NSFont* getNSFont() const { return m_platformData.nsFont(); }
+#endif
+
+#if PLATFORM(MAC) || USE(CORE_TEXT)
+ CFDictionaryRef getCFStringAttributes(TypesettingFeatures) const;
+#endif
+
+#if USE(ATSUI)
+ void checkShapesArabic() const;
+ bool shapesArabic() const
+ {
+ if (!m_checkedShapesArabic)
+ checkShapesArabic();
+ return m_shapesArabic;
+ }
+#endif
+
+#if PLATFORM(QT)
+ QFont getQtFont() const { return m_platformData.font(); }
+#endif
+
+#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX))
+ bool isSystemFont() const { return m_isSystemFont; }
+#if !OS(WINCE) // disable unused members to save space
+ SCRIPT_FONTPROPERTIES* scriptFontProperties() const;
+ SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; }
+#endif
+ static void setShouldApplyMacAscentHack(bool);
+ static bool shouldApplyMacAscentHack();
+#endif
+
+#if PLATFORM(WX)
+ wxFont* getWxFont() const { return m_platformData.font(); }
+#endif
+
+ FontOrientation orientation() const { return m_orientation; }
+
+private:
+ void platformInit();
+ void platformGlyphInit();
+ void platformCharWidthInit();
+ void platformDestroy();
+
+ void initCharWidths();
+
+ void commonInit();
+
+ SimpleFontData* scaledFontData(const FontDescription&, float scaleFactor) const;
+
+#if (PLATFORM(WIN) && !OS(WINCE)) \
+ || (OS(WINDOWS) && PLATFORM(WX))
+ void initGDIFont();
+ void platformCommonDestroy();
+ FloatRect boundsForGDIGlyph(Glyph glyph) const;
+ float widthForGDIGlyph(Glyph glyph) const;
+#endif
+
+ int m_ascent;
+ int m_descent;
+ int m_lineSpacing;
+ int m_lineGap;
+ float m_maxCharWidth;
+ float m_avgCharWidth;
+ float m_xHeight;
+ unsigned m_unitsPerEm;
+
+ FontOrientation m_orientation; // This is our supported orientation according to the tables in the font. FontPlatformData will just always have the desired orientation.
+ // This value represents what we actually support.
+
+ FontPlatformData m_platformData;
+
+ mutable OwnPtr<GlyphMetricsMap<FloatRect> > m_glyphToBoundsMap;
+ mutable GlyphMetricsMap<float> m_glyphToWidthMap;
+
+ bool m_treatAsFixedPitch;
+
+#if ENABLE(SVG_FONTS)
+ OwnPtr<SVGFontData> m_svgFontData;
+#endif
+
+ bool m_isCustomFont; // Whether or not we are custom font loaded via @font-face
+ bool m_isLoading; // Whether or not this custom font is still in the act of loading.
+ bool m_isBrokenIdeographFont;
+
+ Glyph m_spaceGlyph;
+ float m_spaceWidth;
+ float m_adjustedSpaceWidth;
+
+ Glyph m_zeroWidthSpaceGlyph;
+
+ GlyphData m_missingGlyphData;
+
+ struct DerivedFontData {
+ static PassOwnPtr<DerivedFontData> create(bool forCustomFont);
+ ~DerivedFontData();
+
+ bool forCustomFont;
+ OwnPtr<SimpleFontData> smallCaps;
+ OwnPtr<SimpleFontData> emphasisMark;
+ OwnPtr<SimpleFontData> brokenIdeograph;
+
+ private:
+ DerivedFontData(bool custom)
+ : forCustomFont(custom)
+ {
+ }
+ };
+
+ mutable OwnPtr<DerivedFontData> m_derivedFontData;
+
+#if PLATFORM(CG) || PLATFORM(CAIRO) || PLATFORM(WX)
+ float m_syntheticBoldOffset;
+#endif
+
+#ifdef BUILDING_ON_TIGER
+public:
+ void* m_styleGroup;
+
+private:
+#endif
+
+#if USE(ATSUI)
+public:
+ mutable HashMap<unsigned, ATSUStyle> m_ATSUStyleMap;
+ mutable bool m_ATSUMirrors;
+ mutable bool m_checkedShapesArabic;
+ mutable bool m_shapesArabic;
+
+private:
+#endif
+
+#if PLATFORM(MAC) || USE(CORE_TEXT)
+ mutable HashMap<unsigned, RetainPtr<CFDictionaryRef> > m_CFStringAttributes;
+#endif
+
+#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX))
+ bool m_isSystemFont;
+#if !OS(WINCE) // disable unused members to save space
+ mutable SCRIPT_CACHE m_scriptCache;
+ mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties;
+#endif
+#endif
+};
+
+
+#if !PLATFORM(QT)
+ALWAYS_INLINE FloatRect SimpleFontData::boundsForGlyph(Glyph glyph) const
+{
+ if (isZeroWidthSpaceGlyph(glyph))
+ return FloatRect();
+
+ FloatRect bounds;
+ if (m_glyphToBoundsMap) {
+ bounds = m_glyphToBoundsMap->metricsForGlyph(glyph);
+ if (bounds.width() != cGlyphSizeUnknown)
+ return bounds;
+ }
+
+ bounds = platformBoundsForGlyph(glyph);
+ if (!m_glyphToBoundsMap)
+ m_glyphToBoundsMap = adoptPtr(new GlyphMetricsMap<FloatRect>);
+ m_glyphToBoundsMap->setMetricsForGlyph(glyph, bounds);
+ return bounds;
+}
+
+ALWAYS_INLINE float SimpleFontData::widthForGlyph(Glyph glyph) const
+{
+ if (isZeroWidthSpaceGlyph(glyph))
+ return 0;
+
+ float width = m_glyphToWidthMap.metricsForGlyph(glyph);
+ if (width != cGlyphSizeUnknown)
+ return width;
+
+ width = platformWidthForGlyph(glyph);
+ m_glyphToWidthMap.setMetricsForGlyph(glyph, width);
+ return width;
+}
+#endif
+
+} // namespace WebCore
+
+#endif // SimpleFontData_h
diff --git a/Source/WebCore/platform/graphics/StringTruncator.cpp b/Source/WebCore/platform/graphics/StringTruncator.cpp
new file mode 100644
index 0000000..b6c86ce
--- /dev/null
+++ b/Source/WebCore/platform/graphics/StringTruncator.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "StringTruncator.h"
+
+#include "CharacterNames.h"
+#include "Font.h"
+#include "TextBreakIterator.h"
+#include <wtf/Assertions.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+#define STRING_BUFFER_SIZE 2048
+
+typedef unsigned TruncationFunction(const String&, unsigned length, unsigned keepCount, UChar* buffer);
+
+static inline int textBreakAtOrPreceding(TextBreakIterator* it, int offset)
+{
+ if (isTextBreak(it, offset))
+ return offset;
+
+ int result = textBreakPreceding(it, offset);
+ return result == TextBreakDone ? 0 : result;
+}
+
+static inline int boundedTextBreakFollowing(TextBreakIterator* it, int offset, int length)
+{
+ int result = textBreakFollowing(it, offset);
+ return result == TextBreakDone ? length : result;
+}
+
+static unsigned centerTruncateToBuffer(const String& string, unsigned length, unsigned keepCount, UChar* buffer)
+{
+ ASSERT(keepCount < length);
+ ASSERT(keepCount < STRING_BUFFER_SIZE);
+
+ unsigned omitStart = (keepCount + 1) / 2;
+ TextBreakIterator* it = characterBreakIterator(string.characters(), length);
+ unsigned omitEnd = boundedTextBreakFollowing(it, omitStart + (length - keepCount) - 1, length);
+ omitStart = textBreakAtOrPreceding(it, omitStart);
+
+ unsigned truncatedLength = omitStart + 1 + (length - omitEnd);
+ ASSERT(truncatedLength <= length);
+
+ memcpy(buffer, string.characters(), sizeof(UChar) * omitStart);
+ buffer[omitStart] = horizontalEllipsis;
+ memcpy(&buffer[omitStart + 1], &string.characters()[omitEnd], sizeof(UChar) * (length - omitEnd));
+
+ return truncatedLength;
+}
+
+static unsigned rightTruncateToBuffer(const String& string, unsigned length, unsigned keepCount, UChar* buffer)
+{
+ ASSERT(keepCount < length);
+ ASSERT(keepCount < STRING_BUFFER_SIZE);
+
+ TextBreakIterator* it = characterBreakIterator(string.characters(), length);
+ unsigned keepLength = textBreakAtOrPreceding(it, keepCount);
+ unsigned truncatedLength = keepLength + 1;
+
+ memcpy(buffer, string.characters(), sizeof(UChar) * keepLength);
+ buffer[keepLength] = horizontalEllipsis;
+
+ return truncatedLength;
+}
+
+static float stringWidth(const Font& renderer, const UChar* characters, unsigned length, bool disableRoundingHacks)
+{
+ TextRun run(characters, length);
+ if (disableRoundingHacks)
+ run.disableRoundingHacks();
+ return renderer.floatWidth(run);
+}
+
+static String truncateString(const String& string, float maxWidth, const Font& font, TruncationFunction truncateToBuffer, bool disableRoundingHacks)
+{
+ if (string.isEmpty())
+ return string;
+
+ ASSERT(maxWidth >= 0);
+
+ float currentEllipsisWidth = stringWidth(font, &horizontalEllipsis, 1, disableRoundingHacks);
+
+ UChar stringBuffer[STRING_BUFFER_SIZE];
+ unsigned truncatedLength;
+ unsigned keepCount;
+ unsigned length = string.length();
+
+ if (length > STRING_BUFFER_SIZE) {
+ keepCount = STRING_BUFFER_SIZE - 1; // need 1 character for the ellipsis
+ truncatedLength = centerTruncateToBuffer(string, length, keepCount, stringBuffer);
+ } else {
+ keepCount = length;
+ memcpy(stringBuffer, string.characters(), sizeof(UChar) * length);
+ truncatedLength = length;
+ }
+
+ float width = stringWidth(font, stringBuffer, truncatedLength, disableRoundingHacks);
+ if (width <= maxWidth)
+ return string;
+
+ unsigned keepCountForLargestKnownToFit = 0;
+ float widthForLargestKnownToFit = currentEllipsisWidth;
+
+ unsigned keepCountForSmallestKnownToNotFit = keepCount;
+ float widthForSmallestKnownToNotFit = width;
+
+ if (currentEllipsisWidth >= maxWidth) {
+ keepCountForLargestKnownToFit = 1;
+ keepCountForSmallestKnownToNotFit = 2;
+ }
+
+ while (keepCountForLargestKnownToFit + 1 < keepCountForSmallestKnownToNotFit) {
+ ASSERT(widthForLargestKnownToFit <= maxWidth);
+ ASSERT(widthForSmallestKnownToNotFit > maxWidth);
+
+ float ratio = (keepCountForSmallestKnownToNotFit - keepCountForLargestKnownToFit)
+ / (widthForSmallestKnownToNotFit - widthForLargestKnownToFit);
+ keepCount = static_cast<unsigned>(maxWidth * ratio);
+
+ if (keepCount <= keepCountForLargestKnownToFit) {
+ keepCount = keepCountForLargestKnownToFit + 1;
+ } else if (keepCount >= keepCountForSmallestKnownToNotFit) {
+ keepCount = keepCountForSmallestKnownToNotFit - 1;
+ }
+
+ ASSERT(keepCount < length);
+ ASSERT(keepCount > 0);
+ ASSERT(keepCount < keepCountForSmallestKnownToNotFit);
+ ASSERT(keepCount > keepCountForLargestKnownToFit);
+
+ truncatedLength = truncateToBuffer(string, length, keepCount, stringBuffer);
+
+ width = stringWidth(font, stringBuffer, truncatedLength, disableRoundingHacks);
+ if (width <= maxWidth) {
+ keepCountForLargestKnownToFit = keepCount;
+ widthForLargestKnownToFit = width;
+ } else {
+ keepCountForSmallestKnownToNotFit = keepCount;
+ widthForSmallestKnownToNotFit = width;
+ }
+ }
+
+ if (keepCountForLargestKnownToFit == 0) {
+ keepCountForLargestKnownToFit = 1;
+ }
+
+ if (keepCount != keepCountForLargestKnownToFit) {
+ keepCount = keepCountForLargestKnownToFit;
+ truncatedLength = truncateToBuffer(string, length, keepCount, stringBuffer);
+ }
+
+ return String(stringBuffer, truncatedLength);
+}
+
+String StringTruncator::centerTruncate(const String& string, float maxWidth, const Font& font, bool disableRoundingHacks)
+{
+ return truncateString(string, maxWidth, font, centerTruncateToBuffer, disableRoundingHacks);
+}
+
+String StringTruncator::rightTruncate(const String& string, float maxWidth, const Font& font, bool disableRoundingHacks)
+{
+ return truncateString(string, maxWidth, font, rightTruncateToBuffer, disableRoundingHacks);
+}
+
+float StringTruncator::width(const String& string, const Font& font, bool disableRoundingHacks)
+{
+ return stringWidth(font, string.characters(), string.length(), disableRoundingHacks);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/StringTruncator.h b/Source/WebCore/platform/graphics/StringTruncator.h
new file mode 100644
index 0000000..6791d38
--- /dev/null
+++ b/Source/WebCore/platform/graphics/StringTruncator.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 StringTruncator_h
+#define StringTruncator_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+ class Font;
+
+ class StringTruncator {
+ public:
+ static String centerTruncate(const String&, float maxWidth, const Font&, bool disableRoundingHacks = true);
+ static String rightTruncate(const String&, float maxWidth, const Font&, bool disableRoundingHacks = true);
+ static float width(const String&, const Font&, bool disableRoundingHacks = true);
+ };
+
+} // namespace WebCore
+
+#endif // !defined(StringTruncator_h)
diff --git a/Source/WebCore/platform/graphics/StrokeStyleApplier.h b/Source/WebCore/platform/graphics/StrokeStyleApplier.h
new file mode 100644
index 0000000..e40d3d1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/StrokeStyleApplier.h
@@ -0,0 +1,38 @@
+/*
+ Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef StrokeStyleApplier_h
+#define StrokeStyleApplier_h
+
+namespace WebCore {
+
+ class GraphicsContext;
+
+ class StrokeStyleApplier {
+ public:
+ virtual void strokeStyle(GraphicsContext*) = 0;
+
+ protected:
+ StrokeStyleApplier() {}
+ virtual ~StrokeStyleApplier() {}
+ };
+}
+
+#endif
+
diff --git a/Source/WebCore/platform/graphics/TextRenderingMode.h b/Source/WebCore/platform/graphics/TextRenderingMode.h
new file mode 100644
index 0000000..4f817a4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/TextRenderingMode.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 TextRenderingMode_h
+#define TextRenderingMode_h
+
+namespace WebCore {
+
+ enum TextRenderingMode { AutoTextRendering, OptimizeSpeed, OptimizeLegibility, GeometricPrecision };
+
+} // namespace WebCore
+
+#endif // TextRenderingMode_h
diff --git a/Source/WebCore/platform/graphics/TextRun.h b/Source/WebCore/platform/graphics/TextRun.h
new file mode 100644
index 0000000..dce5535
--- /dev/null
+++ b/Source/WebCore/platform/graphics/TextRun.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006, 2007 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TextRun_h
+#define TextRun_h
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class RenderObject;
+class RenderSVGResource;
+
+class TextRun {
+public:
+ TextRun(const UChar* c, int len, bool allowTabs = false, int xpos = 0, int padding = 0, bool rtl = false, bool directionalOverride = false,
+ bool applyRunRounding = true, bool applyWordRounding = true)
+ : m_characters(c)
+ , m_len(len)
+ , m_xpos(xpos)
+ , m_padding(padding)
+#if ENABLE(SVG)
+ , m_horizontalGlyphStretch(1)
+#endif
+ , m_allowTabs(allowTabs)
+ , m_rtl(rtl)
+ , m_directionalOverride(directionalOverride)
+ , m_applyRunRounding(applyRunRounding)
+ , m_applyWordRounding(applyWordRounding)
+ , m_disableSpacing(false)
+#if ENABLE(SVG_FONTS)
+ , m_referencingRenderObject(0)
+ , m_activePaintingResource(0)
+#endif
+ {
+ }
+
+ TextRun(const String& s, bool allowTabs = false, int xpos = 0, int padding = 0, bool rtl = false, bool directionalOverride = false,
+ bool applyRunRounding = true, bool applyWordRounding = true)
+ : m_characters(s.characters())
+ , m_len(s.length())
+ , m_xpos(xpos)
+ , m_padding(padding)
+#if ENABLE(SVG)
+ , m_horizontalGlyphStretch(1)
+#endif
+ , m_allowTabs(allowTabs)
+ , m_rtl(rtl)
+ , m_directionalOverride(directionalOverride)
+ , m_applyRunRounding(applyRunRounding)
+ , m_applyWordRounding(applyWordRounding)
+ , m_disableSpacing(false)
+#if ENABLE(SVG_FONTS)
+ , m_referencingRenderObject(0)
+ , m_activePaintingResource(0)
+#endif
+ {
+ }
+
+ UChar operator[](int i) const { return m_characters[i]; }
+ const UChar* data(int i) const { return &m_characters[i]; }
+
+ const UChar* characters() const { return m_characters; }
+ int length() const { return m_len; }
+
+ void setText(const UChar* c, int len) { m_characters = c; m_len = len; }
+
+#if ENABLE(SVG)
+ float horizontalGlyphStretch() const { return m_horizontalGlyphStretch; }
+ void setHorizontalGlyphStretch(float scale) { m_horizontalGlyphStretch = scale; }
+#endif
+
+ bool allowTabs() const { return m_allowTabs; }
+ int xPos() const { return m_xpos; }
+ int padding() const { return m_padding; }
+ bool rtl() const { return m_rtl; }
+ bool ltr() const { return !m_rtl; }
+ bool directionalOverride() const { return m_directionalOverride; }
+ bool applyRunRounding() const { return m_applyRunRounding; }
+ bool applyWordRounding() const { return m_applyWordRounding; }
+ bool spacingDisabled() const { return m_disableSpacing; }
+
+ void disableSpacing() { m_disableSpacing = true; }
+ void disableRoundingHacks() { m_applyRunRounding = m_applyWordRounding = false; }
+ void setRTL(bool b) { m_rtl = b; }
+ void setDirectionalOverride(bool override) { m_directionalOverride = override; }
+
+#if ENABLE(SVG_FONTS)
+ RenderObject* referencingRenderObject() const { return m_referencingRenderObject; }
+ void setReferencingRenderObject(RenderObject* object) { m_referencingRenderObject = object; }
+
+ RenderSVGResource* activePaintingResource() const { return m_activePaintingResource; }
+ void setActivePaintingResource(RenderSVGResource* object) { m_activePaintingResource = object; }
+#endif
+
+private:
+ const UChar* m_characters;
+ int m_len;
+
+ // m_xpos is the x position relative to the left start of the text line, not relative to the left
+ // start of the containing block. In the case of right alignment or center alignment, left start of
+ // the text line is not the same as left start of the containing block.
+ int m_xpos;
+ int m_padding;
+#if ENABLE(SVG)
+ float m_horizontalGlyphStretch;
+#endif
+ bool m_allowTabs;
+ bool m_rtl;
+ bool m_directionalOverride;
+ bool m_applyRunRounding;
+ bool m_applyWordRounding;
+ bool m_disableSpacing;
+
+#if ENABLE(SVG_FONTS)
+ RenderObject* m_referencingRenderObject;
+ RenderSVGResource* m_activePaintingResource;
+#endif
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/Tile.h b/Source/WebCore/platform/graphics/Tile.h
new file mode 100644
index 0000000..c623ec9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/Tile.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef Tile_h
+#define Tile_h
+
+#if ENABLE(TILED_BACKING_STORE)
+
+#include "IntPoint.h"
+#include "IntPointHash.h"
+#include "IntRect.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+#if PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QPixmap;
+class QRegion;
+QT_END_NAMESPACE
+#endif
+
+namespace WebCore {
+
+class GraphicsContext;
+class TiledBackingStore;
+
+class Tile : public RefCounted<Tile> {
+public:
+ typedef IntPoint Coordinate;
+
+ static PassRefPtr<Tile> create(TiledBackingStore* backingStore, const Coordinate& tileCoordinate) { return adoptRef(new Tile(backingStore, tileCoordinate)); }
+ ~Tile();
+
+ bool isDirty() const;
+ void invalidate(const IntRect&);
+ void updateBackBuffer();
+ void swapBackBufferToFront();
+ bool isReadyToPaint() const;
+ void paint(GraphicsContext*, const IntRect&);
+
+ const Tile::Coordinate& coordinate() const { return m_coordinate; }
+ const IntRect& rect() const { return m_rect; }
+
+ static void paintCheckerPattern(GraphicsContext*, const FloatRect&);
+
+private:
+ Tile(TiledBackingStore*, const Coordinate&);
+
+ TiledBackingStore* m_backingStore;
+ Coordinate m_coordinate;
+ IntRect m_rect;
+
+#if PLATFORM(QT)
+ QPixmap* m_buffer;
+ QPixmap* m_backBuffer;
+ QRegion* m_dirtyRegion;
+#endif
+};
+
+}
+#endif
+#endif
diff --git a/Source/WebCore/platform/graphics/TiledBackingStore.cpp b/Source/WebCore/platform/graphics/TiledBackingStore.cpp
new file mode 100644
index 0000000..1d6f237
--- /dev/null
+++ b/Source/WebCore/platform/graphics/TiledBackingStore.cpp
@@ -0,0 +1,403 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "TiledBackingStore.h"
+
+#if ENABLE(TILED_BACKING_STORE)
+
+#include "GraphicsContext.h"
+#include "TiledBackingStoreClient.h"
+
+namespace WebCore {
+
+static const int defaultTileWidth = 512;
+static const int defaultTileHeight = 512;
+
+TiledBackingStore::TiledBackingStore(TiledBackingStoreClient* client)
+ : m_client(client)
+ , m_tileBufferUpdateTimer(new TileTimer(this, &TiledBackingStore::tileBufferUpdateTimerFired))
+ , m_tileCreationTimer(new TileTimer(this, &TiledBackingStore::tileCreationTimerFired))
+ , m_tileSize(defaultTileWidth, defaultTileHeight)
+ , m_tileCreationDelay(0.01)
+ , m_keepAreaMultiplier(2.f, 3.5f)
+ , m_coverAreaMultiplier(1.5f, 2.5f)
+ , m_contentsScale(1.f)
+ , m_pendingScale(0)
+ , m_contentsFrozen(false)
+{
+}
+
+TiledBackingStore::~TiledBackingStore()
+{
+ delete m_tileBufferUpdateTimer;
+ delete m_tileCreationTimer;
+}
+
+void TiledBackingStore::setTileSize(const IntSize& size)
+{
+ m_tileSize = size;
+ m_tiles.clear();
+ startTileCreationTimer();
+}
+
+void TiledBackingStore::setTileCreationDelay(double delay)
+{
+ m_tileCreationDelay = delay;
+}
+
+void TiledBackingStore::setKeepAndCoverAreaMultipliers(const FloatSize& keepMultiplier, const FloatSize& coverMultiplier)
+{
+ m_keepAreaMultiplier = keepMultiplier;
+ m_coverAreaMultiplier = coverMultiplier;
+ startTileCreationTimer();
+}
+
+void TiledBackingStore::invalidate(const IntRect& contentsDirtyRect)
+{
+ IntRect dirtyRect(mapFromContents(contentsDirtyRect));
+
+ Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.topLeft());
+ Tile::Coordinate bottomRight = tileCoordinateForPoint(dirtyRect.bottomRight());
+
+ for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) {
+ for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) {
+ RefPtr<Tile> currentTile = tileAt(Tile::Coordinate(xCoordinate, yCoordinate));
+ if (!currentTile)
+ continue;
+ currentTile->invalidate(dirtyRect);
+ }
+ }
+
+ startTileBufferUpdateTimer();
+}
+
+void TiledBackingStore::updateTileBuffers()
+{
+ if (m_contentsFrozen)
+ return;
+
+ Vector<IntRect> paintedArea;
+ Vector<RefPtr<Tile> > dirtyTiles;
+ TileMap::iterator end = m_tiles.end();
+ for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) {
+ if (!it->second->isDirty())
+ continue;
+ dirtyTiles.append(it->second);
+ // FIXME: should not request system repaint for the full tile.
+ paintedArea.append(mapToContents(it->second->rect()));
+ }
+
+ if (dirtyTiles.isEmpty())
+ return;
+
+ m_client->tiledBackingStorePaintBegin();
+
+ // FIXME: In single threaded case, tile back buffers could be updated asynchronously
+ // one by one and then swapped to front in one go. This would minimize the time spent
+ // blocking on tile updates.
+ unsigned size = dirtyTiles.size();
+ for (unsigned n = 0; n < size; ++n)
+ dirtyTiles[n]->updateBackBuffer();
+
+ for (unsigned n = 0; n < size; ++n)
+ dirtyTiles[n]->swapBackBufferToFront();
+
+ m_client->tiledBackingStorePaintEnd(paintedArea);
+}
+
+void TiledBackingStore::paint(GraphicsContext* context, const IntRect& rect)
+{
+ context->save();
+
+ // Assumes the backing store is painted with the scale transform applied.
+ // Since tile content is already scaled, first revert the scaling from the painter.
+ context->scale(FloatSize(1.f / m_contentsScale, 1.f / m_contentsScale));
+
+ IntRect dirtyRect = mapFromContents(rect);
+
+ Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.topLeft());
+ Tile::Coordinate bottomRight = tileCoordinateForPoint(dirtyRect.bottomRight());
+
+ for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) {
+ for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) {
+ Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate);
+ RefPtr<Tile> currentTile = tileAt(currentCoordinate);
+ if (currentTile && currentTile->isReadyToPaint())
+ currentTile->paint(context, dirtyRect);
+ else {
+ IntRect tileRect = tileRectForCoordinate(currentCoordinate);
+ IntRect target = intersection(tileRect, dirtyRect);
+ if (target.isEmpty())
+ continue;
+ Tile::paintCheckerPattern(context, FloatRect(target));
+ }
+ }
+ }
+ context->restore();
+}
+
+void TiledBackingStore::adjustVisibleRect()
+{
+ IntRect visibleRect = mapFromContents(m_client->tiledBackingStoreVisibleRect());
+ if (m_previousVisibleRect == visibleRect)
+ return;
+ m_previousVisibleRect = visibleRect;
+
+ startTileCreationTimer();
+}
+
+void TiledBackingStore::setContentsScale(float scale)
+{
+ if (m_pendingScale == m_contentsScale) {
+ m_pendingScale = 0;
+ return;
+ }
+ m_pendingScale = scale;
+ if (m_contentsFrozen)
+ return;
+ commitScaleChange();
+}
+
+void TiledBackingStore::commitScaleChange()
+{
+ m_contentsScale = m_pendingScale;
+ m_pendingScale = 0;
+ m_tiles.clear();
+ createTiles();
+}
+
+double TiledBackingStore::tileDistance(const IntRect& viewport, const Tile::Coordinate& tileCoordinate)
+{
+ if (viewport.intersects(tileRectForCoordinate(tileCoordinate)))
+ return 0;
+
+ IntPoint viewCenter = viewport.location() + IntSize(viewport.width() / 2, viewport.height() / 2);
+ Tile::Coordinate centerCoordinate = tileCoordinateForPoint(viewCenter);
+
+ // Manhattan distance, biased so that vertical distances are shorter.
+ const double horizontalBias = 1.3;
+ return abs(centerCoordinate.y() - tileCoordinate.y()) + horizontalBias * abs(centerCoordinate.x() - tileCoordinate.x());
+}
+
+void TiledBackingStore::createTiles()
+{
+ if (m_contentsFrozen)
+ return;
+
+ IntRect visibleRect = mapFromContents(m_client->tiledBackingStoreVisibleRect());
+ m_previousVisibleRect = visibleRect;
+
+ if (visibleRect.isEmpty())
+ return;
+
+ // Remove tiles that extend outside the current contents rect.
+ dropOverhangingTiles();
+
+ IntRect keepRect = visibleRect;
+ keepRect.inflateX(visibleRect.width() * (m_keepAreaMultiplier.width() - 1.f));
+ keepRect.inflateY(visibleRect.height() * (m_keepAreaMultiplier.height() - 1.f));
+ keepRect.intersect(contentsRect());
+
+ dropTilesOutsideRect(keepRect);
+
+ IntRect coverRect = visibleRect;
+ coverRect.inflateX(visibleRect.width() * (m_coverAreaMultiplier.width() - 1.f));
+ coverRect.inflateY(visibleRect.height() * (m_coverAreaMultiplier.height() - 1.f));
+ coverRect.intersect(contentsRect());
+
+ // Search for the tile position closest to the viewport center that does not yet contain a tile.
+ // Which position is considered the closest depends on the tileDistance function.
+ double shortestDistance = std::numeric_limits<double>::infinity();
+ Vector<Tile::Coordinate> tilesToCreate;
+ unsigned requiredTileCount = 0;
+ Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.topLeft());
+ Tile::Coordinate bottomRight = tileCoordinateForPoint(coverRect.bottomRight());
+ for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) {
+ for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) {
+ Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate);
+ if (tileAt(currentCoordinate))
+ continue;
+ ++requiredTileCount;
+ // Distance is 0 for all currently visible tiles.
+ double distance = tileDistance(visibleRect, currentCoordinate);
+ if (distance > shortestDistance)
+ continue;
+ if (distance < shortestDistance) {
+ tilesToCreate.clear();
+ shortestDistance = distance;
+ }
+ tilesToCreate.append(currentCoordinate);
+ }
+ }
+
+ // Now construct the tile(s)
+ unsigned tilesToCreateCount = tilesToCreate.size();
+ for (unsigned n = 0; n < tilesToCreateCount; ++n) {
+ Tile::Coordinate coordinate = tilesToCreate[n];
+ setTile(coordinate, Tile::create(this, coordinate));
+ }
+ requiredTileCount -= tilesToCreateCount;
+
+ // Paint the content of the newly created tiles
+ if (tilesToCreateCount)
+ updateTileBuffers();
+
+ // Keep creating tiles until the whole coverRect is covered.
+ if (requiredTileCount)
+ m_tileCreationTimer->startOneShot(m_tileCreationDelay);
+}
+
+void TiledBackingStore::dropOverhangingTiles()
+{
+ IntRect contentsRect = this->contentsRect();
+
+ Vector<Tile::Coordinate> tilesToRemove;
+ TileMap::iterator end = m_tiles.end();
+ for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) {
+ Tile::Coordinate tileCoordinate = it->second->coordinate();
+ IntRect tileRect = it->second->rect();
+ IntRect expectedTileRect = tileRectForCoordinate(tileCoordinate);
+ if (expectedTileRect != tileRect || !contentsRect.contains(tileRect))
+ tilesToRemove.append(tileCoordinate);
+ }
+ unsigned removeCount = tilesToRemove.size();
+ for (unsigned n = 0; n < removeCount; ++n)
+ removeTile(tilesToRemove[n]);
+}
+
+void TiledBackingStore::dropTilesOutsideRect(const IntRect& keepRect)
+{
+ FloatRect keepRectF = keepRect;
+
+ Vector<Tile::Coordinate> toRemove;
+ TileMap::iterator end = m_tiles.end();
+ for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) {
+ Tile::Coordinate coordinate = it->second->coordinate();
+ FloatRect tileRect = it->second->rect();
+ if (!tileRect.intersects(keepRectF))
+ toRemove.append(coordinate);
+ }
+ unsigned removeCount = toRemove.size();
+ for (unsigned n = 0; n < removeCount; ++n)
+ removeTile(toRemove[n]);
+}
+
+PassRefPtr<Tile> TiledBackingStore::tileAt(const Tile::Coordinate& coordinate) const
+{
+ return m_tiles.get(coordinate);
+}
+
+void TiledBackingStore::setTile(const Tile::Coordinate& coordinate, PassRefPtr<Tile> tile)
+{
+ m_tiles.set(coordinate, tile);
+}
+
+void TiledBackingStore::removeTile(const Tile::Coordinate& coordinate)
+{
+ m_tiles.remove(coordinate);
+}
+
+IntRect TiledBackingStore::mapToContents(const IntRect& rect) const
+{
+ return enclosingIntRect(FloatRect(rect.x() / m_contentsScale,
+ rect.y() / m_contentsScale,
+ rect.width() / m_contentsScale,
+ rect.height() / m_contentsScale));
+}
+
+IntRect TiledBackingStore::mapFromContents(const IntRect& rect) const
+{
+ return enclosingIntRect(FloatRect(rect.x() * m_contentsScale,
+ rect.y() * m_contentsScale,
+ rect.width() * m_contentsScale,
+ rect.height() * m_contentsScale));
+}
+
+IntRect TiledBackingStore::contentsRect() const
+{
+ return mapFromContents(m_client->tiledBackingStoreContentsRect());
+}
+
+IntRect TiledBackingStore::tileRectForCoordinate(const Tile::Coordinate& coordinate) const
+{
+ IntRect rect(coordinate.x() * m_tileSize.width(),
+ coordinate.y() * m_tileSize.height(),
+ m_tileSize.width(),
+ m_tileSize.height());
+
+ rect.intersect(contentsRect());
+ return rect;
+}
+
+Tile::Coordinate TiledBackingStore::tileCoordinateForPoint(const IntPoint& point) const
+{
+ int x = point.x() / m_tileSize.width();
+ int y = point.y() / m_tileSize.height();
+ return Tile::Coordinate(std::max(x, 0), std::max(y, 0));
+}
+
+
+void TiledBackingStore::startTileBufferUpdateTimer()
+{
+ if (m_tileBufferUpdateTimer->isActive() || m_contentsFrozen)
+ return;
+ m_tileBufferUpdateTimer->startOneShot(0);
+}
+
+void TiledBackingStore::tileBufferUpdateTimerFired(TileTimer*)
+{
+ updateTileBuffers();
+}
+
+void TiledBackingStore::startTileCreationTimer()
+{
+ if (m_tileCreationTimer->isActive() || m_contentsFrozen)
+ return;
+ m_tileCreationTimer->startOneShot(0);
+}
+
+void TiledBackingStore::tileCreationTimerFired(TileTimer*)
+{
+ createTiles();
+}
+
+void TiledBackingStore::setContentsFrozen(bool freeze)
+{
+ if (m_contentsFrozen == freeze)
+ return;
+
+ m_contentsFrozen = freeze;
+
+ // Restart the timers. There might be pending invalidations that
+ // were not painted or created because tiles are not created or
+ // painted when in frozen state.
+ if (m_contentsFrozen)
+ return;
+ if (m_pendingScale)
+ commitScaleChange();
+ else {
+ startTileCreationTimer();
+ startTileBufferUpdateTimer();
+ }
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/TiledBackingStore.h b/Source/WebCore/platform/graphics/TiledBackingStore.h
new file mode 100644
index 0000000..58477db
--- /dev/null
+++ b/Source/WebCore/platform/graphics/TiledBackingStore.h
@@ -0,0 +1,127 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TiledBackingStore_h
+#define TiledBackingStore_h
+
+#if ENABLE(TILED_BACKING_STORE)
+
+#include "FloatSize.h"
+#include "IntPoint.h"
+#include "IntRect.h"
+#include "Tile.h"
+#include "Timer.h"
+#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class GraphicsContext;
+class TiledBackingStoreClient;
+
+class TiledBackingStore : public Noncopyable {
+public:
+ TiledBackingStore(TiledBackingStoreClient*);
+ ~TiledBackingStore();
+
+ void adjustVisibleRect();
+
+ float contentsScale() { return m_contentsScale; }
+ void setContentsScale(float);
+
+ bool contentsFrozen() const { return m_contentsFrozen; }
+ void setContentsFrozen(bool);
+
+ void invalidate(const IntRect& dirtyRect);
+ void paint(GraphicsContext*, const IntRect&);
+
+ IntSize tileSize() { return m_tileSize; }
+ void setTileSize(const IntSize&);
+
+ double tileCreationDelay() const { return m_tileCreationDelay; }
+ void setTileCreationDelay(double delay);
+
+ // Tiled are dropped outside the keep area, and created for cover area. The values a relative to the viewport size.
+ void getKeepAndCoverAreaMultipliers(FloatSize& keepMultiplier, FloatSize& coverMultiplier)
+ {
+ keepMultiplier = m_keepAreaMultiplier;
+ coverMultiplier = m_coverAreaMultiplier;
+ }
+ void setKeepAndCoverAreaMultipliers(const FloatSize& keepMultiplier, const FloatSize& coverMultiplier);
+
+private:
+ void startTileBufferUpdateTimer();
+ void startTileCreationTimer();
+
+ typedef Timer<TiledBackingStore> TileTimer;
+
+ void tileBufferUpdateTimerFired(TileTimer*);
+ void tileCreationTimerFired(TileTimer*);
+
+ void updateTileBuffers();
+ void createTiles();
+
+ void commitScaleChange();
+
+ void dropOverhangingTiles();
+ void dropTilesOutsideRect(const IntRect&);
+
+ PassRefPtr<Tile> tileAt(const Tile::Coordinate&) const;
+ void setTile(const Tile::Coordinate& coordinate, PassRefPtr<Tile> tile);
+ void removeTile(const Tile::Coordinate& coordinate);
+
+ IntRect mapToContents(const IntRect&) const;
+ IntRect mapFromContents(const IntRect&) const;
+
+ IntRect contentsRect() const;
+
+ IntRect tileRectForCoordinate(const Tile::Coordinate&) const;
+ Tile::Coordinate tileCoordinateForPoint(const IntPoint&) const;
+ double tileDistance(const IntRect& viewport, const Tile::Coordinate&);
+
+ void paintCheckerPattern(GraphicsContext*, const IntRect&, const Tile::Coordinate&);
+
+private:
+ TiledBackingStoreClient* m_client;
+
+ typedef HashMap<Tile::Coordinate, RefPtr<Tile> > TileMap;
+ TileMap m_tiles;
+
+ TileTimer* m_tileBufferUpdateTimer;
+ TileTimer* m_tileCreationTimer;
+
+ IntSize m_tileSize;
+ double m_tileCreationDelay;
+ FloatSize m_keepAreaMultiplier;
+ FloatSize m_coverAreaMultiplier;
+
+ IntRect m_previousVisibleRect;
+ float m_contentsScale;
+ float m_pendingScale;
+
+ bool m_contentsFrozen;
+
+ friend class Tile;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/platform/graphics/TiledBackingStoreClient.h b/Source/WebCore/platform/graphics/TiledBackingStoreClient.h
new file mode 100644
index 0000000..6087ec3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/TiledBackingStoreClient.h
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TiledBackingStoreClient_h
+#define TiledBackingStoreClient_h
+
+namespace WebCore {
+
+#if ENABLE(TILED_BACKING_STORE)
+class TiledBackingStoreClient {
+public:
+ virtual void tiledBackingStorePaintBegin() = 0;
+ virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&) = 0;
+ virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea) = 0;
+ virtual IntRect tiledBackingStoreContentsRect() = 0;
+ virtual IntRect tiledBackingStoreVisibleRect() = 0;
+ virtual Color tiledBackingStoreBackgroundColor() const = 0;
+};
+
+#else
+class TiledBackingStoreClient {};
+#endif
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/TypesettingFeatures.h b/Source/WebCore/platform/graphics/TypesettingFeatures.h
new file mode 100644
index 0000000..aa46beb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/TypesettingFeatures.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 TypesettingFeatures_h
+#define TypesettingFeatures_h
+
+namespace WebCore {
+ enum TypesettingFeature {
+ Kerning = 1 << 0,
+ Ligatures = 1 << 1,
+ };
+
+ typedef unsigned TypesettingFeatures;
+} // namespace WebCore
+
+#endif // TypesettingFeatures_h
diff --git a/Source/WebCore/platform/graphics/UnitBezier.h b/Source/WebCore/platform/graphics/UnitBezier.h
new file mode 100644
index 0000000..973d75b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/UnitBezier.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 UnitBezier_h
+#define UnitBezier_h
+
+#include <math.h>
+
+namespace WebCore {
+
+ struct UnitBezier {
+ UnitBezier(double p1x, double p1y, double p2x, double p2y)
+ {
+ // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
+ cx = 3.0 * p1x;
+ bx = 3.0 * (p2x - p1x) - cx;
+ ax = 1.0 - cx -bx;
+
+ cy = 3.0 * p1y;
+ by = 3.0 * (p2y - p1y) - cy;
+ ay = 1.0 - cy - by;
+ }
+
+ double sampleCurveX(double t)
+ {
+ // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
+ return ((ax * t + bx) * t + cx) * t;
+ }
+
+ double sampleCurveY(double t)
+ {
+ return ((ay * t + by) * t + cy) * t;
+ }
+
+ double sampleCurveDerivativeX(double t)
+ {
+ return (3.0 * ax * t + 2.0 * bx) * t + cx;
+ }
+
+ // Given an x value, find a parametric value it came from.
+ double solveCurveX(double x, double epsilon)
+ {
+ double t0;
+ double t1;
+ double t2;
+ double x2;
+ double d2;
+ int i;
+
+ // First try a few iterations of Newton's method -- normally very fast.
+ for (t2 = x, i = 0; i < 8; i++) {
+ x2 = sampleCurveX(t2) - x;
+ if (fabs (x2) < epsilon)
+ return t2;
+ d2 = sampleCurveDerivativeX(t2);
+ if (fabs(d2) < 1e-6)
+ break;
+ t2 = t2 - x2 / d2;
+ }
+
+ // Fall back to the bisection method for reliability.
+ t0 = 0.0;
+ t1 = 1.0;
+ t2 = x;
+
+ if (t2 < t0)
+ return t0;
+ if (t2 > t1)
+ return t1;
+
+ while (t0 < t1) {
+ x2 = sampleCurveX(t2);
+ if (fabs(x2 - x) < epsilon)
+ return t2;
+ if (x > x2)
+ t0 = t2;
+ else
+ t1 = t2;
+ t2 = (t1 - t0) * .5 + t0;
+ }
+
+ // Failure.
+ return t2;
+ }
+
+ double solve(double x, double epsilon)
+ {
+ return sampleCurveY(solveCurveX(x, epsilon));
+ }
+
+ private:
+ double ax;
+ double bx;
+ double cx;
+
+ double ay;
+ double by;
+ double cy;
+ };
+}
+#endif
diff --git a/Source/WebCore/platform/graphics/WOFFFileFormat.cpp b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp
new file mode 100644
index 0000000..b1400ba
--- /dev/null
+++ b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "WOFFFileFormat.h"
+#include <zlib.h>
+
+#if !ENABLE(OPENTYPE_SANITIZER)
+
+#include "SharedBuffer.h"
+
+#if OS(UNIX)
+#include <netinet/in.h>
+#endif
+
+#if PLATFORM(BREWMP)
+#include <AEEstd.h>
+#define htonl(x) std_htonl(x)
+#define htons(x) std_htons(x)
+#define ntohl(x) std_ntohl(x)
+#define ntohs(x) std_ntohs(x)
+#endif
+
+#if PLATFORM(WIN)
+#if CPU(BIG_ENDIAN)
+#define ntohs(x) ((uint16_t)(x))
+#define htons(x) ((uint16_t)(x))
+#define ntohl(x) ((uint32_t)(x))
+#define htonl(x) ((uint32_t)(x))
+#elif CPU(MIDDLE_ENDIAN)
+#define ntohs(x) ((unit16_t)(x))
+#define htons(x) ((uint16_t)(x))
+#define ntohl(x) ((uint32_t)((((uint32_t)(x) & 0xffff0000) >> 16) | (((uint32_t)(x) & 0xffff) << 16))
+#define htonl(x) ntohl(x)
+#else
+#define ntohs(x) ((uint16_t)((((uint16_t)(x) & 0xff00) >> 8) | (((uint16_t)(x) & 0x00ff) << 8)))
+#define htons(x) ntohs(x)
+#define ntohl(x) ((uint32_t)((((uint32_t)(x) & 0xff000000) >> 24) | (((uint32_t)(x) & 0x00ff0000) >> 8) | \
+ (((uint32_t)(x) & 0x0000ff00) << 8) | (((uint32_t)(x) & 0x000000ff) << 24)))
+#define htonl(x) ntohl(x)
+#endif
+#endif // PLATFORM(WIN)
+
+namespace WebCore {
+
+static bool readUInt32(SharedBuffer* buffer, size_t& offset, uint32_t& value)
+{
+ ASSERT_ARG(offset, offset <= buffer->size());
+ if (buffer->size() - offset < sizeof(value))
+ return false;
+
+ value = ntohl(*reinterpret_cast<const uint32_t*>(buffer->data() + offset));
+ offset += sizeof(value);
+
+ return true;
+}
+
+static bool readUInt16(SharedBuffer* buffer, size_t& offset, uint16_t& value)
+{
+ ASSERT_ARG(offset, offset <= buffer->size());
+ if (buffer->size() - offset < sizeof(value))
+ return false;
+
+ value = ntohs(*reinterpret_cast<const uint16_t*>(buffer->data() + offset));
+ offset += sizeof(value);
+
+ return true;
+}
+
+static bool writeUInt32(Vector<char>& vector, uint32_t value)
+{
+ uint32_t bigEndianValue = htonl(value);
+ return vector.tryAppend(reinterpret_cast<char*>(&bigEndianValue), sizeof(bigEndianValue));
+}
+
+static bool writeUInt16(Vector<char>& vector, uint16_t value)
+{
+ uint16_t bigEndianValue = htons(value);
+ return vector.tryAppend(reinterpret_cast<char*>(&bigEndianValue), sizeof(bigEndianValue));
+}
+
+static const uint32_t woffSignature = 0x774f4646; /* 'wOFF' */
+
+bool isWOFF(SharedBuffer* buffer)
+{
+ size_t offset = 0;
+ uint32_t signature;
+
+ return readUInt32(buffer, offset, signature) && signature == woffSignature;
+}
+
+bool convertWOFFToSfnt(SharedBuffer* woff, Vector<char>& sfnt)
+{
+ ASSERT_ARG(sfnt, sfnt.isEmpty());
+
+ size_t offset = 0;
+
+ // Read the WOFF header.
+ uint32_t signature;
+ if (!readUInt32(woff, offset, signature) || signature != woffSignature) {
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ uint32_t flavor;
+ if (!readUInt32(woff, offset, flavor))
+ return false;
+
+ uint32_t length;
+ if (!readUInt32(woff, offset, length) || length != woff->size())
+ return false;
+
+ uint16_t numTables;
+ if (!readUInt16(woff, offset, numTables))
+ return false;
+
+ if (!numTables || numTables > 0x0fff)
+ return false;
+
+ uint16_t reserved;
+ if (!readUInt16(woff, offset, reserved) || reserved)
+ return false;
+
+ uint32_t totalSfntSize;
+ if (!readUInt32(woff, offset, totalSfntSize))
+ return false;
+
+ if (woff->size() - offset < sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t))
+ return false;
+
+ offset += sizeof(uint16_t); // majorVersion
+ offset += sizeof(uint16_t); // minorVersion
+ offset += sizeof(uint32_t); // metaOffset
+ offset += sizeof(uint32_t); // metaLength
+ offset += sizeof(uint32_t); // metaOrigLength
+ offset += sizeof(uint32_t); // privOffset
+ offset += sizeof(uint32_t); // privLength
+
+ // Check if the WOFF can supply as many tables as it claims it has.
+ if (woff->size() - offset < numTables * 5 * sizeof(uint32_t))
+ return false;
+
+ // Write the sfnt offset subtable.
+ uint16_t entrySelector = 0;
+ uint16_t searchRange = 1;
+ while (searchRange < numTables >> 1) {
+ entrySelector++;
+ searchRange <<= 1;
+ }
+ searchRange <<= 4;
+ uint16_t rangeShift = (numTables << 4) - searchRange;
+
+ if (!writeUInt32(sfnt, flavor)
+ || !writeUInt16(sfnt, numTables)
+ || !writeUInt16(sfnt, searchRange)
+ || !writeUInt16(sfnt, entrySelector)
+ || !writeUInt16(sfnt, rangeShift))
+ return false;
+
+ if (sfnt.size() > totalSfntSize)
+ return false;
+
+ if (totalSfntSize - sfnt.size() < numTables * 4 * sizeof(uint32_t))
+ return false;
+
+ size_t sfntTableDirectoryCursor = sfnt.size();
+ sfnt.grow(sfnt.size() + numTables * 4 * sizeof(uint32_t));
+
+ // Process tables.
+ for (uint16_t i = 0; i < numTables; ++i) {
+ // Read a WOFF table directory entry.
+ uint32_t tableTag;
+ if (!readUInt32(woff, offset, tableTag))
+ return false;
+
+ uint32_t tableOffset;
+ if (!readUInt32(woff, offset, tableOffset))
+ return false;
+
+ uint32_t tableCompLength;
+ if (!readUInt32(woff, offset, tableCompLength))
+ return false;
+
+ if (tableOffset > woff->size() || tableCompLength > woff->size() - tableOffset)
+ return false;
+
+ uint32_t tableOrigLength;
+ if (!readUInt32(woff, offset, tableOrigLength) || tableCompLength > tableOrigLength)
+ return false;
+
+ if (tableOrigLength > totalSfntSize || sfnt.size() > totalSfntSize - tableOrigLength)
+ return false;
+
+ uint32_t tableOrigChecksum;
+ if (!readUInt32(woff, offset, tableOrigChecksum))
+ return false;
+
+ // Write an sfnt table directory entry.
+ uint32_t* sfntTableDirectoryPtr = reinterpret_cast<uint32_t*>(sfnt.data() + sfntTableDirectoryCursor);
+ *sfntTableDirectoryPtr++ = htonl(tableTag);
+ *sfntTableDirectoryPtr++ = htonl(tableOrigChecksum);
+ *sfntTableDirectoryPtr++ = htonl(sfnt.size());
+ *sfntTableDirectoryPtr++ = htonl(tableOrigLength);
+ sfntTableDirectoryCursor += 4 * sizeof(uint32_t);
+
+ if (tableCompLength == tableOrigLength) {
+ // The table is not compressed.
+ if (!sfnt.tryAppend(woff->data() + tableOffset, tableCompLength))
+ return false;
+ } else {
+ uLongf destLen = tableOrigLength;
+ if (!sfnt.tryReserveCapacity(sfnt.size() + tableOrigLength))
+ return false;
+ Bytef* dest = reinterpret_cast<Bytef*>(sfnt.end());
+ sfnt.grow(sfnt.size() + tableOrigLength);
+ if (uncompress(dest, &destLen, reinterpret_cast<const Bytef*>(woff->data() + tableOffset), tableCompLength) != Z_OK)
+ return false;
+ if (destLen != tableOrigLength)
+ return false;
+ }
+
+ // Pad to a multiple of 4 bytes.
+ while (sfnt.size() % 4)
+ sfnt.append(0);
+ }
+
+ return sfnt.size() == totalSfntSize;
+}
+
+#endif // !ENABLE(OPENTYPE_SANITIZER)
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/WOFFFileFormat.h b/Source/WebCore/platform/graphics/WOFFFileFormat.h
new file mode 100644
index 0000000..9351d0e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/WOFFFileFormat.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 WOFFFileFormat_h
+#define WOFFFileFormat_h
+
+#if !ENABLE(OPENTYPE_SANITIZER)
+
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class SharedBuffer;
+
+// Returns whether the buffer is a WOFF file.
+bool isWOFF(SharedBuffer* buffer);
+
+// Returns false if the WOFF file woff is invalid or could not be converted to sfnt (for example,
+// if conversion ran out of memory). Otherwise returns true and writes the sfnt payload into sfnt.
+bool convertWOFFToSfnt(SharedBuffer* woff, Vector<char>& sfnt);
+
+} // namespace WebCore
+
+#endif // !ENABLE(OPENTYPE_SANITIZER)
+
+#endif // WOFFFileFormat_h
diff --git a/Source/WebCore/platform/graphics/WidthIterator.cpp b/Source/WebCore/platform/graphics/WidthIterator.cpp
new file mode 100644
index 0000000..2a951e8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/WidthIterator.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2003, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "WidthIterator.h"
+
+#include "Font.h"
+#include "GlyphBuffer.h"
+#include "SimpleFontData.h"
+#include <wtf/MathExtras.h>
+
+#if USE(ICU_UNICODE)
+#include <unicode/unorm.h>
+#endif
+
+using namespace WTF;
+using namespace Unicode;
+using namespace std;
+
+namespace WebCore {
+
+// According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values
+static const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8;
+
+WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, bool accountForGlyphBounds, bool forTextEmphasis)
+ : m_font(font)
+ , m_run(run)
+ , m_end(run.length())
+ , m_currentCharacter(0)
+ , m_runWidthSoFar(0)
+ , m_finalRoundingWidth(0)
+ , m_fallbackFonts(fallbackFonts)
+ , m_accountForGlyphBounds(accountForGlyphBounds)
+ , m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
+ , m_minGlyphBoundingBoxY(numeric_limits<float>::max())
+ , m_firstGlyphOverflow(0)
+ , m_lastGlyphOverflow(0)
+ , m_forTextEmphasis(forTextEmphasis)
+{
+ // If the padding is non-zero, count the number of spaces in the run
+ // and divide that by the padding for per space addition.
+ m_padding = m_run.padding();
+ if (!m_padding)
+ m_padPerSpace = 0;
+ else {
+ int numSpaces = 0;
+ for (int i = 0; i < run.length(); i++) {
+ if (Font::treatAsSpace(m_run[i]))
+ numSpaces++;
+ }
+
+ if (!numSpaces)
+ m_padPerSpace = 0;
+ else
+ m_padPerSpace = m_padding / numSpaces;
+ }
+}
+
+void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
+{
+ if (offset > m_end)
+ offset = m_end;
+
+ int currentCharacter = m_currentCharacter;
+ const UChar* cp = m_run.data(currentCharacter);
+
+ bool rtl = m_run.rtl();
+ bool hasExtraSpacing = (m_font->letterSpacing() || m_font->wordSpacing() || m_padding) && !m_run.spacingDisabled();
+
+ float widthSinceLastRounding = m_runWidthSoFar;
+ m_runWidthSoFar = floorf(m_runWidthSoFar);
+ widthSinceLastRounding -= m_runWidthSoFar;
+
+ float lastRoundingWidth = m_finalRoundingWidth;
+ FloatRect bounds;
+
+ const SimpleFontData* primaryFont = m_font->primaryFont();
+ const SimpleFontData* lastFontData = primaryFont;
+
+ while (currentCharacter < offset) {
+ UChar32 c = *cp;
+ unsigned clusterLength = 1;
+ if (c >= 0x3041) {
+ if (c <= 0x30FE) {
+ // Deal with Hiragana and Katakana voiced and semi-voiced syllables.
+ // Normalize into composed form, and then look for glyph with base + combined mark.
+ // Check above for character range to minimize performance impact.
+ UChar32 normalized = normalizeVoicingMarks(currentCharacter);
+ if (normalized) {
+ c = normalized;
+ clusterLength = 2;
+ }
+ } else if (U16_IS_SURROGATE(c)) {
+ if (!U16_IS_SURROGATE_LEAD(c))
+ break;
+
+ // Do we have a surrogate pair? If so, determine the full Unicode (32 bit)
+ // code point before glyph lookup.
+ // Make sure we have another character and it's a low surrogate.
+ if (currentCharacter + 1 >= m_run.length())
+ break;
+ UChar low = cp[1];
+ if (!U16_IS_TRAIL(low))
+ break;
+ c = U16_GET_SUPPLEMENTARY(c, low);
+ clusterLength = 2;
+ }
+ }
+
+ const GlyphData& glyphData = m_font->glyphDataForCharacter(c, rtl);
+ Glyph glyph = glyphData.glyph;
+ const SimpleFontData* fontData = glyphData.fontData;
+
+ ASSERT(fontData);
+
+ // Now that we have a glyph and font data, get its width.
+ float width;
+ if (c == '\t' && m_run.allowTabs()) {
+ float tabWidth = m_font->tabWidth(*fontData);
+ width = tabWidth - fmodf(m_run.xPos() + m_runWidthSoFar + widthSinceLastRounding, tabWidth);
+ } else {
+ width = fontData->widthForGlyph(glyph);
+
+#if ENABLE(SVG)
+ // SVG uses horizontalGlyphStretch(), when textLength is used to stretch/squeeze text.
+ width *= m_run.horizontalGlyphStretch();
+#endif
+
+ // We special case spaces in two ways when applying word rounding.
+ // First, we round spaces to an adjusted width in all fonts.
+ // Second, in fixed-pitch fonts we ensure that all characters that
+ // match the width of the space character have the same width as the space character.
+ if (width == fontData->spaceWidth() && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) && m_run.applyWordRounding())
+ width = fontData->adjustedSpaceWidth();
+ }
+
+ if (fontData != lastFontData && width) {
+ lastFontData = fontData;
+ if (m_fallbackFonts && fontData != primaryFont) {
+ // FIXME: This does a little extra work that could be avoided if
+ // glyphDataForCharacter() returned whether it chose to use a small caps font.
+ if (!m_font->isSmallCaps() || c == toUpper(c))
+ m_fallbackFonts->add(fontData);
+ else {
+ const GlyphData& uppercaseGlyphData = m_font->glyphDataForCharacter(toUpper(c), rtl);
+ if (uppercaseGlyphData.fontData != primaryFont)
+ m_fallbackFonts->add(uppercaseGlyphData.fontData);
+ }
+ }
+ }
+
+ if (hasExtraSpacing) {
+ // Account for letter-spacing.
+ if (width && m_font->letterSpacing())
+ width += m_font->letterSpacing();
+
+ if (Font::treatAsSpace(c)) {
+ // Account for padding. WebCore uses space padding to justify text.
+ // We distribute the specified padding over the available spaces in the run.
+ if (m_padding) {
+ // Use left over padding if not evenly divisible by number of spaces.
+ if (m_padding < m_padPerSpace) {
+ width += m_padding;
+ m_padding = 0;
+ } else {
+ float previousPadding = m_padding;
+ m_padding -= m_padPerSpace;
+ width += roundf(previousPadding) - roundf(m_padding);
+ }
+ }
+
+ // Account for word spacing.
+ // We apply additional space between "words" by adding width to the space character.
+ if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing())
+ width += m_font->wordSpacing();
+ }
+ }
+
+ if (m_accountForGlyphBounds) {
+ bounds = fontData->boundsForGlyph(glyph);
+ if (!currentCharacter)
+ m_firstGlyphOverflow = max<float>(0, -bounds.x());
+ }
+
+ if (m_forTextEmphasis && !Font::canReceiveTextEmphasis(c))
+ glyph = 0;
+
+ // Advance past the character we just dealt with.
+ cp += clusterLength;
+ currentCharacter += clusterLength;
+
+ // Account for float/integer impedance mismatch between CG and KHTML. "Words" (characters
+ // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
+ // We adjust the width of the last character of a "word" to ensure an integer width.
+ // If we move KHTML to floats we can remove this (and related) hacks.
+
+ float oldWidth = width;
+
+ // Force characters that are used to determine word boundaries for the rounding hack
+ // to be integer width, so following words will start on an integer boundary.
+ if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) {
+ width = ceilf(width);
+
+ // Since widthSinceLastRounding can lose precision if we include measurements for
+ // preceding whitespace, we bypass it here.
+ m_runWidthSoFar += width;
+
+ // Since this is a rounding hack character, we should have reset this sum on the previous
+ // iteration.
+ ASSERT(!widthSinceLastRounding);
+ } else {
+ // Check to see if the next character is a "rounding hack character", if so, adjust
+ // width so that the total run width will be on an integer boundary.
+ if ((m_run.applyWordRounding() && currentCharacter < m_run.length() && Font::isRoundingHackCharacter(*cp))
+ || (m_run.applyRunRounding() && currentCharacter >= m_end)) {
+ float totalWidth = widthSinceLastRounding + width;
+ widthSinceLastRounding = ceilf(totalWidth);
+ width += widthSinceLastRounding - totalWidth;
+ m_runWidthSoFar += widthSinceLastRounding;
+ widthSinceLastRounding = 0;
+ } else
+ widthSinceLastRounding += width;
+ }
+
+ if (glyphBuffer)
+ glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width));
+
+ lastRoundingWidth = width - oldWidth;
+
+ if (m_accountForGlyphBounds) {
+ m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, bounds.bottom());
+ m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, bounds.y());
+ m_lastGlyphOverflow = max<float>(0, bounds.right() - width);
+ }
+ }
+
+ m_currentCharacter = currentCharacter;
+ m_runWidthSoFar += widthSinceLastRounding;
+ m_finalRoundingWidth = lastRoundingWidth;
+}
+
+bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer)
+{
+ glyphBuffer->clear();
+ advance(m_currentCharacter + 1, glyphBuffer);
+ float w = 0;
+ for (int i = 0; i < glyphBuffer->size(); ++i)
+ w += glyphBuffer->advanceAt(i);
+ width = w;
+ return !glyphBuffer->isEmpty();
+}
+
+UChar32 WidthIterator::normalizeVoicingMarks(int currentCharacter)
+{
+ if (currentCharacter + 1 < m_end) {
+ if (combiningClass(m_run[currentCharacter + 1]) == hiraganaKatakanaVoicingMarksCombiningClass) {
+#if USE(ICU_UNICODE)
+ // Normalize into composed form using 3.2 rules.
+ UChar normalizedCharacters[2] = { 0, 0 };
+ UErrorCode uStatus = U_ZERO_ERROR;
+ int32_t resultLength = unorm_normalize(m_run.data(currentCharacter), 2,
+ UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus);
+ if (resultLength == 1 && uStatus == 0)
+ return normalizedCharacters[0];
+#elif USE(QT4_UNICODE)
+ QString tmp(reinterpret_cast<const QChar*>(m_run.data(currentCharacter)), 2);
+ QString res = tmp.normalized(QString::NormalizationForm_C, QChar::Unicode_3_2);
+ if (res.length() == 1)
+ return res.at(0).unicode();
+#endif
+ }
+ }
+ return 0;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/WidthIterator.h b/Source/WebCore/platform/graphics/WidthIterator.h
new file mode 100644
index 0000000..8b3c067
--- /dev/null
+++ b/Source/WebCore/platform/graphics/WidthIterator.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WidthIterator_h
+#define WidthIterator_h
+
+#include <wtf/HashSet.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+class Font;
+class GlyphBuffer;
+class SimpleFontData;
+class TextRun;
+
+struct WidthIterator {
+ WidthIterator(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, bool accountForGlyphBounds = false, bool forTextEmphasis = false);
+
+ void advance(int to, GlyphBuffer* = 0);
+ bool advanceOneCharacter(float& width, GlyphBuffer* = 0);
+
+ float maxGlyphBoundingBoxY() const { ASSERT(m_accountForGlyphBounds); return m_maxGlyphBoundingBoxY; }
+ float minGlyphBoundingBoxY() const { ASSERT(m_accountForGlyphBounds); return m_minGlyphBoundingBoxY; }
+ float firstGlyphOverflow() const { ASSERT(m_accountForGlyphBounds); return m_firstGlyphOverflow; }
+ float lastGlyphOverflow() const { ASSERT(m_accountForGlyphBounds); return m_lastGlyphOverflow; }
+
+ const Font* m_font;
+
+ const TextRun& m_run;
+ int m_end;
+
+ unsigned m_currentCharacter;
+ float m_runWidthSoFar;
+ float m_padding;
+ float m_padPerSpace;
+ float m_finalRoundingWidth;
+
+private:
+ UChar32 normalizeVoicingMarks(int currentCharacter);
+
+ HashSet<const SimpleFontData*>* m_fallbackFonts;
+ bool m_accountForGlyphBounds;
+ float m_maxGlyphBoundingBoxY;
+ float m_minGlyphBoundingBoxY;
+ float m_firstGlyphOverflow;
+ float m_lastGlyphOverflow;
+ bool m_forTextEmphasis;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/brew/IconBrew.cpp b/Source/WebCore/platform/graphics/brew/IconBrew.cpp
new file mode 100644
index 0000000..3345111
--- /dev/null
+++ b/Source/WebCore/platform/graphics/brew/IconBrew.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ * Copyright (C) 2009-2010 Company 100, Inc.
+ *
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+Icon::~Icon()
+{
+ notImplemented();
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ notImplemented();
+ return 0;
+}
+
+void Icon::paint(GraphicsContext*, const IntRect&)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/brew/ImageBrew.cpp b/Source/WebCore/platform/graphics/brew/ImageBrew.cpp
new file mode 100644
index 0000000..b574b0a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/brew/ImageBrew.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010, Company 100, 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "BitmapImage.h"
+#include "FileSystem.h"
+#include "SharedBuffer.h"
+
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+
+namespace WebCore {
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ String resourcePath = makeString(homeDirectoryPath(), "res/", name, ".png");
+
+ RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(resourcePath.utf8().data());
+ if (!buffer)
+ return Image::nullImage();
+
+ RefPtr<Image> image = BitmapImage::create();
+ image->setData(buffer, true);
+ return image.release();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/brew/IntPointBrew.cpp b/Source/WebCore/platform/graphics/brew/IntPointBrew.cpp
new file mode 100644
index 0000000..8792b1d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/brew/IntPointBrew.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Company 100, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include <AEEPoint.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const AEEPoint& point)
+ : m_x(point.x)
+ , m_y(point.y)
+{
+}
+
+IntPoint::operator AEEPoint() const
+{
+ AEEPoint point;
+ point.x = static_cast<int16>(m_x);
+ point.y = static_cast<int16>(m_y);
+ return point;
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/brew/IntSizeBrew.cpp b/Source/WebCore/platform/graphics/brew/IntSizeBrew.cpp
new file mode 100644
index 0000000..01c3365
--- /dev/null
+++ b/Source/WebCore/platform/graphics/brew/IntSizeBrew.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Company 100, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntSize.h"
+
+#include <AEE.h>
+
+namespace WebCore {
+
+IntSize::IntSize(const AEESize& size)
+ : m_width(size.cx)
+ , m_height(size.cy)
+{
+}
+
+IntSize::operator AEESize() const
+{
+ AEESize size;
+ size.cx = width();
+ size.cy = height();
+ return size;
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
new file mode 100644
index 0000000..37385c0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
@@ -0,0 +1,2308 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayerCA.h"
+
+#include "Animation.h"
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "PlatformCALayer.h"
+#include "PlatformString.h"
+#include "RotateTransformOperation.h"
+#include "ScaleTransformOperation.h"
+#include "SystemTime.h"
+#include "TranslateTransformOperation.h"
+#include <limits.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/text/StringConcatenate.h>
+
+using namespace std;
+
+#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
+
+namespace WebCore {
+
+// The threshold width or height above which a tiled layer will be used. This should be
+// large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL
+// texture size limit on all supported hardware.
+static const int cMaxPixelDimension = 2000;
+
+// If we send a duration of 0 to CA, then it will use the default duration
+// of 250ms. So send a very small value instead.
+static const float cAnimationAlmostZeroDuration = 1e-3f;
+
+// CACurrentMediaTime() is a time since boot. These methods convert between that and
+// WebCore time, which is system time (UTC).
+static CFTimeInterval currentTimeToMediaTime(double t)
+{
+ return CACurrentMediaTime() + t - WTF::currentTime();
+}
+
+static bool isTransformTypeTransformationMatrix(TransformOperation::OperationType transformType)
+{
+ switch (transformType) {
+ case TransformOperation::SKEW_X:
+ case TransformOperation::SKEW_Y:
+ case TransformOperation::SKEW:
+ case TransformOperation::MATRIX:
+ case TransformOperation::ROTATE_3D:
+ case TransformOperation::MATRIX_3D:
+ case TransformOperation::PERSPECTIVE:
+ case TransformOperation::IDENTITY:
+ case TransformOperation::NONE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool isTransformTypeFloatPoint3D(TransformOperation::OperationType transformType)
+{
+ switch (transformType) {
+ case TransformOperation::SCALE:
+ case TransformOperation::SCALE_3D:
+ case TransformOperation::TRANSLATE:
+ case TransformOperation::TRANSLATE_3D:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool isTransformTypeNumber(TransformOperation::OperationType transformType)
+{
+ return !isTransformTypeTransformationMatrix(transformType) && !isTransformTypeFloatPoint3D(transformType);
+}
+
+static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize& size, float& value)
+{
+ switch (transformType) {
+ case TransformOperation::ROTATE:
+ case TransformOperation::ROTATE_X:
+ case TransformOperation::ROTATE_Y:
+ value = transformOp ? narrowPrecisionToFloat(deg2rad(static_cast<const RotateTransformOperation*>(transformOp)->angle())) : 0;
+ break;
+ case TransformOperation::SCALE_X:
+ value = transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->x()) : 1;
+ break;
+ case TransformOperation::SCALE_Y:
+ value = transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->y()) : 1;
+ break;
+ case TransformOperation::SCALE_Z:
+ value = transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->z()) : 1;
+ break;
+ case TransformOperation::TRANSLATE_X:
+ value = transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->x(size)) : 0;
+ break;
+ case TransformOperation::TRANSLATE_Y:
+ value = transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->y(size)) : 0;
+ break;
+ case TransformOperation::TRANSLATE_Z:
+ value = transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->z(size)) : 0;
+ break;
+ default:
+ break;
+ }
+}
+
+static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize& size, FloatPoint3D& value)
+{
+ switch (transformType) {
+ case TransformOperation::SCALE:
+ case TransformOperation::SCALE_3D:
+ value.setX(transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->x()) : 1);
+ value.setY(transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->y()) : 1);
+ value.setZ(transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->z()) : 1);
+ break;
+ case TransformOperation::TRANSLATE:
+ case TransformOperation::TRANSLATE_3D:
+ value.setX(transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->x(size)) : 0);
+ value.setY(transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->y(size)) : 0);
+ value.setZ(transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->z(size)) : 0);
+ break;
+ default:
+ break;
+ }
+}
+
+static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize& size, TransformationMatrix& value)
+{
+ switch (transformType) {
+ case TransformOperation::SKEW_X:
+ case TransformOperation::SKEW_Y:
+ case TransformOperation::SKEW:
+ case TransformOperation::MATRIX:
+ case TransformOperation::ROTATE_3D:
+ case TransformOperation::MATRIX_3D:
+ case TransformOperation::PERSPECTIVE:
+ case TransformOperation::IDENTITY:
+ case TransformOperation::NONE:
+ if (transformOp)
+ transformOp->apply(value, size);
+ else
+ value.makeIdentity();
+ break;
+ default:
+ break;
+ }
+}
+
+#if HAVE_MODERN_QUARTZCORE
+static PlatformCAAnimation::ValueFunctionType getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType)
+{
+ // Use literal strings to avoid link-time dependency on those symbols.
+ switch (transformType) {
+ case TransformOperation::ROTATE_X:
+ return PlatformCAAnimation::RotateX;
+ case TransformOperation::ROTATE_Y:
+ return PlatformCAAnimation::RotateY;
+ case TransformOperation::ROTATE:
+ return PlatformCAAnimation::RotateZ;
+ case TransformOperation::SCALE_X:
+ return PlatformCAAnimation::ScaleX;
+ case TransformOperation::SCALE_Y:
+ return PlatformCAAnimation::ScaleY;
+ case TransformOperation::SCALE_Z:
+ return PlatformCAAnimation::ScaleZ;
+ case TransformOperation::TRANSLATE_X:
+ return PlatformCAAnimation::TranslateX;
+ case TransformOperation::TRANSLATE_Y:
+ return PlatformCAAnimation::TranslateY;
+ case TransformOperation::TRANSLATE_Z:
+ return PlatformCAAnimation::TranslateZ;
+ case TransformOperation::SCALE:
+ case TransformOperation::SCALE_3D:
+ return PlatformCAAnimation::Scale;
+ case TransformOperation::TRANSLATE:
+ case TransformOperation::TRANSLATE_3D:
+ return PlatformCAAnimation::Translate;
+ default:
+ return PlatformCAAnimation::NoValueFunction;
+ }
+}
+#endif
+
+static String propertyIdToString(AnimatedPropertyID property)
+{
+ switch (property) {
+ case AnimatedPropertyWebkitTransform:
+ return "transform";
+ case AnimatedPropertyOpacity:
+ return "opacity";
+ case AnimatedPropertyBackgroundColor:
+ return "backgroundColor";
+ case AnimatedPropertyInvalid:
+ ASSERT_NOT_REACHED();
+ }
+ ASSERT_NOT_REACHED();
+ return "";
+}
+
+static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index)
+{
+ return makeString(animationName, '_', String::number(property), '_', String::number(index));
+}
+
+static bool animationHasStepsTimingFunction(const KeyframeValueList& valueList, const Animation* anim)
+{
+ if (anim->timingFunction()->isStepsTimingFunction())
+ return true;
+
+ for (unsigned i = 0; i < valueList.size(); ++i) {
+ const TimingFunction* timingFunction = valueList.at(i)->timingFunction();
+ if (timingFunction && timingFunction->isStepsTimingFunction())
+ return true;
+ }
+
+ return false;
+}
+
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerCA(client);
+}
+
+GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
+ : GraphicsLayer(client)
+ , m_contentsLayerPurpose(NoContentsLayer)
+ , m_contentsLayerHasBackgroundColor(false)
+ , m_uncommittedChanges(NoChange)
+{
+ m_layer = PlatformCALayer::create(PlatformCALayer::LayerTypeWebLayer, this);
+
+#if !HAVE_MODERN_QUARTZCORE
+ setContentsOrientation(defaultContentsOrientation());
+#endif
+
+ updateDebugIndicators();
+}
+
+GraphicsLayerCA::~GraphicsLayerCA()
+{
+ // We release our references to the PlatformCALayers here, but do not actively unparent them,
+ // since that will cause a commit and break our batched commit model. The layers will
+ // get released when the rootmost modified GraphicsLayerCA rebuilds its child layers.
+
+ // Clean up the layer.
+ if (m_layer)
+ m_layer->setOwner(0);
+
+ if (m_contentsLayer)
+ m_contentsLayer->setOwner(0);
+
+ if (m_structuralLayer)
+ m_structuralLayer->setOwner(0);
+
+ removeCloneLayers();
+}
+
+void GraphicsLayerCA::setName(const String& name)
+{
+ String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
+ GraphicsLayer::setName(longName);
+ noteLayerPropertyChanged(NameChanged);
+}
+
+PlatformLayer* GraphicsLayerCA::platformLayer() const
+{
+ return primaryLayer()->platformLayer();
+}
+
+bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ bool childrenChanged = GraphicsLayer::setChildren(children);
+ if (childrenChanged)
+ noteSublayersChanged();
+
+ return childrenChanged;
+}
+
+void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
+{
+ GraphicsLayer::addChild(childLayer);
+ noteSublayersChanged();
+}
+
+void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+ GraphicsLayer::addChildAtIndex(childLayer, index);
+ noteSublayersChanged();
+}
+
+void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildBelow(childLayer, sibling);
+ noteSublayersChanged();
+}
+
+void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildAbove(childLayer, sibling);
+ noteSublayersChanged();
+}
+
+bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ noteSublayersChanged();
+ return true;
+ }
+ return false;
+}
+
+void GraphicsLayerCA::removeFromParent()
+{
+ if (m_parent)
+ static_cast<GraphicsLayerCA*>(m_parent)->noteSublayersChanged();
+ GraphicsLayer::removeFromParent();
+}
+
+void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer)
+{
+ if (layer == m_maskLayer)
+ return;
+
+ GraphicsLayer::setMaskLayer(layer);
+ noteLayerPropertyChanged(MaskLayerChanged);
+
+ propagateLayerChangeToReplicas();
+
+ if (m_replicatedLayer)
+ static_cast<GraphicsLayerCA*>(m_replicatedLayer)->propagateLayerChangeToReplicas();
+}
+
+void GraphicsLayerCA::setReplicatedLayer(GraphicsLayer* layer)
+{
+ if (layer == m_replicatedLayer)
+ return;
+
+ GraphicsLayer::setReplicatedLayer(layer);
+ noteLayerPropertyChanged(ReplicatedLayerChanged);
+}
+
+void GraphicsLayerCA::setReplicatedByLayer(GraphicsLayer* layer)
+{
+ if (layer == m_replicaLayer)
+ return;
+
+ GraphicsLayer::setReplicatedByLayer(layer);
+ noteSublayersChanged();
+ noteLayerPropertyChanged(ReplicatedLayerChanged);
+}
+
+void GraphicsLayerCA::setPosition(const FloatPoint& point)
+{
+ if (point == m_position)
+ return;
+
+ GraphicsLayer::setPosition(point);
+ noteLayerPropertyChanged(PositionChanged);
+}
+
+void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
+{
+ if (point == m_anchorPoint)
+ return;
+
+ GraphicsLayer::setAnchorPoint(point);
+ noteLayerPropertyChanged(AnchorPointChanged);
+}
+
+void GraphicsLayerCA::setSize(const FloatSize& size)
+{
+ if (size == m_size)
+ return;
+
+ GraphicsLayer::setSize(size);
+ noteLayerPropertyChanged(SizeChanged);
+}
+
+void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
+{
+ if (t == m_transform)
+ return;
+
+ GraphicsLayer::setTransform(t);
+ noteLayerPropertyChanged(TransformChanged);
+}
+
+void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
+{
+ if (t == m_childrenTransform)
+ return;
+
+ GraphicsLayer::setChildrenTransform(t);
+ noteLayerPropertyChanged(ChildrenTransformChanged);
+}
+
+void GraphicsLayerCA::moveOrCopyLayerAnimation(MoveOrCopy operation, const String& animationIdentifier, PlatformCALayer *fromLayer, PlatformCALayer *toLayer)
+{
+ RefPtr<PlatformCAAnimation> anim = fromLayer->animationForKey(animationIdentifier);
+ if (!anim)
+ return;
+
+ switch (operation) {
+ case Move:
+ fromLayer->removeAnimationForKey(animationIdentifier);
+ toLayer->addAnimationForKey(animationIdentifier, anim.get());
+ break;
+
+ case Copy:
+ toLayer->addAnimationForKey(animationIdentifier, anim.get());
+ break;
+ }
+}
+
+void GraphicsLayerCA::moveOrCopyAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, PlatformCALayer *fromLayer, PlatformCALayer *toLayer)
+{
+ // Look for running animations affecting this property.
+ AnimationsMap::const_iterator end = m_runningAnimations.end();
+ for (AnimationsMap::const_iterator it = m_runningAnimations.begin(); it != end; ++it) {
+ const Vector<LayerPropertyAnimation>& propertyAnimations = it->second;
+ size_t numAnimations = propertyAnimations.size();
+ for (size_t i = 0; i < numAnimations; ++i) {
+ const LayerPropertyAnimation& currAnimation = propertyAnimations[i];
+ if (currAnimation.m_property == property)
+ moveOrCopyLayerAnimation(operation, animationIdentifier(currAnimation.m_name, currAnimation.m_property, currAnimation.m_index), fromLayer, toLayer);
+ }
+ }
+}
+
+void GraphicsLayerCA::setPreserves3D(bool preserves3D)
+{
+ if (preserves3D == m_preserves3D)
+ return;
+
+ GraphicsLayer::setPreserves3D(preserves3D);
+ noteLayerPropertyChanged(Preserves3DChanged);
+}
+
+void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
+{
+ if (masksToBounds == m_masksToBounds)
+ return;
+
+ GraphicsLayer::setMasksToBounds(masksToBounds);
+ noteLayerPropertyChanged(MasksToBoundsChanged);
+}
+
+void GraphicsLayerCA::setDrawsContent(bool drawsContent)
+{
+ if (drawsContent == m_drawsContent)
+ return;
+
+ GraphicsLayer::setDrawsContent(drawsContent);
+ noteLayerPropertyChanged(DrawsContentChanged);
+}
+
+void GraphicsLayerCA::setAcceleratesDrawing(bool acceleratesDrawing)
+{
+ if (acceleratesDrawing == m_acceleratesDrawing)
+ return;
+
+ GraphicsLayer::setAcceleratesDrawing(acceleratesDrawing);
+ noteLayerPropertyChanged(AcceleratesDrawingChanged);
+}
+
+void GraphicsLayerCA::setBackgroundColor(const Color& color)
+{
+ if (m_backgroundColorSet && m_backgroundColor == color)
+ return;
+
+ GraphicsLayer::setBackgroundColor(color);
+
+ m_contentsLayerHasBackgroundColor = true;
+ noteLayerPropertyChanged(BackgroundColorChanged);
+}
+
+void GraphicsLayerCA::clearBackgroundColor()
+{
+ if (!m_backgroundColorSet)
+ return;
+
+ GraphicsLayer::clearBackgroundColor();
+ m_contentsLayerHasBackgroundColor = false;
+ noteLayerPropertyChanged(BackgroundColorChanged);
+}
+
+void GraphicsLayerCA::setContentsOpaque(bool opaque)
+{
+ if (m_contentsOpaque == opaque)
+ return;
+
+ GraphicsLayer::setContentsOpaque(opaque);
+ noteLayerPropertyChanged(ContentsOpaqueChanged);
+}
+
+void GraphicsLayerCA::setBackfaceVisibility(bool visible)
+{
+ if (m_backfaceVisibility == visible)
+ return;
+
+ GraphicsLayer::setBackfaceVisibility(visible);
+ noteLayerPropertyChanged(BackfaceVisibilityChanged);
+}
+
+void GraphicsLayerCA::setOpacity(float opacity)
+{
+ float clampedOpacity = max(0.0f, min(opacity, 1.0f));
+
+ if (clampedOpacity == m_opacity)
+ return;
+
+ GraphicsLayer::setOpacity(clampedOpacity);
+ noteLayerPropertyChanged(OpacityChanged);
+}
+
+void GraphicsLayerCA::setNeedsDisplay()
+{
+ FloatRect hugeRect(-numeric_limits<float>::max() / 2, -numeric_limits<float>::max() / 2,
+ numeric_limits<float>::max(), numeric_limits<float>::max());
+
+ setNeedsDisplayInRect(hugeRect);
+}
+
+void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ if (!drawsContent())
+ return;
+
+ const size_t maxDirtyRects = 32;
+
+ for (size_t i = 0; i < m_dirtyRects.size(); ++i) {
+ if (m_dirtyRects[i].contains(rect))
+ return;
+ }
+
+ if (m_dirtyRects.size() < maxDirtyRects)
+ m_dirtyRects.append(rect);
+ else
+ m_dirtyRects[0].unite(rect);
+
+ noteLayerPropertyChanged(DirtyRectsChanged);
+}
+
+void GraphicsLayerCA::setContentsNeedsDisplay()
+{
+ noteLayerPropertyChanged(ContentsNeedsDisplay);
+}
+
+void GraphicsLayerCA::setContentsRect(const IntRect& rect)
+{
+ if (rect == m_contentsRect)
+ return;
+
+ GraphicsLayer::setContentsRect(rect);
+ noteLayerPropertyChanged(ContentsRectChanged);
+}
+
+bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& animationName, double timeOffset)
+{
+ ASSERT(!animationName.isEmpty());
+
+ if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
+ return false;
+
+#if !HAVE_MODERN_QUARTZCORE
+ // Older versions of QuartzCore do not handle opacity in transform layers properly, so we will
+ // always do software animation in that case.
+ if (valueList.property() == AnimatedPropertyOpacity)
+ return false;
+#endif
+
+ // CoreAnimation does not handle the steps() timing function. Fall back
+ // to software animation in that case.
+ if (animationHasStepsTimingFunction(valueList, anim))
+ return false;
+
+ bool createdAnimations = false;
+ if (valueList.property() == AnimatedPropertyWebkitTransform)
+ createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize);
+ else
+ createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset);
+
+ if (createdAnimations)
+ noteLayerPropertyChanged(AnimationChanged);
+
+ return createdAnimations;
+}
+
+void GraphicsLayerCA::pauseAnimation(const String& animationName, double timeOffset)
+{
+ if (!animationIsRunning(animationName))
+ return;
+
+ AnimationsToProcessMap::iterator it = m_animationsToProcess.find(animationName);
+ if (it != m_animationsToProcess.end()) {
+ AnimationProcessingAction& processingInfo = it->second;
+ // If an animation is scheduled to be removed, don't change the remove to a pause.
+ if (processingInfo.action != Remove)
+ processingInfo.action = Pause;
+ } else
+ m_animationsToProcess.add(animationName, AnimationProcessingAction(Pause, timeOffset));
+
+ noteLayerPropertyChanged(AnimationChanged);
+}
+
+void GraphicsLayerCA::removeAnimation(const String& animationName)
+{
+ if (!animationIsRunning(animationName))
+ return;
+
+ m_animationsToProcess.add(animationName, AnimationProcessingAction(Remove));
+ noteLayerPropertyChanged(AnimationChanged);
+}
+
+void GraphicsLayerCA::platformCALayerAnimationStarted(CFTimeInterval startTime)
+{
+ if (m_client)
+ m_client->notifyAnimationStarted(this, startTime);
+}
+
+void GraphicsLayerCA::setContentsToImage(Image* image)
+{
+ if (image) {
+ CGImageRef newImage = image->nativeImageForCurrentFrame();
+ if (!newImage)
+ return;
+
+ // Check to see if the image changed; we have to do this because the call to
+ // CGImageCreateCopyWithColorSpace() below can create a new image every time.
+ if (m_uncorrectedContentsImage && m_uncorrectedContentsImage.get() == newImage)
+ return;
+
+ m_uncorrectedContentsImage = newImage;
+ m_pendingContentsImage = newImage;
+
+#if !PLATFORM(WIN)
+ CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get());
+
+ static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ if (colorSpace && CFEqual(colorSpace, deviceRGB)) {
+ // CoreGraphics renders images tagged with DeviceRGB using the color space of the main display. When we hand such
+ // images to CA we need to tag them similarly so CA rendering matches CG rendering.
+ static CGColorSpaceRef genericRGB = CGDisplayCopyColorSpace(kCGDirectMainDisplay);
+ m_pendingContentsImage.adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB));
+ }
+#endif
+ m_contentsLayerPurpose = ContentsLayerForImage;
+ if (!m_contentsLayer)
+ noteSublayersChanged();
+ } else {
+ m_uncorrectedContentsImage = 0;
+ m_pendingContentsImage = 0;
+ m_contentsLayerPurpose = NoContentsLayer;
+ if (m_contentsLayer)
+ noteSublayersChanged();
+ }
+
+ noteLayerPropertyChanged(ContentsImageChanged);
+}
+
+void GraphicsLayerCA::setContentsToMedia(PlatformLayer* mediaLayer)
+{
+ if (m_contentsLayer && mediaLayer == m_contentsLayer->platformLayer())
+ return;
+
+ // FIXME: The passed in layer might be a raw layer or an externally created
+ // PlatformCALayer. To determine this we attempt to get the
+ // PlatformCALayer pointer. If this returns a null pointer we assume it's
+ // raw. This test might be invalid if the raw layer is, for instance, the
+ // PlatformCALayer is using a user data pointer in the raw layer, and
+ // the creator of the raw layer is using it for some other purpose.
+ // For now we don't support such a case.
+ PlatformCALayer* platformCALayer = PlatformCALayer::platformCALayer(mediaLayer);
+ m_contentsLayer = mediaLayer ? (platformCALayer ? platformCALayer : PlatformCALayer::create(mediaLayer, this)) : 0;
+ m_contentsLayerPurpose = mediaLayer ? ContentsLayerForMedia : NoContentsLayer;
+
+ noteSublayersChanged();
+ noteLayerPropertyChanged(ContentsMediaLayerChanged);
+}
+
+void GraphicsLayerCA::setContentsToCanvas(PlatformLayer* canvasLayer)
+{
+ if (m_contentsLayer && canvasLayer == m_contentsLayer->platformLayer())
+ return;
+
+ // Create the PlatformCALayer to wrap the incoming layer
+ m_contentsLayer = canvasLayer ? PlatformCALayer::create(canvasLayer, this) : 0;
+
+ m_contentsLayerPurpose = canvasLayer ? ContentsLayerForCanvas : NoContentsLayer;
+
+ noteSublayersChanged();
+ noteLayerPropertyChanged(ContentsCanvasLayerChanged);
+}
+
+void GraphicsLayerCA::layerDidDisplay(PlatformLayer* layer)
+{
+ PlatformCALayer* currentLayer = PlatformCALayer::platformCALayer(layer);
+ PlatformCALayer* sourceLayer;
+ LayerMap* layerCloneMap;
+
+ if (currentLayer == m_layer) {
+ sourceLayer = m_layer.get();
+ layerCloneMap = m_layerClones.get();
+ } else if (currentLayer == m_contentsLayer) {
+ sourceLayer = m_contentsLayer.get();
+ layerCloneMap = m_contentsLayerClones.get();
+ } else
+ return;
+
+ if (layerCloneMap) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ PlatformCALayer* currClone = it->second.get();
+ if (!currClone)
+ continue;
+
+ if (currClone->contents() != sourceLayer->contents())
+ currClone->setContents(sourceLayer->contents());
+ else
+ currClone->setContentsChanged();
+ }
+ }
+}
+
+void GraphicsLayerCA::syncCompositingState()
+{
+ recursiveCommitChanges();
+}
+
+void GraphicsLayerCA::syncCompositingStateForThisLayerOnly()
+{
+ commitLayerChangesBeforeSublayers();
+ commitLayerChangesAfterSublayers();
+}
+
+void GraphicsLayerCA::recursiveCommitChanges()
+{
+ commitLayerChangesBeforeSublayers();
+
+ if (m_maskLayer)
+ static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesBeforeSublayers();
+
+ const Vector<GraphicsLayer*>& childLayers = children();
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
+ curChild->recursiveCommitChanges();
+ }
+
+ if (m_replicaLayer)
+ static_cast<GraphicsLayerCA*>(m_replicaLayer)->recursiveCommitChanges();
+
+ if (m_maskLayer)
+ static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesAfterSublayers();
+
+ commitLayerChangesAfterSublayers();
+}
+
+void GraphicsLayerCA::commitLayerChangesBeforeSublayers()
+{
+ if (!m_uncommittedChanges)
+ return;
+
+ // Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to
+ if (m_uncommittedChanges & (Preserves3DChanged | ReplicatedLayerChanged))
+ updateStructuralLayer();
+
+ if (m_uncommittedChanges & NameChanged)
+ updateLayerNames();
+
+ if (m_uncommittedChanges & ContentsImageChanged) // Needs to happen before ChildrenChanged
+ updateContentsImage();
+
+ if (m_uncommittedChanges & ContentsMediaLayerChanged) // Needs to happen before ChildrenChanged
+ updateContentsMediaLayer();
+
+ if (m_uncommittedChanges & ContentsCanvasLayerChanged) // Needs to happen before ChildrenChanged
+ updateContentsCanvasLayer();
+
+ if (m_uncommittedChanges & BackgroundColorChanged) // Needs to happen before ChildrenChanged, and after updating image or video
+ updateLayerBackgroundColor();
+
+ if (m_uncommittedChanges & ChildrenChanged)
+ updateSublayerList();
+
+ if (m_uncommittedChanges & PositionChanged)
+ updateLayerPosition();
+
+ if (m_uncommittedChanges & AnchorPointChanged)
+ updateAnchorPoint();
+
+ if (m_uncommittedChanges & SizeChanged)
+ updateLayerSize();
+
+ if (m_uncommittedChanges & TransformChanged)
+ updateTransform();
+
+ if (m_uncommittedChanges & ChildrenTransformChanged)
+ updateChildrenTransform();
+
+ if (m_uncommittedChanges & MasksToBoundsChanged)
+ updateMasksToBounds();
+
+ if (m_uncommittedChanges & DrawsContentChanged)
+ updateLayerDrawsContent();
+
+ if (m_uncommittedChanges & ContentsOpaqueChanged)
+ updateContentsOpaque();
+
+ if (m_uncommittedChanges & BackfaceVisibilityChanged)
+ updateBackfaceVisibility();
+
+ if (m_uncommittedChanges & OpacityChanged)
+ updateOpacityOnLayer();
+
+ if (m_uncommittedChanges & AnimationChanged)
+ updateLayerAnimations();
+
+ if (m_uncommittedChanges & DirtyRectsChanged)
+ repaintLayerDirtyRects();
+
+ if (m_uncommittedChanges & ContentsRectChanged)
+ updateContentsRect();
+
+ if (m_uncommittedChanges & MaskLayerChanged)
+ updateMaskLayer();
+
+ if (m_uncommittedChanges & ContentsNeedsDisplay)
+ updateContentsNeedsDisplay();
+
+ if (m_uncommittedChanges & AcceleratesDrawingChanged)
+ updateAcceleratesDrawing();
+}
+
+void GraphicsLayerCA::commitLayerChangesAfterSublayers()
+{
+ if (!m_uncommittedChanges)
+ return;
+
+ if (m_uncommittedChanges & ReplicatedLayerChanged)
+ updateReplicatedLayers();
+
+ m_uncommittedChanges = NoChange;
+}
+
+void GraphicsLayerCA::updateLayerNames()
+{
+ switch (structuralLayerPurpose()) {
+ case StructuralLayerForPreserves3D:
+ m_structuralLayer->setName("Transform layer " + name());
+ break;
+ case StructuralLayerForReplicaFlattening:
+ m_structuralLayer->setName("Replica flattening layer " + name());
+ break;
+ case NoStructuralLayer:
+ break;
+ }
+ m_layer->setName(name());
+}
+
+void GraphicsLayerCA::updateSublayerList()
+{
+ PlatformCALayerList newSublayers;
+ const Vector<GraphicsLayer*>& childLayers = children();
+
+ if (m_structuralLayer || m_contentsLayer || childLayers.size() > 0) {
+ if (m_structuralLayer) {
+ // Add the replica layer first.
+ if (m_replicaLayer)
+ newSublayers.append(static_cast<GraphicsLayerCA*>(m_replicaLayer)->primaryLayer());
+ // Add the primary layer. Even if we have negative z-order children, the primary layer always comes behind.
+ newSublayers.append(m_layer);
+ } else if (m_contentsLayer) {
+ // FIXME: add the contents layer in the correct order with negative z-order children.
+ // This does not cause visible rendering issues because currently contents layers are only used
+ // for replaced elements that don't have children.
+ newSublayers.append(m_contentsLayer);
+ }
+
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
+ PlatformCALayer* childLayer = curChild->layerForSuperlayer();
+ newSublayers.append(childLayer);
+ }
+
+ for (size_t i = 0; i < newSublayers.size(); --i)
+ newSublayers[i]->removeFromSuperlayer();
+ }
+
+ if (m_structuralLayer) {
+ m_structuralLayer->setSublayers(newSublayers);
+
+ if (m_contentsLayer) {
+ // If we have a transform layer, then the contents layer is parented in the
+ // primary layer (which is itself a child of the transform layer).
+ m_layer->removeAllSublayers();
+ m_layer->appendSublayer(m_contentsLayer.get());
+ }
+ } else
+ m_layer->setSublayers(newSublayers);
+}
+
+void GraphicsLayerCA::updateLayerPosition()
+{
+ FloatSize usedSize = m_usingTiledLayer ? constrainedSize() : m_size;
+
+ // Position is offset on the layer by the layer anchor point.
+ FloatPoint posPoint(m_position.x() + m_anchorPoint.x() * usedSize.width(),
+ m_position.y() + m_anchorPoint.y() * usedSize.height());
+
+ primaryLayer()->setPosition(posPoint);
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ FloatPoint clonePosition = posPoint;
+ if (m_replicaLayer && isReplicatedRootClone(it->first)) {
+ // Maintain the special-case position for the root of a clone subtree,
+ // which we set up in replicatedLayerRoot().
+ clonePosition = positionForCloneRootLayer();
+ }
+ it->second->setPosition(clonePosition);
+ }
+ }
+}
+
+void GraphicsLayerCA::updateLayerSize()
+{
+ FloatRect rect(0, 0, m_size.width(), m_size.height());
+ if (m_structuralLayer) {
+ m_structuralLayer->setBounds(rect);
+
+ if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ it->second->setBounds(rect);
+ }
+
+ // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative.
+ CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ m_layer->setPosition(centerPoint);
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ it->second->setPosition(centerPoint);
+ }
+ }
+
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ if (m_usingTiledLayer) {
+ FloatSize sizeToUse = constrainedSize();
+ rect = CGRectMake(0, 0, sizeToUse.width(), sizeToUse.height());
+ }
+
+ m_layer->setBounds(rect);
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ it->second->setBounds(rect);
+ }
+
+ // Contents transform may depend on height.
+ updateContentsTransform();
+
+ // Note that we don't resize m_contentsLayer. It's up the caller to do that.
+
+ // if we've changed the bounds, we need to recalculate the position
+ // of the layer, taking anchor point into account.
+ updateLayerPosition();
+}
+
+void GraphicsLayerCA::updateAnchorPoint()
+{
+ primaryLayer()->setAnchorPoint(m_anchorPoint);
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ PlatformCALayer* currLayer = it->second.get();
+ currLayer->setAnchorPoint(m_anchorPoint);
+ }
+ }
+
+ updateLayerPosition();
+}
+
+void GraphicsLayerCA::updateTransform()
+{
+ primaryLayer()->setTransform(m_transform);
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ PlatformCALayer* currLayer = it->second.get();
+ if (m_replicaLayer && isReplicatedRootClone(it->first)) {
+ // Maintain the special-case transform for the root of a clone subtree,
+ // which we set up in replicatedLayerRoot().
+ currLayer->setTransform(TransformationMatrix());
+ } else
+ currLayer->setTransform(m_transform);
+ }
+ }
+}
+
+void GraphicsLayerCA::updateChildrenTransform()
+{
+ primaryLayer()->setSublayerTransform(m_childrenTransform);
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ it->second->setSublayerTransform(m_childrenTransform);
+ }
+}
+
+void GraphicsLayerCA::updateMasksToBounds()
+{
+ m_layer->setMasksToBounds(m_masksToBounds);
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ it->second->setMasksToBounds(m_masksToBounds);
+ }
+
+ updateDebugIndicators();
+}
+
+void GraphicsLayerCA::updateContentsOpaque()
+{
+ m_layer.get()->setOpaque(m_contentsOpaque);
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ it->second->setOpaque(m_contentsOpaque);
+ }
+}
+
+void GraphicsLayerCA::updateBackfaceVisibility()
+{
+ if (m_structuralLayer && structuralLayerPurpose() == StructuralLayerForReplicaFlattening) {
+ m_structuralLayer->setDoubleSided(m_backfaceVisibility);
+
+ if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ it->second->setDoubleSided(m_backfaceVisibility);
+ }
+ }
+
+ m_layer->setDoubleSided(m_backfaceVisibility);
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ it->second->setDoubleSided(m_backfaceVisibility);
+ }
+}
+
+void GraphicsLayerCA::updateStructuralLayer()
+{
+ ensureStructuralLayer(structuralLayerPurpose());
+}
+
+void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose)
+{
+ if (purpose == NoStructuralLayer) {
+ if (m_structuralLayer) {
+ // Replace the transformLayer in the parent with this layer.
+ m_layer->removeFromSuperlayer();
+ m_structuralLayer->superlayer()->replaceSublayer(m_structuralLayer.get(), m_layer.get());
+
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_structuralLayer.get(), m_layer.get());
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_structuralLayer.get(), m_layer.get());
+
+ // Release the structural layer.
+ m_structuralLayer = 0;
+
+ // Update the properties of m_layer now that we no longer have a structural layer.
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+
+ updateSublayerList();
+ updateOpacityOnLayer();
+ }
+ return;
+ }
+
+ bool structuralLayerChanged = false;
+
+ if (purpose == StructuralLayerForPreserves3D) {
+ if (m_structuralLayer && m_structuralLayer->layerType() != PlatformCALayer::LayerTypeTransformLayer)
+ m_structuralLayer = 0;
+
+ if (!m_structuralLayer) {
+ m_structuralLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeTransformLayer, this);
+ structuralLayerChanged = true;
+ }
+ } else {
+ if (m_structuralLayer && m_structuralLayer->layerType() != PlatformCALayer::LayerTypeLayer)
+ m_structuralLayer = 0;
+
+ if (!m_structuralLayer) {
+ m_structuralLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, this);
+ structuralLayerChanged = true;
+ }
+ }
+
+ if (!structuralLayerChanged)
+ return;
+
+ updateLayerNames();
+
+ // Update the properties of the structural layer.
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+ updateBackfaceVisibility();
+
+ // Set properties of m_layer to their default values, since these are expressed on on the structural layer.
+ FloatPoint point(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ FloatPoint3D anchorPoint(0.5f, 0.5f, 0);
+ m_layer->setPosition(point);
+ m_layer->setAnchorPoint(anchorPoint);
+ m_layer->setTransform(TransformationMatrix());
+ m_layer->setOpacity(1);
+ if (m_layerClones) {
+ LayerMap::const_iterator end = m_layerClones->end();
+ for (LayerMap::const_iterator it = m_layerClones->begin(); it != end; ++it) {
+ PlatformCALayer* currLayer = it->second.get();
+ currLayer->setPosition(point);
+ currLayer->setAnchorPoint(anchorPoint);
+ currLayer->setTransform(TransformationMatrix());
+ currLayer->setOpacity(1);
+ }
+ }
+
+ // Move this layer to be a child of the transform layer.
+ m_layer->superlayer()->replaceSublayer(m_layer.get(), m_structuralLayer.get());
+ m_structuralLayer->appendSublayer(m_layer.get());
+
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_layer.get(), m_structuralLayer.get());
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_layer.get(), m_structuralLayer.get());
+
+ updateSublayerList();
+ updateOpacityOnLayer();
+}
+
+GraphicsLayerCA::StructuralLayerPurpose GraphicsLayerCA::structuralLayerPurpose() const
+{
+ if (preserves3D())
+ return StructuralLayerForPreserves3D;
+
+ if (isReplicated())
+ return StructuralLayerForReplicaFlattening;
+
+ return NoStructuralLayer;
+}
+
+void GraphicsLayerCA::updateLayerDrawsContent()
+{
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ if (m_drawsContent)
+ m_layer->setNeedsDisplay();
+ else
+ m_layer->setContents(0);
+
+ updateDebugIndicators();
+}
+
+void GraphicsLayerCA::updateAcceleratesDrawing()
+{
+ m_layer->setAcceleratesDrawing(m_acceleratesDrawing);
+}
+
+void GraphicsLayerCA::updateLayerBackgroundColor()
+{
+ if (!m_contentsLayer)
+ return;
+
+ // We never create the contents layer just for background color yet.
+ if (m_backgroundColorSet)
+ m_contentsLayer->setBackgroundColor(m_backgroundColor);
+ else
+ m_contentsLayer->setBackgroundColor(Color::transparent);
+}
+
+void GraphicsLayerCA::updateContentsImage()
+{
+ if (m_pendingContentsImage) {
+ if (!m_contentsLayer.get()) {
+ m_contentsLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, this);
+#ifndef NDEBUG
+ m_contentsLayer->setName("Image Layer");
+#endif
+ setupContentsLayer(m_contentsLayer.get());
+ // m_contentsLayer will be parented by updateSublayerList
+ }
+
+ // FIXME: maybe only do trilinear if the image is being scaled down,
+ // but then what if the layer size changes?
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ m_contentsLayer->setMinificationFilter(PlatformCALayer::Trilinear);
+#endif
+ m_contentsLayer->setContents(m_pendingContentsImage.get());
+ m_pendingContentsImage = 0;
+
+ if (m_contentsLayerClones) {
+ LayerMap::const_iterator end = m_contentsLayerClones->end();
+ for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it)
+ it->second->setContents(m_contentsLayer->contents());
+ }
+
+ updateContentsRect();
+ } else {
+ // No image.
+ // m_contentsLayer will be removed via updateSublayerList.
+ m_contentsLayer = 0;
+ }
+}
+
+void GraphicsLayerCA::updateContentsMediaLayer()
+{
+ // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList().
+ if (m_contentsLayer) {
+ setupContentsLayer(m_contentsLayer.get());
+ updateContentsRect();
+ }
+}
+
+void GraphicsLayerCA::updateContentsCanvasLayer()
+{
+ // CanvasLayer was set as m_contentsLayer, and will get parented in updateSublayerList().
+ if (m_contentsLayer) {
+ setupContentsLayer(m_contentsLayer.get());
+ m_contentsLayer->setNeedsDisplay();
+ updateContentsRect();
+ }
+}
+
+void GraphicsLayerCA::updateContentsRect()
+{
+ if (!m_contentsLayer)
+ return;
+
+ FloatPoint point(m_contentsRect.x(), m_contentsRect.y());
+ FloatRect rect(0, 0, m_contentsRect.width(), m_contentsRect.height());
+
+ m_contentsLayer->setPosition(point);
+ m_contentsLayer->setBounds(rect);
+
+ if (m_contentsLayerClones) {
+ LayerMap::const_iterator end = m_contentsLayerClones->end();
+ for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) {
+ it->second->setPosition(point);
+ it->second->setBounds(rect);
+ }
+ }
+}
+
+void GraphicsLayerCA::updateMaskLayer()
+{
+ PlatformCALayer* maskCALayer = m_maskLayer ? static_cast<GraphicsLayerCA*>(m_maskLayer)->primaryLayer() : 0;
+ m_layer->setMask(maskCALayer);
+
+ LayerMap* maskLayerCloneMap = m_maskLayer ? static_cast<GraphicsLayerCA*>(m_maskLayer)->primaryLayerClones() : 0;
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ PlatformCALayer* maskClone = maskLayerCloneMap ? maskLayerCloneMap->get(it->first).get() : 0;
+ it->second->setMask(maskClone);
+ }
+ }
+}
+
+void GraphicsLayerCA::updateReplicatedLayers()
+{
+ // Clone the descendants of the replicated layer, and parent under us.
+ ReplicaState replicaState(ReplicaState::ReplicaBranch);
+
+ RefPtr<PlatformCALayer>replicaRoot = replicatedLayerRoot(replicaState);
+ if (!replicaRoot)
+ return;
+
+ if (m_structuralLayer)
+ m_structuralLayer->insertSublayer(replicaRoot.get(), 0);
+ else
+ m_layer->insertSublayer(replicaRoot.get(), 0);
+}
+
+// For now, this assumes that layers only ever have one replica, so replicaIndices contains only 0 and 1.
+GraphicsLayerCA::CloneID GraphicsLayerCA::ReplicaState::cloneID() const
+{
+ size_t depth = m_replicaBranches.size();
+
+ const size_t bitsPerUChar = sizeof(UChar) * 8;
+ size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar;
+
+ Vector<UChar> result(vectorSize);
+ result.fill(0);
+
+ // Create a string from the bit sequence which we can use to identify the clone.
+ // Note that the string may contain embedded nulls, but that's OK.
+ for (size_t i = 0; i < depth; ++i) {
+ UChar& currChar = result[i / bitsPerUChar];
+ currChar = (currChar << 1) | m_replicaBranches[i];
+ }
+
+ return String::adopt(result);
+}
+
+PassRefPtr<PlatformCALayer> GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState)
+{
+ // Limit replica nesting, to avoid 2^N explosion of replica layers.
+ if (!m_replicatedLayer || replicaState.replicaDepth() == ReplicaState::maxReplicaDepth)
+ return 0;
+
+ GraphicsLayerCA* replicatedLayer = static_cast<GraphicsLayerCA*>(m_replicatedLayer);
+
+ RefPtr<PlatformCALayer> clonedLayerRoot = replicatedLayer->fetchCloneLayers(this, replicaState, RootCloneLevel);
+ FloatPoint cloneRootPosition = replicatedLayer->positionForCloneRootLayer();
+
+ // Replica root has no offset or transform
+ clonedLayerRoot->setPosition(cloneRootPosition);
+ clonedLayerRoot->setTransform(TransformationMatrix());
+
+ return clonedLayerRoot;
+}
+
+void GraphicsLayerCA::updateLayerAnimations()
+{
+ if (m_animationsToProcess.size()) {
+ AnimationsToProcessMap::const_iterator end = m_animationsToProcess.end();
+ for (AnimationsToProcessMap::const_iterator it = m_animationsToProcess.begin(); it != end; ++it) {
+ const String& currAnimationName = it->first;
+ AnimationsMap::iterator animationIt = m_runningAnimations.find(currAnimationName);
+ if (animationIt == m_runningAnimations.end())
+ continue;
+
+ const AnimationProcessingAction& processingInfo = it->second;
+ const Vector<LayerPropertyAnimation>& animations = animationIt->second;
+ for (size_t i = 0; i < animations.size(); ++i) {
+ const LayerPropertyAnimation& currAnimation = animations[i];
+ switch (processingInfo.action) {
+ case Remove:
+ removeCAAnimationFromLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index);
+ break;
+ case Pause:
+ pauseCAAnimationOnLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, processingInfo.timeOffset);
+ break;
+ }
+ }
+
+ if (processingInfo.action == Remove)
+ m_runningAnimations.remove(currAnimationName);
+ }
+
+ m_animationsToProcess.clear();
+ }
+
+ size_t numAnimations;
+ if ((numAnimations = m_uncomittedAnimations.size())) {
+ for (size_t i = 0; i < numAnimations; ++i) {
+ const LayerPropertyAnimation& pendingAnimation = m_uncomittedAnimations[i];
+ setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_name, pendingAnimation.m_index, pendingAnimation.m_timeOffset);
+
+ AnimationsMap::iterator it = m_runningAnimations.find(pendingAnimation.m_name);
+ if (it == m_runningAnimations.end()) {
+ Vector<LayerPropertyAnimation> animations;
+ animations.append(pendingAnimation);
+ m_runningAnimations.add(pendingAnimation.m_name, animations);
+ } else {
+ Vector<LayerPropertyAnimation>& animations = it->second;
+ animations.append(pendingAnimation);
+ }
+ }
+
+ m_uncomittedAnimations.clear();
+ }
+}
+
+void GraphicsLayerCA::setAnimationOnLayer(PlatformCAAnimation* caAnim, AnimatedPropertyID property, const String& animationName, int index, double timeOffset)
+{
+ PlatformCALayer* layer = animatedLayer(property);
+
+ if (timeOffset)
+ caAnim->setBeginTime(CACurrentMediaTime() - timeOffset);
+
+ String animationID = animationIdentifier(animationName, property, index);
+
+ layer->removeAnimationForKey(animationID);
+ layer->addAnimationForKey(animationID, caAnim);
+
+ if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ // Skip immediate replicas, since they move with the original.
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+
+ it->second->removeAnimationForKey(animationID);
+ it->second->addAnimationForKey(animationID, caAnim);
+ }
+ }
+}
+
+// Workaround for <rdar://problem/7311367>
+static void bug7311367Workaround(PlatformCALayer* transformLayer, const TransformationMatrix& transform)
+{
+ if (!transformLayer)
+ return;
+
+ TransformationMatrix caTransform = transform;
+ caTransform.setM41(caTransform.m41() + 1);
+ transformLayer->setTransform(caTransform);
+
+ caTransform.setM41(caTransform.m41() - 1);
+ transformLayer->setTransform(caTransform);
+}
+
+bool GraphicsLayerCA::removeCAAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index)
+{
+ PlatformCALayer* layer = animatedLayer(property);
+
+ String animationID = animationIdentifier(animationName, property, index);
+
+ if (!layer->animationForKey(animationID))
+ return false;
+
+ layer->removeAnimationForKey(animationID);
+ bug7311367Workaround(m_structuralLayer.get(), m_transform);
+
+ if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ // Skip immediate replicas, since they move with the original.
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+
+ it->second ->removeAnimationForKey(animationID);
+ }
+ }
+ return true;
+}
+
+void GraphicsLayerCA::pauseCAAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, double timeOffset)
+{
+ PlatformCALayer* layer = animatedLayer(property);
+
+ String animationID = animationIdentifier(animationName, property, index);
+
+ RefPtr<PlatformCAAnimation> curAnim = layer->animationForKey(animationID);
+ if (!curAnim)
+ return;
+
+ // Animations on the layer are immutable, so we have to clone and modify.
+ RefPtr<PlatformCAAnimation> newAnim = PlatformCAAnimation::create(curAnim.get());
+
+ newAnim->setSpeed(0);
+ newAnim->setTimeOffset(timeOffset);
+
+ layer->addAnimationForKey(animationID, newAnim.get()); // This will replace the running animation.
+
+ // Pause the animations on the clones too.
+ if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ // Skip immediate replicas, since they move with the original.
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+ it->second->addAnimationForKey(animationID, newAnim.get());
+ }
+ }
+}
+
+void GraphicsLayerCA::repaintLayerDirtyRects()
+{
+ if (!m_dirtyRects.size())
+ return;
+
+ for (size_t i = 0; i < m_dirtyRects.size(); ++i)
+ m_layer->setNeedsDisplay(&(m_dirtyRects[i]));
+
+ m_dirtyRects.clear();
+}
+
+void GraphicsLayerCA::updateContentsNeedsDisplay()
+{
+ if (m_contentsLayer)
+ m_contentsLayer->setNeedsDisplay();
+}
+
+bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset)
+{
+ ASSERT(valueList.property() != AnimatedPropertyWebkitTransform);
+
+ bool isKeyframe = valueList.size() > 2;
+ bool valuesOK;
+
+ bool additive = false;
+ int animationIndex = 0;
+
+ RefPtr<PlatformCAAnimation> caAnimation;
+
+ if (isKeyframe) {
+ caAnimation = createKeyframeAnimation(animation, valueList.property(), additive);
+ valuesOK = setAnimationKeyframes(valueList, animation, caAnimation.get());
+ } else {
+ caAnimation = createBasicAnimation(animation, valueList.property(), additive);
+ valuesOK = setAnimationEndpoints(valueList, animation, caAnimation.get());
+ }
+
+ if (!valuesOK)
+ return false;
+
+ m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset));
+
+ return true;
+}
+
+bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const IntSize& boxSize)
+{
+ ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
+
+ TransformOperationList functionList;
+ bool listsMatch, hasBigRotation;
+ fetchTransformOperationList(valueList, functionList, listsMatch, hasBigRotation);
+
+ // We need to fall back to software animation if we don't have setValueFunction:, and
+ // we would need to animate each incoming transform function separately. This is the
+ // case if we have a rotation >= 180 or we have more than one transform function.
+ if ((hasBigRotation || functionList.size() > 1) && !PlatformCAAnimation::supportsValueFunction())
+ return false;
+
+ bool validMatrices = true;
+
+ // If functionLists don't match we do a matrix animation, otherwise we do a component hardware animation.
+ // Also, we can't do component animation unless we have valueFunction, so we need to do matrix animation
+ // if that's not true as well.
+ bool isMatrixAnimation = !listsMatch || !PlatformCAAnimation::supportsValueFunction();
+
+ size_t numAnimations = isMatrixAnimation ? 1 : functionList.size();
+ bool isKeyframe = valueList.size() > 2;
+
+ // Iterate through the transform functions, sending an animation for each one.
+ for (size_t animationIndex = 0; animationIndex < numAnimations; ++animationIndex) {
+ TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[animationIndex];
+ RefPtr<PlatformCAAnimation> caAnimation;
+
+#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD)
+ // CA applies animations in reverse order (<rdar://problem/7095638>) so we need the last one we add (per property)
+ // to be non-additive.
+ bool additive = animationIndex < (numAnimations - 1);
+#else
+ bool additive = animationIndex > 0;
+#endif
+ if (isKeyframe) {
+ caAnimation = createKeyframeAnimation(animation, valueList.property(), additive);
+ validMatrices = setTransformAnimationKeyframes(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize);
+ } else {
+ caAnimation = createBasicAnimation(animation, valueList.property(), additive);
+ validMatrices = setTransformAnimationEndpoints(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize);
+ }
+
+ if (!validMatrices)
+ break;
+
+ m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset));
+ }
+
+ return validMatrices;
+}
+
+PassRefPtr<PlatformCAAnimation> GraphicsLayerCA::createBasicAnimation(const Animation* anim, AnimatedPropertyID property, bool additive)
+{
+ RefPtr<PlatformCAAnimation> basicAnim = PlatformCAAnimation::create(PlatformCAAnimation::Basic, propertyIdToString(property));
+ setupAnimation(basicAnim.get(), anim, additive);
+ return basicAnim;
+}
+
+PassRefPtr<PlatformCAAnimation>GraphicsLayerCA::createKeyframeAnimation(const Animation* anim, AnimatedPropertyID property, bool additive)
+{
+ RefPtr<PlatformCAAnimation> keyframeAnim = PlatformCAAnimation::create(PlatformCAAnimation::Keyframe, propertyIdToString(property));
+ setupAnimation(keyframeAnim.get(), anim, additive);
+ return keyframeAnim;
+}
+
+void GraphicsLayerCA::setupAnimation(PlatformCAAnimation* propertyAnim, const Animation* anim, bool additive)
+{
+ double duration = anim->duration();
+ if (duration <= 0)
+ duration = cAnimationAlmostZeroDuration;
+
+ float repeatCount = anim->iterationCount();
+ if (repeatCount == Animation::IterationCountInfinite)
+ repeatCount = FLT_MAX;
+ else if (anim->direction() == Animation::AnimationDirectionAlternate)
+ repeatCount /= 2;
+
+ PlatformCAAnimation::FillModeType fillMode = PlatformCAAnimation::NoFillMode;
+ switch (anim->fillMode()) {
+ case AnimationFillModeNone:
+ fillMode = PlatformCAAnimation::Forwards; // Use "forwards" rather than "removed" because the style system will remove the animation when it is finished. This avoids a flash.
+ break;
+ case AnimationFillModeBackwards:
+ fillMode = PlatformCAAnimation::Both; // Use "both" rather than "backwards" because the style system will remove the animation when it is finished. This avoids a flash.
+ break;
+ case AnimationFillModeForwards:
+ fillMode = PlatformCAAnimation::Forwards;
+ break;
+ case AnimationFillModeBoth:
+ fillMode = PlatformCAAnimation::Both;
+ break;
+ }
+
+ propertyAnim->setDuration(duration);
+ propertyAnim->setRepeatCount(repeatCount);
+ propertyAnim->setAutoreverses(anim->direction());
+ propertyAnim->setRemovedOnCompletion(false);
+ propertyAnim->setAdditive(additive);
+ propertyAnim->setFillMode(fillMode);
+}
+
+const TimingFunction* GraphicsLayerCA::timingFunctionForAnimationValue(const AnimationValue* animValue, const Animation* anim)
+{
+ if (animValue->timingFunction())
+ return animValue->timingFunction();
+ if (anim->isTimingFunctionSet())
+ return anim->timingFunction().get();
+
+ return 0;
+}
+
+bool GraphicsLayerCA::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, PlatformCAAnimation* basicAnim)
+{
+ switch (valueList.property()) {
+ case AnimatedPropertyOpacity: {
+ basicAnim->setFromValue(static_cast<const FloatAnimationValue*>(valueList.at(0))->value());
+ basicAnim->setToValue(static_cast<const FloatAnimationValue*>(valueList.at(1))->value());
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED(); // we don't animate color yet
+ break;
+ }
+
+ // This codepath is used for 2-keyframe animations, so we still need to look in the start
+ // for a timing function.
+ const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim);
+ if (timingFunction)
+ basicAnim->setTimingFunction(timingFunction);
+
+ return true;
+}
+
+bool GraphicsLayerCA::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* anim, PlatformCAAnimation* keyframeAnim)
+{
+ Vector<float> keyTimes;
+ Vector<float> values;
+ Vector<const TimingFunction*> timingFunctions;
+
+ for (unsigned i = 0; i < valueList.size(); ++i) {
+ const AnimationValue* curValue = valueList.at(i);
+ keyTimes.append(curValue->keyTime());
+
+ switch (valueList.property()) {
+ case AnimatedPropertyOpacity: {
+ const FloatAnimationValue* floatValue = static_cast<const FloatAnimationValue*>(curValue);
+ values.append(floatValue->value());
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED(); // we don't animate color yet
+ break;
+ }
+
+ timingFunctions.append(timingFunctionForAnimationValue(curValue, anim));
+ }
+
+ // We toss the last tfArray value because it has to one shorter than the others.
+ timingFunctions.removeLast();
+
+ keyframeAnim->setKeyTimes(keyTimes);
+ keyframeAnim->setValues(values);
+ keyframeAnim->setTimingFunctions(timingFunctions);
+
+ return true;
+}
+
+bool GraphicsLayerCA::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, PlatformCAAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
+{
+ ASSERT(valueList.size() == 2);
+ const TransformAnimationValue* startValue = static_cast<const TransformAnimationValue*>(valueList.at(0));
+ const TransformAnimationValue* endValue = static_cast<const TransformAnimationValue*>(valueList.at(1));
+
+ if (isMatrixAnimation) {
+ TransformationMatrix fromTransform, toTransform;
+ startValue->value()->apply(boxSize, fromTransform);
+ endValue->value()->apply(boxSize, toTransform);
+
+ // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
+ if (!fromTransform.isInvertible() || !toTransform.isInvertible())
+ return false;
+
+ basicAnim->setFromValue(fromTransform);
+ basicAnim->setToValue(toTransform);
+ } else {
+ if (isTransformTypeNumber(transformOpType)) {
+ float value;
+ getTransformFunctionValue(startValue->value()->at(functionIndex), transformOpType, boxSize, value);
+ basicAnim->setFromValue(value);
+ getTransformFunctionValue(endValue->value()->at(functionIndex), transformOpType, boxSize, value);
+ basicAnim->setToValue(value);
+ } else if (isTransformTypeFloatPoint3D(transformOpType)) {
+ FloatPoint3D value;
+ getTransformFunctionValue(startValue->value()->at(functionIndex), transformOpType, boxSize, value);
+ basicAnim->setFromValue(value);
+ getTransformFunctionValue(endValue->value()->at(functionIndex), transformOpType, boxSize, value);
+ basicAnim->setToValue(value);
+ } else {
+ TransformationMatrix value;
+ getTransformFunctionValue(startValue->value()->at(functionIndex), transformOpType, boxSize, value);
+ basicAnim->setFromValue(value);
+ getTransformFunctionValue(endValue->value()->at(functionIndex), transformOpType, boxSize, value);
+ basicAnim->setToValue(value);
+ }
+ }
+
+ // This codepath is used for 2-keyframe animations, so we still need to look in the start
+ // for a timing function.
+ const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim);
+ basicAnim->setTimingFunction(timingFunction);
+
+#if HAVE_MODERN_QUARTZCORE
+ PlatformCAAnimation::ValueFunctionType valueFunction = getValueFunctionNameForTransformOperation(transformOpType);
+ if (valueFunction != PlatformCAAnimation::NoValueFunction)
+ basicAnim->setValueFunction(valueFunction);
+#endif
+
+ return true;
+}
+
+bool GraphicsLayerCA::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
+{
+ Vector<float> keyTimes;
+ Vector<float> floatValues;
+ Vector<FloatPoint3D> floatPoint3DValues;
+ Vector<TransformationMatrix> transformationMatrixValues;
+ Vector<const TimingFunction*> timingFunctions;
+
+ for (unsigned i = 0; i < valueList.size(); ++i) {
+ const TransformAnimationValue* curValue = static_cast<const TransformAnimationValue*>(valueList.at(i));
+ keyTimes.append(curValue->keyTime());
+
+ if (isMatrixAnimation) {
+ TransformationMatrix transform;
+ curValue->value()->apply(boxSize, transform);
+
+ // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
+ if (!transform.isInvertible())
+ return false;
+
+ transformationMatrixValues.append(transform);
+ } else {
+ const TransformOperation* transformOp = curValue->value()->at(functionIndex);
+ if (isTransformTypeNumber(transformOpType)) {
+ float value;
+ getTransformFunctionValue(transformOp, transformOpType, boxSize, value);
+ floatValues.append(value);
+ } else if (isTransformTypeFloatPoint3D(transformOpType)) {
+ FloatPoint3D value;
+ getTransformFunctionValue(transformOp, transformOpType, boxSize, value);
+ floatPoint3DValues.append(value);
+ } else {
+ TransformationMatrix value;
+ getTransformFunctionValue(transformOp, transformOpType, boxSize, value);
+ transformationMatrixValues.append(value);
+ }
+ }
+
+ const TimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, animation);
+ timingFunctions.append(timingFunction);
+ }
+
+ // We toss the last tfArray value because it has to one shorter than the others.
+ timingFunctions.removeLast();
+
+ keyframeAnim->setKeyTimes(keyTimes);
+
+ if (isTransformTypeNumber(transformOpType))
+ keyframeAnim->setValues(floatValues);
+ else if (isTransformTypeFloatPoint3D(transformOpType))
+ keyframeAnim->setValues(floatPoint3DValues);
+ else
+ keyframeAnim->setValues(transformationMatrixValues);
+
+ keyframeAnim->setTimingFunctions(timingFunctions);
+
+#if HAVE_MODERN_QUARTZCORE
+ PlatformCAAnimation::ValueFunctionType valueFunction = getValueFunctionNameForTransformOperation(transformOpType);
+ if (valueFunction != PlatformCAAnimation::NoValueFunction)
+ keyframeAnim->setValueFunction(valueFunction);
+#endif
+ return true;
+}
+
+void GraphicsLayerCA::suspendAnimations(double time)
+{
+ double t = currentTimeToMediaTime(time ? time : currentTime());
+ primaryLayer()->setSpeed(0);
+ primaryLayer()->setTimeOffset(t);
+
+ // Suspend the animations on the clones too.
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ it->second->setSpeed(0);
+ it->second->setTimeOffset(t);
+ }
+ }
+}
+
+void GraphicsLayerCA::resumeAnimations()
+{
+ primaryLayer()->setSpeed(1);
+ primaryLayer()->setTimeOffset(0);
+
+ // Resume the animations on the clones too.
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ it->second->setSpeed(1);
+ it->second->setTimeOffset(0);
+ }
+ }
+}
+
+PlatformCALayer* GraphicsLayerCA::hostLayerForSublayers() const
+{
+ return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get();
+}
+
+PlatformCALayer* GraphicsLayerCA::layerForSuperlayer() const
+{
+ return m_structuralLayer ? m_structuralLayer.get() : m_layer.get();
+}
+
+PlatformCALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const
+{
+ return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
+}
+
+GraphicsLayerCA::LayerMap* GraphicsLayerCA::animatedLayerClones(AnimatedPropertyID property) const
+{
+ return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones();
+}
+
+void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
+{
+ if (color.isValid())
+ m_layer->setBackgroundColor(color);
+ else
+ m_layer->setBackgroundColor(Color::transparent);
+}
+
+void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth)
+{
+ if (color.isValid()) {
+ m_layer->setBorderColor(color);
+ m_layer->setBorderWidth(borderWidth);
+ } else {
+ m_layer->setBorderColor(Color::transparent);
+ m_layer->setBorderWidth(0);
+ }
+}
+
+FloatSize GraphicsLayerCA::constrainedSize() const
+{
+ float tileColumns = ceilf(m_size.width() / kTiledLayerTileSize);
+ float tileRows = ceilf(m_size.height() / kTiledLayerTileSize);
+ double numTiles = tileColumns * tileRows;
+
+ FloatSize constrainedSize = m_size;
+ const unsigned cMaxTileCount = 512;
+ while (numTiles > cMaxTileCount) {
+ // Constrain the wider dimension.
+ if (constrainedSize.width() >= constrainedSize.height()) {
+ tileColumns = max(floorf(cMaxTileCount / tileRows), 1.0f);
+ constrainedSize.setWidth(tileColumns * kTiledLayerTileSize);
+ } else {
+ tileRows = max(floorf(cMaxTileCount / tileColumns), 1.0f);
+ constrainedSize.setHeight(tileRows * kTiledLayerTileSize);
+ }
+ numTiles = tileColumns * tileRows;
+ }
+
+ return constrainedSize;
+}
+
+bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
+{
+ if (!m_drawsContent)
+ return false;
+
+ // FIXME: catch zero-size height or width here (or earlier)?
+ return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension;
+}
+
+void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
+{
+ if (useTiledLayer == m_usingTiledLayer)
+ return;
+
+ RefPtr<PlatformCALayer> oldLayer = m_layer;
+
+ m_layer = PlatformCALayer::create(useTiledLayer ? PlatformCALayer::LayerTypeWebTiledLayer : PlatformCALayer::LayerTypeWebLayer, this);
+
+ m_usingTiledLayer = useTiledLayer;
+
+ if (useTiledLayer) {
+#if !HAVE_MODERN_QUARTZCORE
+ // Tiled layer has issues with flipped coordinates.
+ setContentsOrientation(CompositingCoordinatesTopDown);
+#endif
+ } else {
+#if !HAVE_MODERN_QUARTZCORE
+ setContentsOrientation(GraphicsLayerCA::defaultContentsOrientation());
+#endif
+ }
+
+ m_layer->adoptSublayers(oldLayer.get());
+
+ oldLayer->superlayer()->replaceSublayer(oldLayer.get(), m_layer.get());
+
+ updateContentsTransform();
+
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+ updateMasksToBounds();
+ updateContentsOpaque();
+ updateBackfaceVisibility();
+ updateLayerBackgroundColor();
+
+ updateOpacityOnLayer();
+
+#ifndef NDEBUG
+ String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name;
+ m_layer->setName(name);
+#endif
+
+ // move over animations
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get());
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, oldLayer.get(), m_layer.get());
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get());
+
+ // need to tell new layer to draw itself
+ setNeedsDisplay();
+
+ updateDebugIndicators();
+}
+
+GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCA::defaultContentsOrientation() const
+{
+#if !HAVE_MODERN_QUARTZCORE
+ // Older QuartzCore does not support -geometryFlipped, so we manually flip the root
+ // layer geometry, and then flip the contents of each layer back so that the CTM for CG
+ // is unflipped, allowing it to do the correct font auto-hinting.
+ return CompositingCoordinatesBottomUp;
+#else
+ return CompositingCoordinatesTopDown;
+#endif
+}
+
+void GraphicsLayerCA::updateContentsTransform()
+{
+#if !HAVE_MODERN_QUARTZCORE
+ if (contentsOrientation() == CompositingCoordinatesBottomUp) {
+ CGAffineTransform contentsTransform = CGAffineTransformMakeScale(1, -1);
+ contentsTransform = CGAffineTransformTranslate(contentsTransform, 0, -m_layer->bounds().size().height());
+ m_layer->setContentsTransform(TransformationMatrix(contentsTransform));
+ }
+#endif
+}
+
+void GraphicsLayerCA::setupContentsLayer(PlatformCALayer* contentsLayer)
+{
+ // Turn off implicit animations on the inner layer.
+ contentsLayer->setMasksToBounds(true);
+
+ if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) {
+ TransformationMatrix flipper(
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+ contentsLayer->setTransform(flipper);
+ contentsLayer->setAnchorPoint(FloatPoint3D(0, 1, 0));
+ } else
+ contentsLayer->setAnchorPoint(FloatPoint3D());
+
+ if (showDebugBorders()) {
+ contentsLayer->setBorderColor(Color(0, 0, 128, 180));
+ contentsLayer->setBorderWidth(1.0f);
+ }
+}
+
+PassRefPtr<PlatformCALayer> GraphicsLayerCA::findOrMakeClone(CloneID cloneID, PlatformCALayer *sourceLayer, LayerMap* clones, CloneLevel cloneLevel)
+{
+ if (!sourceLayer)
+ return 0;
+
+ RefPtr<PlatformCALayer> resultLayer;
+
+ // Add with a dummy value to get an iterator for the insertion position, and a boolean that tells
+ // us whether there's an item there. This technique avoids two hash lookups.
+ RefPtr<PlatformCALayer> dummy;
+ pair<LayerMap::iterator, bool> addResult = clones->add(cloneID, dummy);
+ if (!addResult.second) {
+ // Value was not added, so it exists already.
+ resultLayer = addResult.first->second.get();
+ } else {
+ resultLayer = cloneLayer(sourceLayer, cloneLevel);
+#ifndef NDEBUG
+ resultLayer->setName(String::format("Clone %d of layer %p", cloneID[0U], sourceLayer));
+#endif
+ addResult.first->second = resultLayer;
+ }
+
+ return resultLayer;
+}
+
+void GraphicsLayerCA::ensureCloneLayers(CloneID cloneID, RefPtr<PlatformCALayer>& primaryLayer, RefPtr<PlatformCALayer>& structuralLayer, RefPtr<PlatformCALayer>& contentsLayer, CloneLevel cloneLevel)
+{
+ structuralLayer = 0;
+ contentsLayer = 0;
+
+ if (!m_layerClones)
+ m_layerClones = new LayerMap;
+
+ if (!m_structuralLayerClones && m_structuralLayer)
+ m_structuralLayerClones = new LayerMap;
+
+ if (!m_contentsLayerClones && m_contentsLayer)
+ m_contentsLayerClones = new LayerMap;
+
+ primaryLayer = findOrMakeClone(cloneID, m_layer.get(), m_layerClones.get(), cloneLevel);
+ structuralLayer = findOrMakeClone(cloneID, m_structuralLayer.get(), m_structuralLayerClones.get(), cloneLevel);
+ contentsLayer = findOrMakeClone(cloneID, m_contentsLayer.get(), m_contentsLayerClones.get(), cloneLevel);
+}
+
+void GraphicsLayerCA::removeCloneLayers()
+{
+ m_layerClones = 0;
+ m_structuralLayerClones = 0;
+ m_contentsLayerClones = 0;
+}
+
+FloatPoint GraphicsLayerCA::positionForCloneRootLayer() const
+{
+ // This can get called during a sync when we've just removed the m_replicaLayer.
+ if (!m_replicaLayer)
+ return FloatPoint();
+
+ FloatPoint replicaPosition = m_replicaLayer->replicatedLayerPosition();
+ return FloatPoint(replicaPosition.x() + m_anchorPoint.x() * m_size.width(),
+ replicaPosition.y() + m_anchorPoint.y() * m_size.height());
+}
+
+void GraphicsLayerCA::propagateLayerChangeToReplicas()
+{
+ for (GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) {
+ GraphicsLayerCA* currLayerCA = static_cast<GraphicsLayerCA*>(currLayer);
+ if (!currLayerCA->hasCloneLayers())
+ break;
+
+ if (currLayerCA->replicaLayer())
+ static_cast<GraphicsLayerCA*>(currLayerCA->replicaLayer())->noteLayerPropertyChanged(ReplicatedLayerChanged);
+ }
+}
+
+PassRefPtr<PlatformCALayer> GraphicsLayerCA::fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState& replicaState, CloneLevel cloneLevel)
+{
+ RefPtr<PlatformCALayer> primaryLayer;
+ RefPtr<PlatformCALayer> structuralLayer;
+ RefPtr<PlatformCALayer> contentsLayer;
+ ensureCloneLayers(replicaState.cloneID(), primaryLayer, structuralLayer, contentsLayer, cloneLevel);
+
+ if (m_maskLayer) {
+ RefPtr<PlatformCALayer> maskClone = static_cast<GraphicsLayerCA*>(m_maskLayer)->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
+ primaryLayer->setMask(maskClone.get());
+ }
+
+ if (m_replicatedLayer) {
+ // We are a replica being asked for clones of our layers.
+ RefPtr<PlatformCALayer> replicaRoot = replicatedLayerRoot(replicaState);
+ if (!replicaRoot)
+ return 0;
+
+ if (structuralLayer) {
+ structuralLayer->insertSublayer(replicaRoot.get(), 0);
+ return structuralLayer;
+ }
+
+ primaryLayer->insertSublayer(replicaRoot.get(), 0);
+ return primaryLayer;
+ }
+
+ const Vector<GraphicsLayer*>& childLayers = children();
+ Vector<RefPtr<PlatformCALayer> > clonalSublayers;
+
+ RefPtr<PlatformCALayer> replicaLayer;
+
+ if (m_replicaLayer && m_replicaLayer != replicaRoot) {
+ // We have nested replicas. Ask the replica layer for a clone of its contents.
+ replicaState.setBranchType(ReplicaState::ReplicaBranch);
+ replicaLayer = static_cast<GraphicsLayerCA*>(m_replicaLayer)->fetchCloneLayers(replicaRoot, replicaState, RootCloneLevel);
+ replicaState.setBranchType(ReplicaState::ChildBranch);
+ }
+
+ if (replicaLayer || structuralLayer || contentsLayer || childLayers.size() > 0) {
+ if (structuralLayer) {
+ // Replicas render behind the actual layer content.
+ if (replicaLayer)
+ clonalSublayers.append(replicaLayer);
+
+ // Add the primary layer next. Even if we have negative z-order children, the primary layer always comes behind.
+ clonalSublayers.append(primaryLayer);
+ } else if (contentsLayer) {
+ // FIXME: add the contents layer in the correct order with negative z-order children.
+ // This does not cause visible rendering issues because currently contents layers are only used
+ // for replaced elements that don't have children.
+ clonalSublayers.append(contentsLayer);
+ }
+
+ replicaState.push(ReplicaState::ChildBranch);
+
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
+
+ RefPtr<PlatformCALayer> childLayer = curChild->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
+ if (childLayer)
+ clonalSublayers.append(childLayer);
+ }
+
+ replicaState.pop();
+
+ for (size_t i = 0; i < clonalSublayers.size(); ++i)
+ clonalSublayers[i]->removeFromSuperlayer();
+ }
+
+ RefPtr<PlatformCALayer> result;
+ if (structuralLayer) {
+ structuralLayer->setSublayers(clonalSublayers);
+
+ if (contentsLayer) {
+ // If we have a transform layer, then the contents layer is parented in the
+ // primary layer (which is itself a child of the transform layer).
+ primaryLayer->removeAllSublayers();
+ primaryLayer->appendSublayer(contentsLayer.get());
+ }
+
+ result = structuralLayer;
+ } else {
+ primaryLayer->setSublayers(clonalSublayers);
+ result = primaryLayer;
+ }
+
+ return result;
+}
+
+PassRefPtr<PlatformCALayer> GraphicsLayerCA::cloneLayer(PlatformCALayer *layer, CloneLevel cloneLevel)
+{
+ PlatformCALayer::LayerType layerType = (layer->layerType() == PlatformCALayer::LayerTypeTransformLayer) ?
+ PlatformCALayer::LayerTypeTransformLayer : PlatformCALayer::LayerTypeLayer;
+ RefPtr<PlatformCALayer> newLayer = PlatformCALayer::create(layerType, this);
+
+ newLayer->setPosition(layer->position());
+ newLayer->setBounds(layer->bounds());
+ newLayer->setAnchorPoint(layer->anchorPoint());
+ newLayer->setTransform(layer->transform());
+ newLayer->setSublayerTransform(layer->sublayerTransform());
+ newLayer->setContents(layer->contents());
+ newLayer->setMasksToBounds(layer->masksToBounds());
+ newLayer->setDoubleSided(layer->isDoubleSided());
+ newLayer->setOpaque(layer->isOpaque());
+ newLayer->setBackgroundColor(layer->backgroundColor());
+
+ if (cloneLevel == IntermediateCloneLevel) {
+ newLayer->setOpacity(layer->opacity());
+ moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyWebkitTransform, layer, newLayer.get());
+ moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyOpacity, layer, newLayer.get());
+ }
+
+ if (showDebugBorders()) {
+ newLayer->setBorderColor(Color(255, 122, 251));
+ newLayer->setBorderWidth(2);
+ }
+
+ return newLayer;
+}
+
+void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity)
+{
+ LayerMap* layerCloneMap = 0;
+
+ if (preserves3D()) {
+ m_layer->setOpacity(accumulatedOpacity);
+ layerCloneMap = m_layerClones.get();
+ } else {
+ primaryLayer()->setOpacity(accumulatedOpacity);
+ layerCloneMap = primaryLayerClones();
+ }
+
+ if (layerCloneMap) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+ it->second->setOpacity(m_opacity);
+ }
+ }
+}
+
+void GraphicsLayerCA::updateOpacityOnLayer()
+{
+#if !HAVE_MODERN_QUARTZCORE
+ // Distribute opacity either to our own layer or to our children. We pass in the
+ // contribution from our parent(s).
+ distributeOpacity(parent() ? parent()->accumulatedOpacity() : 1);
+#else
+ primaryLayer()->setOpacity(m_opacity);
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+
+ it->second->setOpacity(m_opacity);
+ }
+
+ }
+#endif
+}
+
+void GraphicsLayerCA::noteSublayersChanged()
+{
+ noteLayerPropertyChanged(ChildrenChanged);
+ propagateLayerChangeToReplicas();
+}
+
+void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags)
+{
+ if (!m_uncommittedChanges && m_client)
+ m_client->notifySyncRequired(this);
+
+ m_uncommittedChanges |= flags;
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h
new file mode 100644
index 0000000..13cbdd1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 GraphicsLayerCA_h
+#define GraphicsLayerCA_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayer.h"
+#include "Image.h"
+#include "PlatformCAAnimation.h"
+#include "PlatformCALayerClient.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class PlatformCALayer;
+
+class GraphicsLayerCA : public GraphicsLayer, public PlatformCALayerClient {
+public:
+ // The width and height of a single tile in a tiled layer. Should be large enough to
+ // avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
+ // to keep the overall tile cost low.
+ static const int kTiledLayerTileSize = 512;
+
+ GraphicsLayerCA(GraphicsLayerClient*);
+ virtual ~GraphicsLayerCA();
+
+ virtual void setName(const String&);
+
+ virtual PlatformLayer* platformLayer() const;
+ virtual PlatformCALayer* platformCALayer() const { return primaryLayer(); }
+
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
+ virtual void addChild(GraphicsLayer*);
+ virtual void addChildAtIndex(GraphicsLayer*, int index);
+ virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+
+ virtual void removeFromParent();
+
+ virtual void setMaskLayer(GraphicsLayer*);
+ virtual void setReplicatedLayer(GraphicsLayer*);
+
+ virtual void setPosition(const FloatPoint&);
+ virtual void setAnchorPoint(const FloatPoint3D&);
+ virtual void setSize(const FloatSize&);
+
+ virtual void setTransform(const TransformationMatrix&);
+
+ virtual void setChildrenTransform(const TransformationMatrix&);
+
+ virtual void setPreserves3D(bool);
+ virtual void setMasksToBounds(bool);
+ virtual void setDrawsContent(bool);
+ virtual void setAcceleratesDrawing(bool);
+
+ virtual void setBackgroundColor(const Color&);
+ virtual void clearBackgroundColor();
+
+ virtual void setContentsOpaque(bool);
+ virtual void setBackfaceVisibility(bool);
+
+ // return true if we started an animation
+ virtual void setOpacity(float);
+
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+ virtual void setContentsNeedsDisplay();
+
+ virtual void setContentsRect(const IntRect&);
+
+ virtual void suspendAnimations(double time);
+ virtual void resumeAnimations();
+
+ virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& animationName, double timeOffset);
+ virtual void pauseAnimation(const String& animationName, double timeOffset);
+ virtual void removeAnimation(const String& animationName);
+
+ virtual void setContentsToImage(Image*);
+ virtual void setContentsToMedia(PlatformLayer*);
+ virtual void setContentsToCanvas(PlatformLayer*);
+
+ virtual bool hasContentsLayer() const { return m_contentsLayer; }
+
+ virtual void setDebugBackgroundColor(const Color&);
+ virtual void setDebugBorder(const Color&, float borderWidth);
+
+ virtual void layerDidDisplay(PlatformLayer*);
+
+ void recursiveCommitChanges();
+
+ virtual void syncCompositingState();
+ virtual void syncCompositingStateForThisLayerOnly();
+
+protected:
+ virtual void setOpacityInternal(float);
+
+private:
+ // PlatformCALayerClient overrides
+ virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*) { }
+ virtual bool platformCALayerRespondsToLayoutChanges() const { return false; }
+
+ virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime);
+ virtual CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return contentsOrientation(); }
+ virtual void platformCALayerPaintContents(GraphicsContext& context, const IntRect& clip) { paintGraphicsLayerContents(context, clip); }
+ virtual bool platformCALayerShowDebugBorders() const { return showDebugBorders(); }
+ virtual bool platformCALayerShowRepaintCounter() const { return showRepaintCounter(); }
+ virtual int platformCALayerIncrementRepaintCount() { return incrementRepaintCount(); }
+
+ virtual bool platformCALayerContentsOpaque() const { return contentsOpaque(); }
+ virtual bool platformCALayerDrawsContent() const { return drawsContent(); }
+ virtual void platformCALayerLayerDidDisplay(PlatformLayer* layer) { return layerDidDisplay(layer); }
+
+ void updateOpacityOnLayer();
+
+ PlatformCALayer* primaryLayer() const { return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get(); }
+ PlatformCALayer* hostLayerForSublayers() const;
+ PlatformCALayer* layerForSuperlayer() const;
+ PlatformCALayer* animatedLayer(AnimatedPropertyID) const;
+
+ typedef String CloneID; // Identifier for a given clone, based on original/replica branching down the tree.
+ static bool isReplicatedRootClone(const CloneID& cloneID) { return cloneID[0U] & 1; }
+
+ typedef HashMap<CloneID, RefPtr<PlatformCALayer> > LayerMap;
+ LayerMap* primaryLayerClones() const { return m_structuralLayer.get() ? m_structuralLayerClones.get() : m_layerClones.get(); }
+ LayerMap* animatedLayerClones(AnimatedPropertyID) const;
+
+ bool createAnimationFromKeyframes(const KeyframeValueList&, const Animation*, const String& animationName, double timeOffset);
+ bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& animationName, double timeOffset, const IntSize& boxSize);
+
+ // Return autoreleased animation (use RetainPtr?)
+ PassRefPtr<PlatformCAAnimation> createBasicAnimation(const Animation*, AnimatedPropertyID, bool additive);
+ PassRefPtr<PlatformCAAnimation> createKeyframeAnimation(const Animation*, AnimatedPropertyID, bool additive);
+ void setupAnimation(PlatformCAAnimation*, const Animation*, bool additive);
+
+ const TimingFunction* timingFunctionForAnimationValue(const AnimationValue*, const Animation*);
+
+ bool setAnimationEndpoints(const KeyframeValueList&, const Animation*, PlatformCAAnimation*);
+ bool setAnimationKeyframes(const KeyframeValueList&, const Animation*, PlatformCAAnimation*);
+
+ bool setTransformAnimationEndpoints(const KeyframeValueList&, const Animation*, PlatformCAAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize);
+ bool setTransformAnimationKeyframes(const KeyframeValueList&, const Animation*, PlatformCAAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize);
+
+ bool animationIsRunning(const String& animationName) const
+ {
+ return m_runningAnimations.find(animationName) != m_runningAnimations.end();
+ }
+
+ void commitLayerChangesBeforeSublayers();
+ void commitLayerChangesAfterSublayers();
+
+ FloatSize constrainedSize() const;
+
+ bool requiresTiledLayer(const FloatSize&) const;
+ void swapFromOrToTiledLayer(bool useTiledLayer);
+
+ CompositingCoordinatesOrientation defaultContentsOrientation() const;
+ void updateContentsTransform();
+
+ void setupContentsLayer(PlatformCALayer*);
+ PlatformCALayer* contentsLayer() const { return m_contentsLayer.get(); }
+
+ virtual void setReplicatedByLayer(GraphicsLayer*);
+
+ // Used to track the path down the tree for replica layers.
+ struct ReplicaState {
+ static const size_t maxReplicaDepth = 16;
+ enum ReplicaBranchType { ChildBranch = 0, ReplicaBranch = 1 };
+ ReplicaState(ReplicaBranchType firstBranch)
+ : m_replicaDepth(0)
+ {
+ push(firstBranch);
+ }
+
+ // Called as we walk down the tree to build replicas.
+ void push(ReplicaBranchType branchType)
+ {
+ m_replicaBranches.append(branchType);
+ if (branchType == ReplicaBranch)
+ ++m_replicaDepth;
+ }
+
+ void setBranchType(ReplicaBranchType branchType)
+ {
+ ASSERT(!m_replicaBranches.isEmpty());
+
+ if (m_replicaBranches.last() != branchType) {
+ if (branchType == ReplicaBranch)
+ ++m_replicaDepth;
+ else
+ --m_replicaDepth;
+ }
+
+ m_replicaBranches.last() = branchType;
+ }
+
+ void pop()
+ {
+ if (m_replicaBranches.last() == ReplicaBranch)
+ --m_replicaDepth;
+ m_replicaBranches.removeLast();
+ }
+
+ size_t depth() const { return m_replicaBranches.size(); }
+ size_t replicaDepth() const { return m_replicaDepth; }
+
+ CloneID cloneID() const;
+
+ private:
+ Vector<ReplicaBranchType> m_replicaBranches;
+ size_t m_replicaDepth;
+ };
+ PassRefPtr<PlatformCALayer>replicatedLayerRoot(ReplicaState&);
+
+ enum CloneLevel { RootCloneLevel, IntermediateCloneLevel };
+ PassRefPtr<PlatformCALayer> fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState&, CloneLevel);
+
+ PassRefPtr<PlatformCALayer> cloneLayer(PlatformCALayer *, CloneLevel);
+ PassRefPtr<PlatformCALayer> findOrMakeClone(CloneID, PlatformCALayer *, LayerMap*, CloneLevel);
+
+ void ensureCloneLayers(CloneID cloneID, RefPtr<PlatformCALayer>& primaryLayer, RefPtr<PlatformCALayer>& structuralLayer, RefPtr<PlatformCALayer>& contentsLayer, CloneLevel cloneLevel);
+
+ bool hasCloneLayers() const { return m_layerClones; }
+ void removeCloneLayers();
+ FloatPoint positionForCloneRootLayer() const;
+
+ void propagateLayerChangeToReplicas();
+
+ // All these "update" methods will be called inside a BEGIN_BLOCK_OBJC_EXCEPTIONS/END_BLOCK_OBJC_EXCEPTIONS block.
+ void updateLayerNames();
+ void updateSublayerList();
+ void updateLayerPosition();
+ void updateLayerSize();
+ void updateAnchorPoint();
+ void updateTransform();
+ void updateChildrenTransform();
+ void updateMasksToBounds();
+ void updateContentsOpaque();
+ void updateBackfaceVisibility();
+ void updateStructuralLayer();
+ void updateLayerDrawsContent();
+ void updateLayerBackgroundColor();
+
+ void updateContentsImage();
+ void updateContentsMediaLayer();
+ void updateContentsCanvasLayer();
+ void updateContentsRect();
+ void updateMaskLayer();
+ void updateReplicatedLayers();
+
+ void updateLayerAnimations();
+ void updateContentsNeedsDisplay();
+ void updateAcceleratesDrawing();
+
+ enum StructuralLayerPurpose {
+ NoStructuralLayer = 0,
+ StructuralLayerForPreserves3D,
+ StructuralLayerForReplicaFlattening
+ };
+ void ensureStructuralLayer(StructuralLayerPurpose);
+ StructuralLayerPurpose structuralLayerPurpose() const;
+
+ void setAnimationOnLayer(PlatformCAAnimation*, AnimatedPropertyID, const String& animationName, int index, double timeOffset);
+ bool removeCAAnimationFromLayer(AnimatedPropertyID, const String& animationName, int index);
+ void pauseCAAnimationOnLayer(AnimatedPropertyID, const String& animationName, int index, double timeOffset);
+
+ enum MoveOrCopy { Move, Copy };
+ static void moveOrCopyLayerAnimation(MoveOrCopy, const String& animationIdentifier, PlatformCALayer *fromLayer, PlatformCALayer *toLayer);
+ void moveOrCopyAnimationsForProperty(MoveOrCopy, AnimatedPropertyID, PlatformCALayer * fromLayer, PlatformCALayer * toLayer);
+
+ enum LayerChange {
+ NoChange = 0,
+ NameChanged = 1 << 1,
+ ChildrenChanged = 1 << 2, // also used for content layer, and preserves-3d, and size if tiling changes?
+ PositionChanged = 1 << 3,
+ AnchorPointChanged = 1 << 4,
+ SizeChanged = 1 << 5,
+ TransformChanged = 1 << 6,
+ ChildrenTransformChanged = 1 << 7,
+ Preserves3DChanged = 1 << 8,
+ MasksToBoundsChanged = 1 << 9,
+ DrawsContentChanged = 1 << 10, // need this?
+ BackgroundColorChanged = 1 << 11,
+ ContentsOpaqueChanged = 1 << 12,
+ BackfaceVisibilityChanged = 1 << 13,
+ OpacityChanged = 1 << 14,
+ AnimationChanged = 1 << 15,
+ DirtyRectsChanged = 1 << 16,
+ ContentsImageChanged = 1 << 17,
+ ContentsMediaLayerChanged = 1 << 18,
+ ContentsCanvasLayerChanged = 1 << 19,
+ ContentsRectChanged = 1 << 20,
+ MaskLayerChanged = 1 << 21,
+ ReplicatedLayerChanged = 1 << 22,
+ ContentsNeedsDisplay = 1 << 23,
+ AcceleratesDrawingChanged = 1 << 24
+ };
+ typedef unsigned LayerChangeFlags;
+ void noteLayerPropertyChanged(LayerChangeFlags flags);
+ void noteSublayersChanged();
+
+ void repaintLayerDirtyRects();
+
+ RefPtr<PlatformCALayer> m_layer; // The main layer
+ RefPtr<PlatformCALayer> m_structuralLayer; // A layer used for structural reasons, like preserves-3d or replica-flattening. Is the parent of m_layer.
+ RefPtr<PlatformCALayer> m_contentsLayer; // A layer used for inner content, like image and video
+
+ // References to clones of our layers, for replicated layers.
+ OwnPtr<LayerMap> m_layerClones;
+ OwnPtr<LayerMap> m_structuralLayerClones;
+ OwnPtr<LayerMap> m_contentsLayerClones;
+
+ enum ContentsLayerPurpose {
+ NoContentsLayer = 0,
+ ContentsLayerForImage,
+ ContentsLayerForMedia,
+ ContentsLayerForCanvas
+ };
+
+ ContentsLayerPurpose m_contentsLayerPurpose;
+ bool m_contentsLayerHasBackgroundColor : 1;
+
+ RetainPtr<CGImageRef> m_uncorrectedContentsImage;
+ RetainPtr<CGImageRef> m_pendingContentsImage;
+
+ // This represents the animation of a single property. There may be multiple transform animations for
+ // a single transition or keyframe animation, so index is used to distinguish these.
+ struct LayerPropertyAnimation {
+ LayerPropertyAnimation(PassRefPtr<PlatformCAAnimation> caAnimation, const String& animationName, AnimatedPropertyID property, int index, double timeOffset)
+ : m_animation(caAnimation)
+ , m_name(animationName)
+ , m_property(property)
+ , m_index(index)
+ , m_timeOffset(timeOffset)
+ { }
+
+ RefPtr<PlatformCAAnimation> m_animation;
+ String m_name;
+ AnimatedPropertyID m_property;
+ int m_index;
+ double m_timeOffset;
+ };
+
+ // Uncommitted transitions and animations.
+ Vector<LayerPropertyAnimation> m_uncomittedAnimations;
+
+ enum Action { Remove, Pause };
+ struct AnimationProcessingAction {
+ AnimationProcessingAction(Action action = Remove, double timeOffset = 0)
+ : action(action)
+ , timeOffset(timeOffset)
+ {
+ }
+ Action action;
+ double timeOffset; // only used for pause
+ };
+ typedef HashMap<String, AnimationProcessingAction> AnimationsToProcessMap;
+ AnimationsToProcessMap m_animationsToProcess;
+
+ // Map of animation names to their associated lists of property animations, so we can remove/pause them.
+ typedef HashMap<String, Vector<LayerPropertyAnimation> > AnimationsMap;
+ AnimationsMap m_runningAnimations;
+
+ Vector<FloatRect> m_dirtyRects;
+
+ LayerChangeFlags m_uncommittedChanges;
+};
+
+} // namespace WebCore
+
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayerCA_h
diff --git a/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h b/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h
new file mode 100644
index 0000000..4bfce63
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 PlatformCAAnimation_h
+#define PlatformCAAnimation_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Color.h"
+#include "FloatPoint3D.h"
+#include "TransformationMatrix.h"
+#include <wtf/RefCounted.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+@class CAPropertyAnimation;
+typedef CAPropertyAnimation* PlatformAnimationRef;
+#else
+typedef void* CAPropertyAnimation; // So the m_animation declaration works
+typedef void* PlatformAnimationRef;
+#endif
+#elif PLATFORM(WIN)
+typedef struct _CACFAnimation* CACFAnimationRef;
+typedef CACFAnimationRef PlatformAnimationRef;
+#endif
+
+namespace WebCore {
+
+class FloatRect;
+class PlatformCAAnimation;
+class TimingFunction;
+
+class PlatformCAAnimation : public RefCounted<PlatformCAAnimation> {
+public:
+ friend class PlatformCALayer;
+
+ enum AnimationType { Basic, Keyframe };
+ enum FillModeType { NoFillMode, Forwards, Backwards, Both };
+ enum ValueFunctionType { NoValueFunction, RotateX, RotateY, RotateZ, ScaleX, ScaleY, ScaleZ, Scale, TranslateX, TranslateY, TranslateZ, Translate };
+
+ static PassRefPtr<PlatformCAAnimation> create(AnimationType, const String& keyPath);
+ static PassRefPtr<PlatformCAAnimation> create(PlatformAnimationRef animation);
+ static PassRefPtr<PlatformCAAnimation> create(const PlatformCAAnimation* animation);
+
+ ~PlatformCAAnimation();
+
+ static bool supportsValueFunction();
+
+ PlatformAnimationRef platformAnimation() const;
+
+ AnimationType animationType() const { return m_type; }
+ String keyPath() const;
+
+ CFTimeInterval beginTime() const;
+ void setBeginTime(CFTimeInterval);
+
+ CFTimeInterval duration() const;
+ void setDuration(CFTimeInterval);
+
+ float speed() const;
+ void setSpeed(float);
+
+ CFTimeInterval timeOffset() const;
+ void setTimeOffset(CFTimeInterval);
+
+ float repeatCount() const;
+ void setRepeatCount(float);
+
+ bool autoreverses() const;
+ void setAutoreverses(bool);
+
+ FillModeType fillMode() const;
+ void setFillMode(FillModeType);
+
+ void setTimingFunction(const TimingFunction*);
+ void copyTimingFunctionFrom(const PlatformCAAnimation*);
+
+ bool isRemovedOnCompletion() const;
+ void setRemovedOnCompletion(bool);
+
+ bool isAdditive() const;
+ void setAdditive(bool);
+
+ ValueFunctionType valueFunction() const;
+ void setValueFunction(ValueFunctionType);
+
+ // Basic-animation properties.
+ void setFromValue(float);
+ void setFromValue(const WebCore::TransformationMatrix&);
+ void setFromValue(const FloatPoint3D&);
+ void setFromValue(const WebCore::Color&);
+ void copyFromValueFrom(const PlatformCAAnimation*);
+
+ void setToValue(float);
+ void setToValue(const WebCore::TransformationMatrix&);
+ void setToValue(const FloatPoint3D&);
+ void setToValue(const WebCore::Color&);
+ void copyToValueFrom(const PlatformCAAnimation*);
+
+ // Keyframe-animation properties.
+ void setValues(const Vector<float>&);
+ void setValues(const Vector<WebCore::TransformationMatrix>&);
+ void setValues(const Vector<FloatPoint3D>&);
+ void setValues(const Vector<WebCore::Color>&);
+ void copyValuesFrom(const PlatformCAAnimation*);
+
+ void setKeyTimes(const Vector<float>&);
+ void copyKeyTimesFrom(const PlatformCAAnimation*);
+
+ void setTimingFunctions(const Vector<const TimingFunction*>&);
+ void copyTimingFunctionsFrom(const PlatformCAAnimation*);
+
+protected:
+ PlatformCAAnimation(AnimationType, const String& keyPath);
+ PlatformCAAnimation(PlatformAnimationRef animation);
+ PlatformCAAnimation(const PlatformCAAnimation* animation);
+
+private:
+ AnimationType m_type;
+
+#if PLATFORM(MAC)
+ RetainPtr<CAPropertyAnimation> m_animation;
+#elif PLATFORM(WIN)
+ RetainPtr<CACFAnimationRef> m_animation;
+#endif
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // PlatformCAAnimation_h
diff --git a/Source/WebCore/platform/graphics/ca/PlatformCALayer.h b/Source/WebCore/platform/graphics/ca/PlatformCALayer.h
new file mode 100644
index 0000000..46f4bbf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/PlatformCALayer.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 PlatformCALayer_h
+#define PlatformCALayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsContext.h"
+#include "PlatformCAAnimation.h"
+#include "PlatformCALayerClient.h"
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class PlatformCALayer;
+
+typedef Vector<RefPtr<PlatformCALayer> > PlatformCALayerList;
+
+class PlatformCALayer : public RefCounted<PlatformCALayer> {
+public:
+ // LayerTypeRootLayer is used on some platforms. It has no backing store, so setNeedsDisplay
+ // should not call CACFLayerSetNeedsDisplay, but rather just notify the renderer that it
+ // has changed and should be re-rendered.
+ enum LayerType { LayerTypeLayer, LayerTypeWebLayer, LayerTypeTransformLayer, LayerTypeWebTiledLayer, LayerTypeRootLayer, LayerTypeCustom };
+ enum FilterType { Linear, Nearest, Trilinear };
+
+ static PassRefPtr<PlatformCALayer> create(LayerType, PlatformCALayerClient*);
+
+ // This function passes the layer as a void* rather than a PlatformLayer because PlatformLayer
+ // is defined differently for Obj C and C++. This allows callers from both languages.
+ static PassRefPtr<PlatformCALayer> create(void* platformLayer, PlatformCALayerClient*);
+
+ ~PlatformCALayer();
+
+ // This function passes the layer as a void* rather than a PlatformLayer because PlatformLayer
+ // is defined differently for Obj C and C++. This allows callers from both languages.
+ static PlatformCALayer* platformCALayer(void* platformLayer);
+
+ PlatformLayer* platformLayer() const;
+
+ PlatformCALayer* rootLayer() const;
+
+ static bool isValueFunctionSupported();
+
+ PlatformCALayerClient* owner() const { return m_owner; }
+ void setOwner(PlatformCALayerClient*);
+
+ void animationStarted(CFTimeInterval beginTime)
+ {
+ if (m_owner)
+ m_owner->platformCALayerAnimationStarted(beginTime);
+ }
+
+ // Layout support
+ void setNeedsLayout();
+
+
+ void setNeedsDisplay(const FloatRect* dirtyRect = 0);
+
+ // This tells the layer tree to commit changes and perform a render, without do a setNeedsDisplay on any layer.
+ void setNeedsCommit();
+
+ void setContentsChanged();
+
+ LayerType layerType() const { return m_layerType; }
+
+ PlatformCALayer* superlayer() const;
+ void removeFromSuperlayer();
+ void setSublayers(const PlatformCALayerList&);
+ void removeAllSublayers();
+ void appendSublayer(PlatformCALayer*);
+ void insertSublayer(PlatformCALayer*, size_t index);
+ void replaceSublayer(PlatformCALayer* reference, PlatformCALayer*);
+ size_t sublayerCount() const;
+
+ // This method removes the sublayers from the source and reparents them to the current layer.
+ // Any sublayers previously in the current layer are removed.
+ void adoptSublayers(PlatformCALayer* source);
+
+ void addAnimationForKey(const String& key, PlatformCAAnimation* animation);
+ void removeAnimationForKey(const String& key);
+ PassRefPtr<PlatformCAAnimation> animationForKey(const String& key);
+
+ PlatformCALayer* mask() const;
+ void setMask(PlatformCALayer*);
+
+ bool isOpaque() const;
+ void setOpaque(bool);
+
+ FloatRect bounds() const;
+ void setBounds(const FloatRect&);
+
+ FloatPoint3D position() const;
+ void setPosition(const FloatPoint3D&);
+ void setPosition(const FloatPoint& pos) { setPosition(FloatPoint3D(pos.x(), pos.y(), 0)); }
+
+ FloatPoint3D anchorPoint() const;
+ void setAnchorPoint(const FloatPoint3D&);
+
+ TransformationMatrix transform() const;
+ void setTransform(const TransformationMatrix&);
+
+ TransformationMatrix sublayerTransform() const;
+ void setSublayerTransform(const TransformationMatrix&);
+
+ TransformationMatrix contentsTransform() const;
+ void setContentsTransform(const TransformationMatrix&);
+
+ bool isHidden() const;
+ void setHidden(bool);
+
+ bool isGeometryFlipped() const;
+ void setGeometryFlipped(bool);
+
+ bool isDoubleSided() const;
+ void setDoubleSided(bool);
+
+ bool masksToBounds() const;
+ void setMasksToBounds(bool);
+
+ bool acceleratesDrawing() const;
+ void setAcceleratesDrawing(bool);
+
+ CFTypeRef contents() const;
+ void setContents(CFTypeRef);
+
+ FloatRect contentsRect() const;
+ void setContentsRect(const FloatRect&);
+
+ void setMinificationFilter(FilterType);
+ void setMagnificationFilter(FilterType);
+
+ Color backgroundColor() const;
+ void setBackgroundColor(const Color&);
+
+ float borderWidth() const;
+ void setBorderWidth(float);
+
+ Color borderColor() const;
+ void setBorderColor(const Color&);
+
+ float opacity() const;
+ void setOpacity(float);
+
+ String name() const;
+ void setName(const String&);
+
+ FloatRect frame() const;
+ void setFrame(const FloatRect&);
+
+ float speed() const;
+ void setSpeed(float);
+
+ CFTimeInterval timeOffset() const;
+ void setTimeOffset(CFTimeInterval);
+
+#if PLATFORM(WIN) && !defined(NDEBUG)
+ void printTree() const;
+#endif
+
+protected:
+ PlatformCALayer(LayerType, PlatformLayer*, PlatformCALayerClient*);
+
+private:
+ PlatformCALayerClient* m_owner;
+ LayerType m_layerType;
+
+#if PLATFORM(MAC) || PLATFORM(WIN)
+ RetainPtr<PlatformLayer> m_layer;
+#endif
+
+#if PLATFORM(WIN)
+ HashMap<String, RefPtr<PlatformCAAnimation> > m_animations;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+ RetainPtr<NSObject> m_delegate;
+#else
+ RetainPtr<void> m_delegate;
+#endif
+#endif
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // PlatformCALayer_h
diff --git a/Source/WebCore/platform/graphics/ca/PlatformCALayerClient.h b/Source/WebCore/platform/graphics/ca/PlatformCALayerClient.h
new file mode 100644
index 0000000..ae1815c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/PlatformCALayerClient.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 PlatformCALayerClient_h
+#define PlatformCALayerClient_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsContext.h"
+#include "GraphicsLayer.h"
+#include "PlatformCAAnimation.h"
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class PlatformCALayer;
+
+class PlatformCALayerClient {
+public:
+ virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*) = 0;
+ virtual bool platformCALayerRespondsToLayoutChanges() const = 0;
+
+ virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime) = 0;
+ virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const = 0;
+ virtual void platformCALayerPaintContents(GraphicsContext&, const IntRect& inClip) = 0;
+ virtual bool platformCALayerShowDebugBorders() const = 0;
+ virtual bool platformCALayerShowRepaintCounter() const = 0;
+ virtual int platformCALayerIncrementRepaintCount() = 0;
+
+ virtual bool platformCALayerContentsOpaque() const = 0;
+ virtual bool platformCALayerDrawsContent() const = 0;
+ virtual void platformCALayerLayerDidDisplay(PlatformLayer*) = 0;
+
+protected:
+ virtual ~PlatformCALayerClient() {}
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // PlatformCALayerClient_h
diff --git a/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp b/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp
new file mode 100644
index 0000000..27805e6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if PLATFORM(CA)
+
+#include "TransformationMatrix.h"
+
+#include "FloatConversion.h"
+
+namespace WebCore {
+
+TransformationMatrix::TransformationMatrix(const CATransform3D& t)
+{
+ setMatrix(
+ t.m11, t.m12, t.m13, t.m14,
+ t.m21, t.m22, t.m23, t.m24,
+ t.m31, t.m32, t.m33, t.m34,
+ t.m41, t.m42, t.m43, t.m44);
+}
+
+TransformationMatrix::operator CATransform3D() const
+{
+ CATransform3D toT3D;
+ toT3D.m11 = narrowPrecisionToFloat(m11());
+ toT3D.m12 = narrowPrecisionToFloat(m12());
+ toT3D.m13 = narrowPrecisionToFloat(m13());
+ toT3D.m14 = narrowPrecisionToFloat(m14());
+ toT3D.m21 = narrowPrecisionToFloat(m21());
+ toT3D.m22 = narrowPrecisionToFloat(m22());
+ toT3D.m23 = narrowPrecisionToFloat(m23());
+ toT3D.m24 = narrowPrecisionToFloat(m24());
+ toT3D.m31 = narrowPrecisionToFloat(m31());
+ toT3D.m32 = narrowPrecisionToFloat(m32());
+ toT3D.m33 = narrowPrecisionToFloat(m33());
+ toT3D.m34 = narrowPrecisionToFloat(m34());
+ toT3D.m41 = narrowPrecisionToFloat(m41());
+ toT3D.m42 = narrowPrecisionToFloat(m42());
+ toT3D.m43 = narrowPrecisionToFloat(m43());
+ toT3D.m44 = narrowPrecisionToFloat(m44());
+ return toT3D;
+}
+
+}
+
+#endif // PLATFORM(CA)
diff --git a/Source/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm b/Source/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm
new file mode 100644
index 0000000..2a00857
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "PlatformCAAnimation.h"
+
+#import "FloatConversion.h"
+#import "PlatformString.h"
+#import "TimingFunction.h"
+#import <QuartzCore/QuartzCore.h>
+#import <wtf/UnusedParam.h>
+
+#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
+
+using namespace WebCore;
+
+// This value must be the same as in PlatformCALayerMac.mm
+static NSString * const WKNonZeroBeginTimeFlag = @"WKPlatformCAAnimationNonZeroBeginTimeFlag";
+
+static bool hasNonZeroBeginTimeFlag(const PlatformCAAnimation* animation)
+{
+ return [[animation->platformAnimation() valueForKey:WKNonZeroBeginTimeFlag] boolValue];
+}
+
+static void setNonZeroBeginTimeFlag(PlatformCAAnimation* animation, bool value)
+{
+ [animation->platformAnimation() setValue:[NSNumber numberWithBool:value] forKey:WKNonZeroBeginTimeFlag];
+}
+
+static NSString* toCAFillModeType(PlatformCAAnimation::FillModeType type)
+{
+ switch (type) {
+ case PlatformCAAnimation::NoFillMode:
+ case PlatformCAAnimation::Forwards: return kCAFillModeForwards;
+ case PlatformCAAnimation::Backwards: return kCAFillModeBackwards;
+ case PlatformCAAnimation::Both: return kCAFillModeBoth;
+ }
+ return @"";
+}
+
+static PlatformCAAnimation::FillModeType fromCAFillModeType(NSString* string)
+{
+ if ([string isEqualToString:kCAFillModeBackwards])
+ return PlatformCAAnimation::Backwards;
+
+ if ([string isEqualToString:kCAFillModeBoth])
+ return PlatformCAAnimation::Both;
+
+ return PlatformCAAnimation::Forwards;
+}
+
+#if HAVE_MODERN_QUARTZCORE
+static NSString* toCAValueFunctionType(PlatformCAAnimation::ValueFunctionType type)
+{
+ switch (type) {
+ case PlatformCAAnimation::NoValueFunction: return @"";
+ case PlatformCAAnimation::RotateX: return kCAValueFunctionRotateX;
+ case PlatformCAAnimation::RotateY: return kCAValueFunctionRotateY;
+ case PlatformCAAnimation::RotateZ: return kCAValueFunctionRotateZ;
+ case PlatformCAAnimation::ScaleX: return kCAValueFunctionScaleX;
+ case PlatformCAAnimation::ScaleY: return kCAValueFunctionScaleY;
+ case PlatformCAAnimation::ScaleZ: return kCAValueFunctionScaleZ;
+ case PlatformCAAnimation::Scale: return kCAValueFunctionScale;
+ case PlatformCAAnimation::TranslateX: return kCAValueFunctionTranslateX;
+ case PlatformCAAnimation::TranslateY: return kCAValueFunctionTranslateY;
+ case PlatformCAAnimation::TranslateZ: return kCAValueFunctionTranslateZ;
+ case PlatformCAAnimation::Translate: return kCAValueFunctionTranslate;
+ }
+ return @"";
+}
+
+static PlatformCAAnimation::ValueFunctionType fromCAValueFunctionType(NSString* string)
+{
+ if ([string isEqualToString:kCAValueFunctionRotateX])
+ return PlatformCAAnimation::RotateX;
+
+ if ([string isEqualToString:kCAValueFunctionRotateY])
+ return PlatformCAAnimation::RotateY;
+
+ if ([string isEqualToString:kCAValueFunctionRotateZ])
+ return PlatformCAAnimation::RotateZ;
+
+ if ([string isEqualToString:kCAValueFunctionScaleX])
+ return PlatformCAAnimation::ScaleX;
+
+ if ([string isEqualToString:kCAValueFunctionScaleY])
+ return PlatformCAAnimation::ScaleY;
+
+ if ([string isEqualToString:kCAValueFunctionScaleZ])
+ return PlatformCAAnimation::ScaleZ;
+
+ if ([string isEqualToString:kCAValueFunctionScale])
+ return PlatformCAAnimation::Scale;
+
+ if ([string isEqualToString:kCAValueFunctionTranslateX])
+ return PlatformCAAnimation::TranslateX;
+
+ if ([string isEqualToString:kCAValueFunctionTranslateY])
+ return PlatformCAAnimation::TranslateY;
+
+ if ([string isEqualToString:kCAValueFunctionTranslateZ])
+ return PlatformCAAnimation::TranslateZ;
+
+ if ([string isEqualToString:kCAValueFunctionTranslate])
+ return PlatformCAAnimation::Translate;
+
+ return PlatformCAAnimation::NoValueFunction;
+}
+#endif
+
+static CAMediaTimingFunction* toCAMediaTimingFunction(const TimingFunction* timingFunction)
+{
+ if (!timingFunction)
+ return [CAMediaTimingFunction functionWithControlPoints:0.25f :0.1f :0.25f :0.1f];
+
+ if (timingFunction->isCubicBezierTimingFunction()) {
+ const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction);
+ return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(ctf->x1()) :static_cast<float>(ctf->y1())
+ :static_cast<float>(ctf->x2()) :static_cast<float>(ctf->y2())];
+ }
+
+ return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
+
+ return 0;
+}
+
+PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(AnimationType type, const String& keyPath)
+{
+ return adoptRef(new PlatformCAAnimation(type, keyPath));
+}
+
+PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef animation)
+{
+ return adoptRef(new PlatformCAAnimation(animation));
+}
+
+PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(const PlatformCAAnimation* animation)
+{
+ return adoptRef(new PlatformCAAnimation(animation));
+}
+
+PlatformCAAnimation::PlatformCAAnimation(AnimationType type, const String& keyPath)
+ : m_type(type)
+{
+ if (type == Basic)
+ m_animation.adoptNS([[CABasicAnimation animationWithKeyPath:keyPath] retain]);
+ else
+ m_animation.adoptNS([[CAKeyframeAnimation animationWithKeyPath:keyPath] retain]);
+}
+
+PlatformCAAnimation::PlatformCAAnimation(PlatformAnimationRef animation)
+{
+ if ([static_cast<CAAnimation*>(animation) isKindOfClass:[CABasicAnimation class]])
+ m_type = Basic;
+ else if ([static_cast<CAAnimation*>(animation) isKindOfClass:[CAKeyframeAnimation class]])
+ m_type = Keyframe;
+ else {
+ ASSERT(0);
+ return;
+ }
+
+ m_animation = static_cast<CAPropertyAnimation*>(animation);
+}
+
+PlatformCAAnimation::PlatformCAAnimation(const PlatformCAAnimation* animation)
+{
+ PlatformCAAnimation* newAnimation = new PlatformCAAnimation(animation->animationType(), animation->keyPath());
+
+ newAnimation->setBeginTime(animation->beginTime());
+ newAnimation->setDuration(animation->duration());
+ newAnimation->setSpeed(animation->speed());
+ newAnimation->setTimeOffset(animation->timeOffset());
+ newAnimation->setRepeatCount(animation->repeatCount());
+ newAnimation->setAutoreverses(animation->autoreverses());
+ newAnimation->setFillMode(animation->fillMode());
+ newAnimation->setRemovedOnCompletion(animation->isRemovedOnCompletion());
+ newAnimation->setAdditive(animation->isAdditive());
+ newAnimation->copyTimingFunctionFrom(animation);
+
+#if HAVE_MODERN_QUARTZCORE
+ newAnimation->setValueFunction(animation->valueFunction());
+#endif
+
+ setNonZeroBeginTimeFlag(newAnimation, hasNonZeroBeginTimeFlag(animation));
+
+ // Copy the specific Basic or Keyframe values
+ if (animation->animationType() == Keyframe) {
+ newAnimation->copyValuesFrom(animation);
+ newAnimation->copyKeyTimesFrom(animation);
+ newAnimation->copyTimingFunctionsFrom(animation);
+ } else {
+ newAnimation->copyFromValueFrom(animation);
+ newAnimation->copyToValueFrom(animation);
+ }
+}
+
+PlatformCAAnimation::~PlatformCAAnimation()
+{
+}
+
+bool PlatformCAAnimation::supportsValueFunction()
+{
+ static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)];
+ return sHaveValueFunction;
+}
+
+PlatformAnimationRef PlatformCAAnimation::platformAnimation() const
+{
+ return m_animation.get();
+}
+
+String PlatformCAAnimation::keyPath() const
+{
+ return [m_animation.get() keyPath];
+}
+
+CFTimeInterval PlatformCAAnimation::beginTime() const
+{
+ return [m_animation.get() beginTime];
+}
+
+void PlatformCAAnimation::setBeginTime(CFTimeInterval value)
+{
+ [m_animation.get() setBeginTime:value];
+
+ // Also set a flag to tell us if we've passed in a 0 value.
+ // The flag is needed because later beginTime will get changed
+ // to the time at which it fired and we need to know whether
+ // or not it was 0 to begin with.
+ if (value)
+ setNonZeroBeginTimeFlag(this, true);
+}
+
+CFTimeInterval PlatformCAAnimation::duration() const
+{
+ return [m_animation.get() duration];
+}
+
+void PlatformCAAnimation::setDuration(CFTimeInterval value)
+{
+ [m_animation.get() setDuration:value];
+}
+
+float PlatformCAAnimation::speed() const
+{
+ return [m_animation.get() speed];
+}
+
+void PlatformCAAnimation::setSpeed(float value)
+{
+ [m_animation.get() setSpeed:value];
+}
+
+CFTimeInterval PlatformCAAnimation::timeOffset() const
+{
+ return [m_animation.get() timeOffset];
+}
+
+void PlatformCAAnimation::setTimeOffset(CFTimeInterval value)
+{
+ [m_animation.get() setTimeOffset:value];
+}
+
+float PlatformCAAnimation::repeatCount() const
+{
+ return [m_animation.get() repeatCount];
+}
+
+void PlatformCAAnimation::setRepeatCount(float value)
+{
+ [m_animation.get() setRepeatCount:value];
+}
+
+bool PlatformCAAnimation::autoreverses() const
+{
+ return [m_animation.get() autoreverses];
+}
+
+void PlatformCAAnimation::setAutoreverses(bool value)
+{
+ [m_animation.get() setAutoreverses:value];
+}
+
+PlatformCAAnimation::FillModeType PlatformCAAnimation::fillMode() const
+{
+ return fromCAFillModeType([m_animation.get() fillMode]);
+}
+
+void PlatformCAAnimation::setFillMode(FillModeType value)
+{
+ [m_animation.get() setFillMode:toCAFillModeType(value)];
+}
+
+void PlatformCAAnimation::setTimingFunction(const TimingFunction* value)
+{
+ [m_animation.get() setTimingFunction:toCAMediaTimingFunction(value)];
+}
+
+void PlatformCAAnimation::copyTimingFunctionFrom(const PlatformCAAnimation* value)
+{
+ [m_animation.get() setTimingFunction:[value->m_animation.get() timingFunction]];
+}
+
+bool PlatformCAAnimation::isRemovedOnCompletion() const
+{
+ return [m_animation.get() isRemovedOnCompletion];
+}
+
+void PlatformCAAnimation::setRemovedOnCompletion(bool value)
+{
+ [m_animation.get() setRemovedOnCompletion:value];
+}
+
+bool PlatformCAAnimation::isAdditive() const
+{
+ return [m_animation.get() isAdditive];
+}
+
+void PlatformCAAnimation::setAdditive(bool value)
+{
+ [m_animation.get() setAdditive:value];
+}
+
+PlatformCAAnimation::ValueFunctionType PlatformCAAnimation::valueFunction() const
+{
+#if HAVE_MODERN_QUARTZCORE
+ CAValueFunction* vf = [m_animation.get() valueFunction];
+ return fromCAValueFunctionType([vf name]);
+#else
+ return NoValueFunction;
+#endif
+}
+
+void PlatformCAAnimation::setValueFunction(ValueFunctionType value)
+{
+#if HAVE_MODERN_QUARTZCORE
+ [m_animation.get() setValueFunction:[CAValueFunction functionWithName:toCAValueFunctionType(value)]];
+#else
+ UNUSED_PARAM(value);
+#endif
+}
+
+void PlatformCAAnimation::setFromValue(float value)
+{
+ if (animationType() != Basic)
+ return;
+ [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[NSNumber numberWithDouble:value]];
+}
+
+void PlatformCAAnimation::setFromValue(const WebCore::TransformationMatrix& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[NSValue valueWithCATransform3D:value]];
+}
+
+void PlatformCAAnimation::setFromValue(const FloatPoint3D& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ NSArray* array = [NSArray arrayWithObjects:
+ [NSNumber numberWithDouble:value.x()],
+ [NSNumber numberWithDouble:value.y()],
+ [NSNumber numberWithDouble:value.z()],
+ nil];
+ [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:array];
+}
+
+void PlatformCAAnimation::setFromValue(const WebCore::Color& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ NSArray* array = [NSArray arrayWithObjects:
+ [NSNumber numberWithDouble:value.red()],
+ [NSNumber numberWithDouble:value.green()],
+ [NSNumber numberWithDouble:value.blue()],
+ [NSNumber numberWithDouble:value.alpha()],
+ nil];
+ [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:array];
+}
+
+void PlatformCAAnimation::copyFromValueFrom(const PlatformCAAnimation* value)
+{
+ if (animationType() != Basic || value->animationType() != Basic)
+ return;
+
+ CABasicAnimation* otherAnimation = static_cast<CABasicAnimation*>(value->m_animation.get());
+ [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[otherAnimation fromValue]];
+}
+
+void PlatformCAAnimation::setToValue(float value)
+{
+ if (animationType() != Basic)
+ return;
+ [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[NSNumber numberWithDouble:value]];
+}
+
+void PlatformCAAnimation::setToValue(const WebCore::TransformationMatrix& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[NSValue valueWithCATransform3D:value]];
+}
+
+void PlatformCAAnimation::setToValue(const FloatPoint3D& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ NSArray* array = [NSArray arrayWithObjects:
+ [NSNumber numberWithDouble:value.x()],
+ [NSNumber numberWithDouble:value.y()],
+ [NSNumber numberWithDouble:value.z()],
+ nil];
+ [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:array];
+}
+
+void PlatformCAAnimation::setToValue(const WebCore::Color& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ NSArray* array = [NSArray arrayWithObjects:
+ [NSNumber numberWithDouble:value.red()],
+ [NSNumber numberWithDouble:value.green()],
+ [NSNumber numberWithDouble:value.blue()],
+ [NSNumber numberWithDouble:value.alpha()],
+ nil];
+ [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:array];
+}
+
+void PlatformCAAnimation::copyToValueFrom(const PlatformCAAnimation* value)
+{
+ if (animationType() != Basic || value->animationType() != Basic)
+ return;
+
+ CABasicAnimation* otherAnimation = static_cast<CABasicAnimation*>(value->m_animation.get());
+ [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[otherAnimation toValue]];
+}
+
+
+// Keyframe-animation properties.
+void PlatformCAAnimation::setValues(const Vector<float>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ NSMutableArray* array = [NSMutableArray array];
+ for (size_t i = 0; i < value.size(); ++i)
+ [array addObject:[NSNumber numberWithDouble:value[i]]];
+ [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array];
+}
+
+void PlatformCAAnimation::setValues(const Vector<WebCore::TransformationMatrix>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ NSMutableArray* array = [NSMutableArray array];
+
+ for (size_t i = 0; i < value.size(); ++i)
+ [array addObject:[NSValue valueWithCATransform3D:value[i]]];
+
+ [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array];
+}
+
+void PlatformCAAnimation::setValues(const Vector<FloatPoint3D>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ NSMutableArray* array = [NSMutableArray array];
+
+ for (size_t i = 0; i < value.size(); ++i) {
+ NSArray* object = [NSArray arrayWithObjects:
+ [NSNumber numberWithDouble:value[i].x()],
+ [NSNumber numberWithDouble:value[i].y()],
+ [NSNumber numberWithDouble:value[i].z()],
+ nil];
+ [array addObject:object];
+ }
+ [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array];
+}
+
+void PlatformCAAnimation::setValues(const Vector<WebCore::Color>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ NSMutableArray* array = [NSMutableArray array];
+
+ for (size_t i = 0; i < value.size(); ++i) {
+ NSArray* object = [NSArray arrayWithObjects:
+ [NSNumber numberWithDouble:value[i].red()],
+ [NSNumber numberWithDouble:value[i].green()],
+ [NSNumber numberWithDouble:value[i].blue()],
+ [NSNumber numberWithDouble:value[i].alpha()],
+ nil];
+ [array addObject:object];
+ }
+ [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array];
+}
+
+void PlatformCAAnimation::copyValuesFrom(const PlatformCAAnimation* value)
+{
+ if (animationType() != Keyframe || value->animationType() != Keyframe)
+ return;
+
+ CAKeyframeAnimation* otherAnimation = static_cast<CAKeyframeAnimation*>(value->m_animation.get());
+ [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:[otherAnimation values]];
+}
+
+void PlatformCAAnimation::setKeyTimes(const Vector<float>& value)
+{
+ NSMutableArray* array = [NSMutableArray array];
+
+ for (size_t i = 0; i < value.size(); ++i)
+ [array addObject:[NSNumber numberWithFloat:value[i]]];
+
+ [static_cast<CAKeyframeAnimation*>(m_animation.get()) setKeyTimes:array];
+}
+
+void PlatformCAAnimation::copyKeyTimesFrom(const PlatformCAAnimation* value)
+{
+ CAKeyframeAnimation* other = static_cast<CAKeyframeAnimation*>(value->m_animation.get());
+ [static_cast<CAKeyframeAnimation*>(m_animation.get()) setKeyTimes:[other keyTimes]];
+}
+
+void PlatformCAAnimation::setTimingFunctions(const Vector<const TimingFunction*>& value)
+{
+ NSMutableArray* array = [NSMutableArray array];
+
+ for (size_t i = 0; i < value.size(); ++i)
+ [array addObject:toCAMediaTimingFunction(value[i])];
+
+ [static_cast<CAKeyframeAnimation*>(m_animation.get()) setTimingFunctions:array];
+}
+
+void PlatformCAAnimation::copyTimingFunctionsFrom(const PlatformCAAnimation* value)
+{
+ CAKeyframeAnimation* other = static_cast<CAKeyframeAnimation*>(value->m_animation.get());
+ [static_cast<CAKeyframeAnimation*>(m_animation.get()) setTimingFunctions:[other timingFunctions]];
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm b/Source/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm
new file mode 100644
index 0000000..28460a7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "PlatformCALayer.h"
+
+#import "BlockExceptions.h"
+#import "FloatConversion.h"
+#import "GraphicsContext.h"
+#import "GraphicsLayerCA.h"
+#import "WebLayer.h"
+#import "WebTiledLayer.h"
+#import <objc/objc-auto.h>
+#import <objc/objc-runtime.h>
+#import <QuartzCore/QuartzCore.h>
+#import <wtf/CurrentTime.h>
+#import <wtf/UnusedParam.h>
+
+#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
+
+using namespace WebCore;
+
+// This value must be the same as in PlatformCAAnimationMac.mm
+static NSString * const WKNonZeroBeginTimeFlag = @"WKPlatformCAAnimationNonZeroBeginTimeFlag";
+
+static double mediaTimeToCurrentTime(CFTimeInterval t)
+{
+ return WTF::currentTime() + t - CACurrentMediaTime();
+}
+
+// Delegate for animationDidStart callback
+@interface WebAnimationDelegate : NSObject {
+ PlatformCALayer* m_owner;
+}
+
+- (void)animationDidStart:(CAAnimation *)anim;
+- (void)setOwner:(PlatformCALayer*)owner;
+
+@end
+
+@implementation WebAnimationDelegate
+
+- (void)animationDidStart:(CAAnimation *)animation
+{
+ // hasNonZeroBeginTime is stored in a key in the animation
+ bool hasNonZeroBeginTime = [[animation valueForKey:WKNonZeroBeginTimeFlag] boolValue];
+ CFTimeInterval startTime;
+
+ if (hasNonZeroBeginTime) {
+ // We don't know what time CA used to commit the animation, so just use the current time
+ // (even though this will be slightly off).
+ startTime = mediaTimeToCurrentTime(CACurrentMediaTime());
+ } else
+ startTime = mediaTimeToCurrentTime([animation beginTime]);
+
+ if (m_owner)
+ m_owner->animationStarted(startTime);
+}
+
+- (void)setOwner:(PlatformCALayer*)owner
+{
+ m_owner = owner;
+}
+
+@end
+
+@interface CALayer(Private)
+- (void)setContentsChanged;
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+- (void)setAcceleratesDrawing:(BOOL)flag;
+- (BOOL)acceleratesDrawing;
+#endif
+@end
+
+static NSString * const platformCALayerPointer = @"WKPlatformCALayer";
+
+bool PlatformCALayer::isValueFunctionSupported()
+{
+ static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)];
+ return sHaveValueFunction;
+}
+
+void PlatformCALayer::setOwner(PlatformCALayerClient* owner)
+{
+ m_owner = owner;
+
+ // Change the delegate's owner if needed
+ if (m_delegate)
+ [static_cast<WebAnimationDelegate*>(m_delegate.get()) setOwner:this];
+}
+
+static NSDictionary* nullActionsDictionary()
+{
+ NSNull* nullValue = [NSNull null];
+ NSDictionary* actions = [NSDictionary dictionaryWithObjectsAndKeys:
+ nullValue, @"anchorPoint",
+ nullValue, @"bounds",
+ nullValue, @"contents",
+ nullValue, @"contentsRect",
+ nullValue, @"opacity",
+ nullValue, @"position",
+ nullValue, @"shadowColor",
+ nullValue, @"sublayerTransform",
+ nullValue, @"sublayers",
+ nullValue, @"transform",
+ nullValue, @"zPosition",
+ nil];
+ return actions;
+}
+
+#if HAVE_MODERN_QUARTZCORE
+static NSString* toCAFilterType(PlatformCALayer::FilterType type)
+{
+ switch (type) {
+ case PlatformCALayer::Linear: return kCAFilterLinear;
+ case PlatformCALayer::Nearest: return kCAFilterNearest;
+ case PlatformCALayer::Trilinear: return kCAFilterTrilinear;
+ default: return 0;
+ }
+}
+#endif
+
+PassRefPtr<PlatformCALayer> PlatformCALayer::create(LayerType layerType, PlatformCALayerClient* owner)
+{
+ return adoptRef(new PlatformCALayer(layerType, 0, owner));
+}
+
+PassRefPtr<PlatformCALayer> PlatformCALayer::create(void* platformLayer, PlatformCALayerClient* owner)
+{
+ return adoptRef(new PlatformCALayer(LayerTypeCustom, static_cast<PlatformLayer*>(platformLayer), owner));
+}
+
+PlatformCALayer::PlatformCALayer(LayerType layerType, PlatformLayer* layer, PlatformCALayerClient* owner)
+ : m_owner(owner)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ if (layer) {
+ m_layerType = LayerTypeCustom;
+ m_layer = layer;
+ } else {
+ m_layerType = layerType;
+
+ Class layerClass = Nil;
+ switch(layerType) {
+ case LayerTypeLayer:
+ case LayerTypeRootLayer:
+ layerClass = [CALayer class];
+ break;
+ case LayerTypeWebLayer:
+ layerClass = [WebLayer class];
+ break;
+ case LayerTypeTransformLayer:
+ layerClass = NSClassFromString(@"CATransformLayer");
+ break;
+ case LayerTypeWebTiledLayer:
+ layerClass = [WebTiledLayer class];
+ break;
+ case LayerTypeCustom:
+ break;
+ }
+
+ if (layerClass)
+ m_layer.adoptNS([[layerClass alloc] init]);
+ }
+
+ // Save a pointer to 'this' in the CALayer
+ [m_layer.get() setValue:[NSValue valueWithPointer:this] forKey:platformCALayerPointer];
+
+ // Clear all the implicit animations on the CALayer
+ [m_layer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
+
+ // If this is a TiledLayer, set some initial values
+ if (m_layerType == LayerTypeWebTiledLayer) {
+ WebTiledLayer* tiledLayer = static_cast<WebTiledLayer*>(m_layer.get());
+ [tiledLayer setTileSize:CGSizeMake(GraphicsLayerCA::kTiledLayerTileSize, GraphicsLayerCA::kTiledLayerTileSize)];
+ [tiledLayer setLevelsOfDetail:1];
+ [tiledLayer setLevelsOfDetailBias:0];
+ [tiledLayer setContentsGravity:@"bottomLeft"];
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+PlatformCALayer::~PlatformCALayer()
+{
+ [m_layer.get() setValue:nil forKey:platformCALayerPointer];
+
+ // Clear the owner, which also clears it in the delegate to prevent attempts
+ // to use the GraphicsLayerCA after it has been destroyed.
+ setOwner(0);
+
+ // Remove the owner pointer from the delegate in case there is a pending animationStarted event.
+ [static_cast<WebAnimationDelegate*>(m_delegate.get()) setOwner:nil];
+}
+
+PlatformCALayer* PlatformCALayer::platformCALayer(void* platformLayer)
+{
+ if (!platformLayer)
+ return 0;
+
+ // Pointer to PlatformCALayer is kept in a key of the CALayer
+ PlatformCALayer* platformCALayer = nil;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ platformCALayer = static_cast<PlatformCALayer*>([[static_cast<CALayer*>(platformLayer) valueForKey:platformCALayerPointer] pointerValue]);
+ END_BLOCK_OBJC_EXCEPTIONS
+ return platformCALayer;
+}
+
+PlatformLayer* PlatformCALayer::platformLayer() const
+{
+ return m_layer.get();
+}
+
+void PlatformCALayer::setNeedsDisplay(const FloatRect* dirtyRect)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ if (dirtyRect)
+ [m_layer.get() setNeedsDisplayInRect:*dirtyRect];
+ else
+ [m_layer.get() setNeedsDisplay];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void PlatformCALayer::setContentsChanged()
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setContentsChanged];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+PlatformCALayer* PlatformCALayer::superlayer() const
+{
+ return platformCALayer([m_layer.get() superlayer]);
+}
+
+void PlatformCALayer::removeFromSuperlayer()
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() removeFromSuperlayer];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void PlatformCALayer::setSublayers(const PlatformCALayerList& list)
+{
+ // Short circuiting here not only avoids the allocation of sublayers, but avoids <rdar://problem/7390716> (see below)
+ if (list.size() == 0) {
+ removeAllSublayers();
+ return;
+ }
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ NSMutableArray* sublayers = [[NSMutableArray alloc] init];
+ for (size_t i = 0; i < list.size(); ++i)
+ [sublayers addObject:list[i]->m_layer.get()];
+
+ [m_layer.get() setSublayers:sublayers];
+ [sublayers release];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void PlatformCALayer::removeAllSublayers()
+{
+ // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC.
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ if (objc_collectingEnabled())
+ while ([[m_layer.get() sublayers] count])
+ [[[m_layer.get() sublayers] objectAtIndex:0] removeFromSuperlayer];
+ else
+ [m_layer.get() setSublayers:nil];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void PlatformCALayer::appendSublayer(PlatformCALayer* layer)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() addSublayer:layer->m_layer.get()];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void PlatformCALayer::insertSublayer(PlatformCALayer* layer, size_t index)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() insertSublayer:layer->m_layer.get() atIndex:index];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void PlatformCALayer::replaceSublayer(PlatformCALayer* reference, PlatformCALayer* layer)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() replaceSublayer:reference->m_layer.get() with:layer->m_layer.get()];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+size_t PlatformCALayer::sublayerCount() const
+{
+ return [[m_layer.get() sublayers] count];
+}
+
+void PlatformCALayer::adoptSublayers(PlatformCALayer* source)
+{
+ // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC.
+ NSArray* sublayers = [source->m_layer.get() sublayers];
+
+ if (objc_collectingEnabled() && ![sublayers count]) {
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ while ([[m_layer.get() sublayers] count])
+ [[[m_layer.get() sublayers] objectAtIndex:0] removeFromSuperlayer];
+ END_BLOCK_OBJC_EXCEPTIONS
+ return;
+ }
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setSublayers:sublayers];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void PlatformCALayer::addAnimationForKey(const String& key, PlatformCAAnimation* animation)
+{
+ // Add the delegate
+ if (!m_delegate) {
+ WebAnimationDelegate* webAnimationDelegate = [[WebAnimationDelegate alloc] init];
+ m_delegate.adoptNS(webAnimationDelegate);
+ [webAnimationDelegate setOwner:this];
+ }
+
+ CAPropertyAnimation* propertyAnimation = static_cast<CAPropertyAnimation*>(animation->platformAnimation());
+
+ if (![propertyAnimation delegate])
+ [propertyAnimation setDelegate:static_cast<id>(m_delegate.get())];
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() addAnimation:animation->m_animation.get() forKey:key];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void PlatformCALayer::removeAnimationForKey(const String& key)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() removeAnimationForKey:key];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+PassRefPtr<PlatformCAAnimation> PlatformCALayer::animationForKey(const String& key)
+{
+ CAPropertyAnimation* propertyAnimation = static_cast<CAPropertyAnimation*>([m_layer.get() animationForKey:key]);
+ if (!propertyAnimation)
+ return 0;
+ return PlatformCAAnimation::create(propertyAnimation);
+}
+
+PlatformCALayer* PlatformCALayer::mask() const
+{
+ return platformCALayer([m_layer.get() mask]);
+}
+
+void PlatformCALayer::setMask(PlatformCALayer* layer)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setMask:layer ? layer->platformLayer() : 0];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+bool PlatformCALayer::isOpaque() const
+{
+ return [m_layer.get() isOpaque];
+}
+
+void PlatformCALayer::setOpaque(bool value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setOpaque:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+FloatRect PlatformCALayer::bounds() const
+{
+ return [m_layer.get() bounds];
+}
+
+void PlatformCALayer::setBounds(const FloatRect& value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setBounds:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+FloatPoint3D PlatformCALayer::position() const
+{
+ CGPoint point = [m_layer.get() position];
+ return FloatPoint3D(point.x, point.y, [m_layer.get() zPosition]);
+}
+
+void PlatformCALayer::setPosition(const FloatPoint3D& value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setPosition:CGPointMake(value.x(), value.y())];
+ [m_layer.get() setZPosition:value.z()];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+FloatPoint3D PlatformCALayer::anchorPoint() const
+{
+ CGPoint point = [m_layer.get() anchorPoint];
+ float z = 0;
+#if HAVE_MODERN_QUARTZCORE
+ z = [m_layer.get() anchorPointZ];
+#endif
+ return FloatPoint3D(point.x, point.y, z);
+}
+
+void PlatformCALayer::setAnchorPoint(const FloatPoint3D& value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setAnchorPoint:CGPointMake(value.x(), value.y())];
+#if HAVE_MODERN_QUARTZCORE
+ [m_layer.get() setAnchorPointZ:value.z()];
+#endif
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+TransformationMatrix PlatformCALayer::transform() const
+{
+ return [m_layer.get() transform];
+}
+
+void PlatformCALayer::setTransform(const TransformationMatrix& value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setTransform:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+TransformationMatrix PlatformCALayer::sublayerTransform() const
+{
+ return [m_layer.get() sublayerTransform];
+}
+
+void PlatformCALayer::setSublayerTransform(const TransformationMatrix& value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setSublayerTransform:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+TransformationMatrix PlatformCALayer::contentsTransform() const
+{
+#if !HAVE_MODERN_QUARTZCORE
+ if (m_layerType != LayerTypeWebLayer)
+ return TransformationMatrix();
+
+ return [static_cast<WebLayer*>(m_layer.get()) contentsTransform];
+#else
+ return TransformationMatrix();
+#endif
+}
+
+void PlatformCALayer::setContentsTransform(const TransformationMatrix& value)
+{
+#if !HAVE_MODERN_QUARTZCORE
+ if (m_layerType != LayerTypeWebLayer)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setContentsTransform:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+#else
+ UNUSED_PARAM(value);
+#endif
+}
+
+bool PlatformCALayer::isHidden() const
+{
+ return [m_layer.get() isHidden];
+}
+
+void PlatformCALayer::setHidden(bool value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setHidden:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+bool PlatformCALayer::isGeometryFlipped() const
+{
+#if HAVE_MODERN_QUARTZCORE
+ return [m_layer.get() isGeometryFlipped];
+#else
+ return false;
+#endif
+}
+
+void PlatformCALayer::setGeometryFlipped(bool value)
+{
+#if HAVE_MODERN_QUARTZCORE
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setGeometryFlipped:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+#else
+ UNUSED_PARAM(value);
+#endif
+}
+
+bool PlatformCALayer::isDoubleSided() const
+{
+ return [m_layer.get() isDoubleSided];
+}
+
+void PlatformCALayer::setDoubleSided(bool value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setDoubleSided:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+bool PlatformCALayer::masksToBounds() const
+{
+ return [m_layer.get() masksToBounds];
+}
+
+void PlatformCALayer::setMasksToBounds(bool value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setMasksToBounds:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+bool PlatformCALayer::acceleratesDrawing() const
+{
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ return [m_layer.get() acceleratesDrawing];
+#else
+ return false;
+#endif
+}
+
+void PlatformCALayer::setAcceleratesDrawing(bool acceleratesDrawing)
+{
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setAcceleratesDrawing:acceleratesDrawing];
+ END_BLOCK_OBJC_EXCEPTIONS
+#else
+ UNUSED_PARAM(acceleratesDrawing);
+#endif
+}
+
+CFTypeRef PlatformCALayer::contents() const
+{
+ return [m_layer.get() contents];
+}
+
+void PlatformCALayer::setContents(CFTypeRef value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setContents:static_cast<id>(const_cast<void*>(value))];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+FloatRect PlatformCALayer::contentsRect() const
+{
+ return [m_layer.get() contentsRect];
+}
+
+void PlatformCALayer::setContentsRect(const FloatRect& value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setContentsRect:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void PlatformCALayer::setMinificationFilter(FilterType value)
+{
+#if HAVE_MODERN_QUARTZCORE
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setMinificationFilter:toCAFilterType(value)];
+ END_BLOCK_OBJC_EXCEPTIONS
+#else
+ UNUSED_PARAM(value);
+#endif
+}
+
+void PlatformCALayer::setMagnificationFilter(FilterType value)
+{
+#if HAVE_MODERN_QUARTZCORE
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setMagnificationFilter:toCAFilterType(value)];
+ END_BLOCK_OBJC_EXCEPTIONS
+#else
+ UNUSED_PARAM(value);
+#endif
+}
+
+Color PlatformCALayer::backgroundColor() const
+{
+ return [m_layer.get() backgroundColor];
+}
+
+void PlatformCALayer::setBackgroundColor(const Color& value)
+{
+ CGFloat components[4];
+ value.getRGBA(components[0], components[1], components[2], components[3]);
+
+ RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ RetainPtr<CGColorRef> color(AdoptCF, CGColorCreate(colorSpace.get(), components));
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setBackgroundColor:color.get()];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+float PlatformCALayer::borderWidth() const
+{
+ return [m_layer.get() borderWidth];
+}
+
+void PlatformCALayer::setBorderWidth(float value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setBorderWidth:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+Color PlatformCALayer::borderColor() const
+{
+ return [m_layer.get() borderColor];
+}
+
+void PlatformCALayer::setBorderColor(const Color& value)
+{
+ CGFloat components[4];
+ value.getRGBA(components[0], components[1], components[2], components[3]);
+
+ RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ RetainPtr<CGColorRef> color(AdoptCF, CGColorCreate(colorSpace.get(), components));
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setBorderColor:color.get()];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+float PlatformCALayer::opacity() const
+{
+ return [m_layer.get() opacity];
+}
+
+void PlatformCALayer::setOpacity(float value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setOpacity:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+String PlatformCALayer::name() const
+{
+ return [m_layer.get() name];
+}
+
+void PlatformCALayer::setName(const String& value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setName:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+FloatRect PlatformCALayer::frame() const
+{
+ return [m_layer.get() frame];
+}
+
+void PlatformCALayer::setFrame(const FloatRect& value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setFrame:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+float PlatformCALayer::speed() const
+{
+ return [m_layer.get() speed];
+}
+
+void PlatformCALayer::setSpeed(float value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setSpeed:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+CFTimeInterval PlatformCALayer::timeOffset() const
+{
+ return [m_layer.get() timeOffset];
+}
+
+void PlatformCALayer::setTimeOffset(CFTimeInterval value)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setTimeOffset:value];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/ca/win/PlatformCAAnimationWin.cpp b/Source/WebCore/platform/graphics/ca/win/PlatformCAAnimationWin.cpp
new file mode 100644
index 0000000..7230cfc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/win/PlatformCAAnimationWin.cpp
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2011 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "PlatformCAAnimation.h"
+
+#include "FloatConversion.h"
+#include "PlatformString.h"
+#include "TimingFunction.h"
+#include <QuartzCore/CACFAnimation.h>
+#include <QuartzCore/CACFTiming.h>
+#include <QuartzCore/CACFTimingFunction.h>
+#include <QuartzCore/CACFValueFunction.h>
+#include <QuartzCore/CACFVector.h>
+#include <wtf/UnusedParam.h>
+
+using namespace WebCore;
+
+static String toCACFFillModeType(PlatformCAAnimation::FillModeType type)
+{
+ switch (type) {
+ case PlatformCAAnimation::NoFillMode:
+ case PlatformCAAnimation::Forwards: return kCACFFillModeForwards;
+ case PlatformCAAnimation::Backwards: return kCACFFillModeBackwards;
+ case PlatformCAAnimation::Both: return kCACFFillModeBoth;
+ }
+ return "";
+}
+
+static PlatformCAAnimation::FillModeType fromCACFFillModeType(const String& string)
+{
+ if (string == kCACFFillModeBackwards)
+ return PlatformCAAnimation::Backwards;
+
+ if (string == kCACFFillModeBoth)
+ return PlatformCAAnimation::Both;
+
+ return PlatformCAAnimation::Forwards;
+}
+
+static String toCACFValueFunctionType(PlatformCAAnimation::ValueFunctionType type)
+{
+ switch (type) {
+ case PlatformCAAnimation::NoValueFunction: return "";
+ case PlatformCAAnimation::RotateX: return kCACFValueFunctionRotateX;
+ case PlatformCAAnimation::RotateY: return kCACFValueFunctionRotateY;
+ case PlatformCAAnimation::RotateZ: return kCACFValueFunctionRotateZ;
+ case PlatformCAAnimation::ScaleX: return kCACFValueFunctionScaleX;
+ case PlatformCAAnimation::ScaleY: return kCACFValueFunctionScaleY;
+ case PlatformCAAnimation::ScaleZ: return kCACFValueFunctionScaleZ;
+ case PlatformCAAnimation::Scale: return kCACFValueFunctionScale;
+ case PlatformCAAnimation::TranslateX: return kCACFValueFunctionTranslateX;
+ case PlatformCAAnimation::TranslateY: return kCACFValueFunctionTranslateY;
+ case PlatformCAAnimation::TranslateZ: return kCACFValueFunctionTranslateZ;
+ case PlatformCAAnimation::Translate: return kCACFValueFunctionTranslate;
+ }
+ return "";
+}
+
+static PlatformCAAnimation::ValueFunctionType fromCACFValueFunctionType(const String string)
+{
+ if (string == kCACFValueFunctionRotateX)
+ return PlatformCAAnimation::RotateX;
+
+ if (string == kCACFValueFunctionRotateY)
+ return PlatformCAAnimation::RotateY;
+
+ if (string == kCACFValueFunctionRotateZ)
+ return PlatformCAAnimation::RotateZ;
+
+ if (string == kCACFValueFunctionScaleX)
+ return PlatformCAAnimation::ScaleX;
+
+ if (string == kCACFValueFunctionScaleY)
+ return PlatformCAAnimation::ScaleY;
+
+ if (string == kCACFValueFunctionScaleZ)
+ return PlatformCAAnimation::ScaleZ;
+
+ if (string == kCACFValueFunctionScale)
+ return PlatformCAAnimation::Scale;
+
+ if (string == kCACFValueFunctionTranslateX)
+ return PlatformCAAnimation::TranslateX;
+
+ if (string == kCACFValueFunctionTranslateY)
+ return PlatformCAAnimation::TranslateY;
+
+ if (string == kCACFValueFunctionTranslateZ)
+ return PlatformCAAnimation::TranslateZ;
+
+ if (string == kCACFValueFunctionTranslate)
+ return PlatformCAAnimation::Translate;
+
+ return PlatformCAAnimation::NoValueFunction;
+}
+
+static CACFTimingFunctionRef toCACFTimingFunction(const TimingFunction* timingFunction)
+{
+ if (!timingFunction)
+ return CACFTimingFunctionCreate(0.25f, 0.1f, 0.25f, 0.1f);
+
+ if (timingFunction->isCubicBezierTimingFunction()) {
+ const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction);
+ return CACFTimingFunctionCreate(static_cast<float>(ctf->x1()), static_cast<float>(ctf->y1()), static_cast<float>(ctf->x2()), static_cast<float>(ctf->y2()));
+ }
+
+ return CACFTimingFunctionGetFunctionWithName(kCACFTimingFunctionLinear);
+}
+
+PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(AnimationType type, const String& keyPath)
+{
+ return adoptRef(new PlatformCAAnimation(type, keyPath));
+}
+
+PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef animation)
+{
+ return adoptRef(new PlatformCAAnimation(animation));
+}
+
+PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(const PlatformCAAnimation* animation)
+{
+ return adoptRef(new PlatformCAAnimation(animation));
+}
+
+PlatformCAAnimation::PlatformCAAnimation(AnimationType type, const String& keyPath)
+ : m_type(type)
+{
+ if (type == Basic)
+ m_animation.adoptCF(CACFAnimationCreate(kCACFBasicAnimation));
+ else
+ m_animation.adoptCF(CACFAnimationCreate(kCACFKeyframeAnimation));
+
+ RetainPtr<CFStringRef> s(AdoptCF, keyPath.createCFString());
+ CACFAnimationSetKeyPath(m_animation.get(), s.get());
+}
+
+PlatformCAAnimation::PlatformCAAnimation(PlatformAnimationRef animation)
+{
+ if (String(CACFAnimationGetClass(animation)) == kCACFBasicAnimation)
+ m_type = Basic;
+ else if (String(CACFAnimationGetClass(animation)) == kCACFKeyframeAnimation)
+ m_type = Keyframe;
+ else {
+ ASSERT(0);
+ return;
+ }
+
+ m_animation = animation;
+}
+
+PlatformCAAnimation::PlatformCAAnimation(const PlatformCAAnimation* animation)
+{
+ m_animation.adoptCF(CACFAnimationCreate((animation->animationType() == Basic) ? kCACFBasicAnimation : kCACFKeyframeAnimation));
+ RetainPtr<CFStringRef> keyPath(AdoptCF, animation->keyPath().createCFString());
+ CACFAnimationSetKeyPath(m_animation.get(), keyPath.get());
+
+ setBeginTime(animation->beginTime());
+ setDuration(animation->duration());
+ setSpeed(animation->speed());
+ setTimeOffset(animation->timeOffset());
+ setRepeatCount(animation->repeatCount());
+ setAutoreverses(animation->autoreverses());
+ setFillMode(animation->fillMode());
+ setRemovedOnCompletion(animation->isRemovedOnCompletion());
+ setAdditive(animation->isAdditive());
+ copyTimingFunctionFrom(animation);
+ setValueFunction(animation->valueFunction());
+
+ // Copy the specific Basic or Keyframe values
+ if (animation->animationType() == Keyframe) {
+ copyValuesFrom(animation);
+ copyKeyTimesFrom(animation);
+ copyTimingFunctionsFrom(animation);
+ } else {
+ copyFromValueFrom(animation);
+ copyToValueFrom(animation);
+ }
+}
+
+PlatformCAAnimation::~PlatformCAAnimation()
+{
+}
+
+bool PlatformCAAnimation::supportsValueFunction()
+{
+ return true;
+}
+
+PlatformAnimationRef PlatformCAAnimation::platformAnimation() const
+{
+ return m_animation.get();
+}
+
+String PlatformCAAnimation::keyPath() const
+{
+ return CACFAnimationGetKeyPath(m_animation.get());
+}
+
+CFTimeInterval PlatformCAAnimation::beginTime() const
+{
+ return CACFAnimationGetBeginTime(m_animation.get());
+}
+
+void PlatformCAAnimation::setBeginTime(CFTimeInterval value)
+{
+ CACFAnimationSetBeginTime(m_animation.get(), value);
+}
+
+CFTimeInterval PlatformCAAnimation::duration() const
+{
+ return CACFAnimationGetDuration(m_animation.get());
+}
+
+void PlatformCAAnimation::setDuration(CFTimeInterval value)
+{
+ CACFAnimationSetDuration(m_animation.get(), value);
+}
+
+float PlatformCAAnimation::speed() const
+{
+ return CACFAnimationGetSpeed(m_animation.get());
+}
+
+void PlatformCAAnimation::setSpeed(float value)
+{
+ CACFAnimationSetSpeed(m_animation.get(), value);
+}
+
+CFTimeInterval PlatformCAAnimation::timeOffset() const
+{
+ return CACFAnimationGetTimeOffset(m_animation.get());
+}
+
+void PlatformCAAnimation::setTimeOffset(CFTimeInterval value)
+{
+ CACFAnimationSetTimeOffset(m_animation.get(), value);
+}
+
+float PlatformCAAnimation::repeatCount() const
+{
+ return CACFAnimationGetRepeatCount(m_animation.get());
+}
+
+void PlatformCAAnimation::setRepeatCount(float value)
+{
+ CACFAnimationSetRepeatCount(m_animation.get(), value);
+}
+
+bool PlatformCAAnimation::autoreverses() const
+{
+ return CACFAnimationGetAutoreverses(m_animation.get());
+}
+
+void PlatformCAAnimation::setAutoreverses(bool value)
+{
+ CACFAnimationSetAutoreverses(m_animation.get(), value);
+}
+
+PlatformCAAnimation::FillModeType PlatformCAAnimation::fillMode() const
+{
+ return fromCACFFillModeType(CACFAnimationGetFillMode(m_animation.get()));
+}
+
+void PlatformCAAnimation::setFillMode(FillModeType value)
+{
+ RetainPtr<CFStringRef> keyPath(AdoptCF, toCACFFillModeType(value).createCFString());
+ CACFAnimationSetFillMode(m_animation.get(), keyPath.get());
+}
+
+void PlatformCAAnimation::setTimingFunction(const TimingFunction* value)
+{
+ CACFAnimationSetTimingFunction(m_animation.get(), toCACFTimingFunction(value));
+}
+
+void PlatformCAAnimation::copyTimingFunctionFrom(const PlatformCAAnimation* value)
+{
+ CACFAnimationSetTimingFunction(m_animation.get(), CACFAnimationGetTimingFunction(value->m_animation.get()));
+}
+
+bool PlatformCAAnimation::isRemovedOnCompletion() const
+{
+ return CACFAnimationIsRemovedOnCompletion(m_animation.get());
+}
+
+void PlatformCAAnimation::setRemovedOnCompletion(bool value)
+{
+ CACFAnimationSetRemovedOnCompletion(m_animation.get(), value);
+}
+
+bool PlatformCAAnimation::isAdditive() const
+{
+ return CACFAnimationIsAdditive(m_animation.get());
+}
+
+void PlatformCAAnimation::setAdditive(bool value)
+{
+ CACFAnimationSetAdditive(m_animation.get(), value);
+}
+
+PlatformCAAnimation::ValueFunctionType PlatformCAAnimation::valueFunction() const
+{
+ return fromCACFValueFunctionType(CACFValueFunctionGetName(CACFAnimationGetValueFunction(m_animation.get())));
+}
+
+void PlatformCAAnimation::setValueFunction(ValueFunctionType value)
+{
+ RetainPtr<CFStringRef> keyPath(AdoptCF, toCACFValueFunctionType(value).createCFString());
+ CACFAnimationSetValueFunction(m_animation.get(), CACFValueFunctionGetFunctionWithName(keyPath.get()));
+}
+
+void PlatformCAAnimation::setFromValue(float value)
+{
+ if (animationType() != Basic)
+ return;
+
+ RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value));
+ CACFAnimationSetFromValue(m_animation.get(), v.get());
+}
+
+void PlatformCAAnimation::setFromValue(const WebCore::TransformationMatrix& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreateTransform(value));
+ CACFAnimationSetFromValue(m_animation.get(), v.get());
+}
+
+void PlatformCAAnimation::setFromValue(const FloatPoint3D& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ float a[3] = { value.x(), value.y(), value.z() };
+ RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(3, a));
+ CACFAnimationSetFromValue(m_animation.get(), v.get());
+}
+
+void PlatformCAAnimation::setFromValue(const WebCore::Color& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ float a[4] = { value.red(), value.green(), value.blue(), value.alpha() };
+ RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(4, a));
+ CACFAnimationSetFromValue(m_animation.get(), v.get());
+}
+
+void PlatformCAAnimation::copyFromValueFrom(const PlatformCAAnimation* value)
+{
+ if (animationType() != Basic || value->animationType() != Basic)
+ return;
+
+ CACFAnimationSetFromValue(m_animation.get(), CACFAnimationGetFromValue(value->platformAnimation()));
+}
+
+void PlatformCAAnimation::setToValue(float value)
+{
+ if (animationType() != Basic)
+ return;
+
+ RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value));
+ CACFAnimationSetToValue(m_animation.get(), v.get());
+}
+
+void PlatformCAAnimation::setToValue(const WebCore::TransformationMatrix& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreateTransform(value));
+ CACFAnimationSetToValue(m_animation.get(), v.get());
+}
+
+void PlatformCAAnimation::setToValue(const FloatPoint3D& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ float a[3] = { value.x(), value.y(), value.z() };
+ RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(3, a));
+ CACFAnimationSetToValue(m_animation.get(), v.get());
+}
+
+void PlatformCAAnimation::setToValue(const WebCore::Color& value)
+{
+ if (animationType() != Basic)
+ return;
+
+ float a[4] = { value.red(), value.green(), value.blue(), value.alpha() };
+ RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(4, a));
+ CACFAnimationSetToValue(m_animation.get(), v.get());
+}
+
+void PlatformCAAnimation::copyToValueFrom(const PlatformCAAnimation* value)
+{
+ if (animationType() != Basic || value->animationType() != Basic)
+ return;
+
+ CACFAnimationSetToValue(m_animation.get(), CACFAnimationGetToValue(value->platformAnimation()));
+}
+
+
+// Keyframe-animation properties.
+void PlatformCAAnimation::setValues(const Vector<float>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks));
+ for (size_t i = 0; i < value.size(); ++i) {
+ RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value[i]));
+ CFArrayAppendValue(array.get(), v.get());
+ }
+
+ CACFAnimationSetValues(m_animation.get(), array.get());
+}
+
+void PlatformCAAnimation::setValues(const Vector<WebCore::TransformationMatrix>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks));
+ for (size_t i = 0; i < value.size(); ++i) {
+ RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreateTransform(value[i]));
+ CFArrayAppendValue(array.get(), v.get());
+ }
+
+ CACFAnimationSetValues(m_animation.get(), array.get());
+}
+
+void PlatformCAAnimation::setValues(const Vector<FloatPoint3D>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks));
+ for (size_t i = 0; i < value.size(); ++i) {
+ float a[3] = { value[i].x(), value[i].y(), value[i].z() };
+ RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(3, a));
+ CFArrayAppendValue(array.get(), v.get());
+ }
+
+ CACFAnimationSetValues(m_animation.get(), array.get());
+}
+
+void PlatformCAAnimation::setValues(const Vector<WebCore::Color>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks));
+ for (size_t i = 0; i < value.size(); ++i) {
+ float a[4] = { value[i].red(), value[i].green(), value[i].blue(), value[i].alpha() };
+ RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(4, a));
+ CFArrayAppendValue(array.get(), v.get());
+ }
+
+ CACFAnimationSetValues(m_animation.get(), array.get());
+}
+
+void PlatformCAAnimation::copyValuesFrom(const PlatformCAAnimation* value)
+{
+ if (animationType() != Keyframe || value->animationType() != Keyframe)
+ return;
+
+ CACFAnimationSetValues(m_animation.get(), CACFAnimationGetValues(value->platformAnimation()));
+}
+
+void PlatformCAAnimation::setKeyTimes(const Vector<float>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks));
+ for (size_t i = 0; i < value.size(); ++i) {
+ RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value[i]));
+ CFArrayAppendValue(array.get(), v.get());
+ }
+
+ CACFAnimationSetKeyTimes(m_animation.get(), array.get());
+}
+
+void PlatformCAAnimation::copyKeyTimesFrom(const PlatformCAAnimation* value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ CACFAnimationSetKeyTimes(m_animation.get(), CACFAnimationGetKeyTimes(value->platformAnimation()));
+}
+
+void PlatformCAAnimation::setTimingFunctions(const Vector<const TimingFunction*>& value)
+{
+ if (animationType() != Keyframe)
+ return;
+
+ RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks));
+ for (size_t i = 0; i < value.size(); ++i) {
+ RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value[i]));
+ CFArrayAppendValue(array.get(), toCACFTimingFunction(value[i]));
+ }
+
+ CACFAnimationSetTimingFunctions(m_animation.get(), array.get());
+}
+
+void PlatformCAAnimation::copyTimingFunctionsFrom(const PlatformCAAnimation* value)
+{
+ CACFAnimationSetTimingFunctions(m_animation.get(), CACFAnimationGetTimingFunctions(value->platformAnimation()));
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp
new file mode 100644
index 0000000..919c3b3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp
@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 2011 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "PlatformCALayer.h"
+
+#include "Font.h"
+#include "GraphicsContext.h"
+#include "PlatformCALayerWinInternal.h"
+#include "WKCACFLayerRenderer.h"
+#include <QuartzCore/CoreAnimationCF.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+bool PlatformCALayer::isValueFunctionSupported()
+{
+ return true;
+}
+
+void PlatformCALayer::setOwner(PlatformCALayerClient* owner)
+{
+ m_owner = owner;
+}
+
+static CFStringRef toCACFLayerType(PlatformCALayer::LayerType type)
+{
+ return (type == PlatformCALayer::LayerTypeTransformLayer) ? kCACFTransformLayer : kCACFLayer;
+}
+
+static CFStringRef toCACFFilterType(PlatformCALayer::FilterType type)
+{
+ switch (type) {
+ case PlatformCALayer::Linear: return kCACFFilterLinear;
+ case PlatformCALayer::Nearest: return kCACFFilterNearest;
+ case PlatformCALayer::Trilinear: return kCACFFilterTrilinear;
+ default: return 0;
+ }
+}
+
+static WKCACFLayerRenderer* rendererForLayer(const PlatformCALayer* layer)
+{
+ // We need the WKCACFLayerRenderer associated with this layer, which is stored in the UserData of the CACFContext
+ void* userData = wkCACFLayerGetContextUserData(layer->platformLayer());
+ if (!userData)
+ return 0;
+
+ return static_cast<WKCACFLayerRenderer*>(userData);
+}
+
+static PlatformCALayerWinInternal* intern(const PlatformCALayer* layer)
+{
+ return static_cast<PlatformCALayerWinInternal*>(CACFLayerGetUserData(layer->platformLayer()));
+}
+
+static PlatformCALayerWinInternal* intern(void* layer)
+{
+ return static_cast<PlatformCALayerWinInternal*>(CACFLayerGetUserData(static_cast<CACFLayerRef>(layer)));
+}
+
+PassRefPtr<PlatformCALayer> PlatformCALayer::create(LayerType layerType, PlatformCALayerClient* owner)
+{
+ return adoptRef(new PlatformCALayer(layerType, 0, owner));
+}
+
+PassRefPtr<PlatformCALayer> PlatformCALayer::create(void* platformLayer, PlatformCALayerClient* owner)
+{
+ return adoptRef(new PlatformCALayer(LayerTypeCustom, static_cast<PlatformLayer*>(platformLayer), owner));
+}
+
+static void displayCallback(CACFLayerRef caLayer, CGContextRef context)
+{
+ ASSERT_ARG(caLayer, CACFLayerGetUserData(caLayer));
+ intern(caLayer)->displayCallback(caLayer, context);
+}
+
+static void layoutSublayersProc(CACFLayerRef caLayer)
+{
+ PlatformCALayer* layer = PlatformCALayer::platformCALayer(caLayer);
+ if (layer && layer->owner())
+ layer->owner()->platformCALayerLayoutSublayersOfLayer(layer);
+}
+
+PlatformCALayer::PlatformCALayer(LayerType layerType, PlatformLayer* layer, PlatformCALayerClient* owner)
+ : m_owner(owner)
+{
+ if (layer) {
+ m_layerType = LayerTypeCustom;
+ m_layer = layer;
+ } else {
+ m_layerType = layerType;
+ m_layer.adoptCF(CACFLayerCreate(toCACFLayerType(layerType)));
+
+ // Create the PlatformCALayerWinInternal object and point to it in the userdata.
+ PlatformCALayerWinInternal* intern = new PlatformCALayerWinInternal(this);
+ CACFLayerSetUserData(m_layer.get(), intern);
+
+ // Set the display callback
+ CACFLayerSetDisplayCallback(m_layer.get(), displayCallback);
+ CACFLayerSetLayoutCallback(m_layer.get(), layoutSublayersProc);
+ }
+}
+
+PlatformCALayer::~PlatformCALayer()
+{
+ // Toss all the kids
+ removeAllSublayers();
+
+ // Get rid of the user data
+ PlatformCALayerWinInternal* layerIntern = intern(this);
+ CACFLayerSetUserData(m_layer.get(), 0);
+
+ delete layerIntern;
+}
+
+PlatformCALayer* PlatformCALayer::platformCALayer(void* platformLayer)
+{
+ if (!platformLayer)
+ return 0;
+
+ PlatformCALayerWinInternal* layerIntern = intern(platformLayer);
+ return layerIntern ? layerIntern->owner() : 0;
+}
+
+PlatformLayer* PlatformCALayer::platformLayer() const
+{
+ return m_layer.get();
+}
+
+PlatformCALayer* PlatformCALayer::rootLayer() const
+{
+ WKCACFLayerRenderer* renderer = rendererForLayer(this);
+ return renderer ? renderer->rootLayer() : 0;
+}
+
+void PlatformCALayer::setNeedsDisplay(const FloatRect* dirtyRect)
+{
+ intern(this)->setNeedsDisplay(dirtyRect);
+}
+
+void PlatformCALayer::setNeedsCommit()
+{
+ WKCACFLayerRenderer* renderer = rendererForLayer(this);
+ if (renderer)
+ renderer->layerTreeDidChange();
+}
+
+void PlatformCALayer::setContentsChanged()
+{
+ // FIXME: There is no equivalent of setContentsChanged in CACF. For now I will
+ // set contents to 0 and then back to its original value to see if that
+ // kicks CACF into redisplaying.
+ RetainPtr<CFTypeRef> contents = CACFLayerGetContents(m_layer.get());
+ CACFLayerSetContents(m_layer.get(), 0);
+ CACFLayerSetContents(m_layer.get(), contents.get());
+ setNeedsCommit();
+}
+
+void PlatformCALayer::setNeedsLayout()
+{
+ if (!m_owner || !m_owner->platformCALayerRespondsToLayoutChanges())
+ return;
+
+ CACFLayerSetNeedsLayout(m_layer.get());
+ setNeedsCommit();
+}
+
+PlatformCALayer* PlatformCALayer::superlayer() const
+{
+ return platformCALayer(CACFLayerGetSuperlayer(m_layer.get()));
+}
+
+void PlatformCALayer::removeFromSuperlayer()
+{
+ CACFLayerRemoveFromSuperlayer(m_layer.get());
+ setNeedsCommit();
+}
+
+void PlatformCALayer::setSublayers(const PlatformCALayerList& list)
+{
+ intern(this)->setSublayers(list);
+}
+
+void PlatformCALayer::removeAllSublayers()
+{
+ intern(this)->removeAllSublayers();
+}
+
+void PlatformCALayer::appendSublayer(PlatformCALayer* layer)
+{
+ // This must be in terms of insertSublayer instead of a direct call so PlatformCALayerInternal can override.
+ insertSublayer(layer, sublayerCount());
+}
+
+void PlatformCALayer::insertSublayer(PlatformCALayer* layer, size_t index)
+{
+ intern(this)->insertSublayer(layer, index);
+}
+
+void PlatformCALayer::replaceSublayer(PlatformCALayer* reference, PlatformCALayer* newLayer)
+{
+ // This must not use direct calls to allow PlatformCALayerInternal to override.
+ ASSERT_ARG(reference, reference);
+ ASSERT_ARG(reference, reference->superlayer() == this);
+
+ if (reference == newLayer)
+ return;
+
+ int referenceIndex = intern(this)->indexOfSublayer(reference);
+ ASSERT(referenceIndex != -1);
+ if (referenceIndex == -1)
+ return;
+
+ reference->removeFromSuperlayer();
+
+ if (newLayer) {
+ newLayer->removeFromSuperlayer();
+ insertSublayer(newLayer, referenceIndex);
+ }
+}
+
+size_t PlatformCALayer::sublayerCount() const
+{
+ return intern(this)->sublayerCount();
+}
+
+void PlatformCALayer::adoptSublayers(PlatformCALayer* source)
+{
+ // Make a list of the sublayers from source
+ PlatformCALayerList sublayers;
+ size_t n = source->sublayerCount();
+ CFArrayRef sourceSublayers = CACFLayerGetSublayers(source->platformLayer());
+
+ for (size_t i = 0; i < n; ++i) {
+ CACFLayerRef layer = static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sourceSublayers, i)));
+ sublayers.append(platformCALayer(layer));
+ }
+
+ // Use setSublayers() because it properly nulls out the superlayer pointers.
+ setSublayers(sublayers);
+}
+
+void PlatformCALayer::addAnimationForKey(const String& key, PlatformCAAnimation* animation)
+{
+ // Add it to the animation list
+ m_animations.add(key, animation);
+
+ RetainPtr<CFStringRef> s(AdoptCF, key.createCFString());
+ CACFLayerAddAnimation(m_layer.get(), s.get(), animation->platformAnimation());
+ setNeedsCommit();
+
+ // Tell the renderer about it so we can fire the start animation event
+ WKCACFLayerRenderer* renderer = rendererForLayer(this);
+ if (renderer)
+ renderer->addPendingAnimatedLayer(this);
+}
+
+void PlatformCALayer::removeAnimationForKey(const String& key)
+{
+ // Remove it from the animation list
+ m_animations.remove(key);
+
+ RetainPtr<CFStringRef> s(AdoptCF, key.createCFString());
+ CACFLayerRemoveAnimation(m_layer.get(), s.get());
+
+ // We don't "remove" a layer from WKCACFLayerRenderer when it loses an animation.
+ // There may be other active animations on the layer and if an animation
+ // callback is fired on a layer without any animations no harm is done.
+
+ setNeedsCommit();
+}
+
+PassRefPtr<PlatformCAAnimation> PlatformCALayer::animationForKey(const String& key)
+{
+ HashMap<String, RefPtr<PlatformCAAnimation> >::iterator it = m_animations.find(key);
+ if (it == m_animations.end())
+ return 0;
+
+ return it->second;
+}
+
+PlatformCALayer* PlatformCALayer::mask() const
+{
+ return platformCALayer(CACFLayerGetMask(m_layer.get()));
+}
+
+void PlatformCALayer::setMask(PlatformCALayer* layer)
+{
+ CACFLayerSetMask(m_layer.get(), layer ? layer->platformLayer() : 0);
+ setNeedsCommit();
+}
+
+bool PlatformCALayer::isOpaque() const
+{
+ return CACFLayerIsOpaque(m_layer.get());
+}
+
+void PlatformCALayer::setOpaque(bool value)
+{
+ CACFLayerSetOpaque(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+FloatRect PlatformCALayer::bounds() const
+{
+ return CACFLayerGetBounds(m_layer.get());
+}
+
+void PlatformCALayer::setBounds(const FloatRect& value)
+{
+ intern(this)->setBounds(value);
+ setNeedsLayout();
+}
+
+FloatPoint3D PlatformCALayer::position() const
+{
+ CGPoint point = CACFLayerGetPosition(m_layer.get());
+ return FloatPoint3D(point.x, point.y, CACFLayerGetZPosition(m_layer.get()));
+}
+
+void PlatformCALayer::setPosition(const FloatPoint3D& value)
+{
+ CACFLayerSetPosition(m_layer.get(), CGPointMake(value.x(), value.y()));
+ CACFLayerSetZPosition(m_layer.get(), value.z());
+ setNeedsCommit();
+}
+
+FloatPoint3D PlatformCALayer::anchorPoint() const
+{
+ CGPoint point = CACFLayerGetAnchorPoint(m_layer.get());
+ float z = CACFLayerGetAnchorPointZ(m_layer.get());
+ return FloatPoint3D(point.x, point.y, z);
+}
+
+void PlatformCALayer::setAnchorPoint(const FloatPoint3D& value)
+{
+ CACFLayerSetAnchorPoint(m_layer.get(), CGPointMake(value.x(), value.y()));
+ CACFLayerSetAnchorPointZ(m_layer.get(), value.z());
+ setNeedsCommit();
+}
+
+TransformationMatrix PlatformCALayer::transform() const
+{
+ return CACFLayerGetTransform(m_layer.get());
+}
+
+void PlatformCALayer::setTransform(const TransformationMatrix& value)
+{
+ CACFLayerSetTransform(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+TransformationMatrix PlatformCALayer::sublayerTransform() const
+{
+ return CACFLayerGetSublayerTransform(m_layer.get());
+}
+
+void PlatformCALayer::setSublayerTransform(const TransformationMatrix& value)
+{
+ CACFLayerSetSublayerTransform(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+TransformationMatrix PlatformCALayer::contentsTransform() const
+{
+ // ContentsTransform is not used
+ return TransformationMatrix();
+}
+
+void PlatformCALayer::setContentsTransform(const TransformationMatrix&)
+{
+ // ContentsTransform is not used
+}
+
+bool PlatformCALayer::isHidden() const
+{
+ return CACFLayerIsHidden(m_layer.get());
+}
+
+void PlatformCALayer::setHidden(bool value)
+{
+ CACFLayerSetHidden(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+bool PlatformCALayer::isGeometryFlipped() const
+{
+ return CACFLayerIsGeometryFlipped(m_layer.get());
+}
+
+void PlatformCALayer::setGeometryFlipped(bool value)
+{
+ CACFLayerSetGeometryFlipped(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+bool PlatformCALayer::isDoubleSided() const
+{
+ return CACFLayerIsDoubleSided(m_layer.get());
+}
+
+void PlatformCALayer::setDoubleSided(bool value)
+{
+ CACFLayerSetDoubleSided(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+bool PlatformCALayer::masksToBounds() const
+{
+ return CACFLayerGetMasksToBounds(m_layer.get());
+}
+
+void PlatformCALayer::setMasksToBounds(bool value)
+{
+ CACFLayerSetMasksToBounds(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+bool PlatformCALayer::acceleratesDrawing() const
+{
+ return false;
+}
+
+void PlatformCALayer::setAcceleratesDrawing(bool)
+{
+}
+
+CFTypeRef PlatformCALayer::contents() const
+{
+ return CACFLayerGetContents(m_layer.get());
+}
+
+void PlatformCALayer::setContents(CFTypeRef value)
+{
+ CACFLayerSetContents(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+FloatRect PlatformCALayer::contentsRect() const
+{
+ return CACFLayerGetContentsRect(m_layer.get());
+}
+
+void PlatformCALayer::setContentsRect(const FloatRect& value)
+{
+ CACFLayerSetContentsRect(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+void PlatformCALayer::setMinificationFilter(FilterType value)
+{
+ CACFLayerSetMinificationFilter(m_layer.get(), toCACFFilterType(value));
+}
+
+void PlatformCALayer::setMagnificationFilter(FilterType value)
+{
+ CACFLayerSetMagnificationFilter(m_layer.get(), toCACFFilterType(value));
+ setNeedsCommit();
+}
+
+Color PlatformCALayer::backgroundColor() const
+{
+ return CACFLayerGetBackgroundColor(m_layer.get());
+}
+
+void PlatformCALayer::setBackgroundColor(const Color& value)
+{
+ CGFloat components[4];
+ value.getRGBA(components[0], components[1], components[2], components[3]);
+
+ RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ RetainPtr<CGColorRef> color(AdoptCF, CGColorCreate(colorSpace.get(), components));
+
+ CACFLayerSetBackgroundColor(m_layer.get(), color.get());
+ setNeedsCommit();
+}
+
+float PlatformCALayer::borderWidth() const
+{
+ return CACFLayerGetBorderWidth(m_layer.get());
+}
+
+void PlatformCALayer::setBorderWidth(float value)
+{
+ CACFLayerSetBorderWidth(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+Color PlatformCALayer::borderColor() const
+{
+ return CACFLayerGetBorderColor(m_layer.get());
+}
+
+void PlatformCALayer::setBorderColor(const Color& value)
+{
+ CGFloat components[4];
+ value.getRGBA(components[0], components[1], components[2], components[3]);
+
+ RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ RetainPtr<CGColorRef> color(AdoptCF, CGColorCreate(colorSpace.get(), components));
+
+ CACFLayerSetBorderColor(m_layer.get(), color.get());
+ setNeedsCommit();
+}
+
+float PlatformCALayer::opacity() const
+{
+ return CACFLayerGetOpacity(m_layer.get());
+}
+
+void PlatformCALayer::setOpacity(float value)
+{
+ CACFLayerSetOpacity(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+String PlatformCALayer::name() const
+{
+ return CACFLayerGetName(m_layer.get());
+}
+
+void PlatformCALayer::setName(const String& value)
+{
+ RetainPtr<CFStringRef> s(AdoptCF, value.createCFString());
+ CACFLayerSetName(m_layer.get(), s.get());
+ setNeedsCommit();
+}
+
+FloatRect PlatformCALayer::frame() const
+{
+ return CACFLayerGetFrame(m_layer.get());
+}
+
+void PlatformCALayer::setFrame(const FloatRect& value)
+{
+ intern(this)->setFrame(value);
+ setNeedsLayout();
+}
+
+float PlatformCALayer::speed() const
+{
+ return CACFLayerGetSpeed(m_layer.get());
+}
+
+void PlatformCALayer::setSpeed(float value)
+{
+ CACFLayerSetSpeed(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+CFTimeInterval PlatformCALayer::timeOffset() const
+{
+ return CACFLayerGetTimeOffset(m_layer.get());
+}
+
+void PlatformCALayer::setTimeOffset(CFTimeInterval value)
+{
+ CACFLayerSetTimeOffset(m_layer.get(), value);
+ setNeedsCommit();
+}
+
+#ifndef NDEBUG
+static void printIndent(int indent)
+{
+ for ( ; indent > 0; --indent)
+ fprintf(stderr, " ");
+}
+
+static void printTransform(const CATransform3D& transform)
+{
+ fprintf(stderr, "[%g %g %g %g; %g %g %g %g; %g %g %g %g; %g %g %g %g]",
+ transform.m11, transform.m12, transform.m13, transform.m14,
+ transform.m21, transform.m22, transform.m23, transform.m24,
+ transform.m31, transform.m32, transform.m33, transform.m34,
+ transform.m41, transform.m42, transform.m43, transform.m44);
+}
+
+static void printLayer(const PlatformCALayer* layer, int indent)
+{
+ FloatPoint3D layerPosition = layer->position();
+ FloatPoint3D layerAnchorPoint = layer->anchorPoint();
+ FloatRect layerBounds = layer->bounds();
+ printIndent(indent);
+
+ char* layerTypeName = 0;
+ switch (layer->layerType()) {
+ case PlatformCALayer::LayerTypeLayer: layerTypeName = "layer"; break;
+ case PlatformCALayer::LayerTypeWebLayer: layerTypeName = "web-layer"; break;
+ case PlatformCALayer::LayerTypeTransformLayer: layerTypeName = "transform-layer"; break;
+ case PlatformCALayer::LayerTypeWebTiledLayer: layerTypeName = "web-tiled-layer"; break;
+ case PlatformCALayer::LayerTypeRootLayer: layerTypeName = "root-layer"; break;
+ case PlatformCALayer::LayerTypeCustom: layerTypeName = "custom-layer"; break;
+ }
+
+ fprintf(stderr, "(%s [%g %g %g] [%g %g %g %g] [%g %g %g] superlayer=%p\n",
+ layerTypeName,
+ layerPosition.x(), layerPosition.y(), layerPosition.z(),
+ layerBounds.x(), layerBounds.y(), layerBounds.width(), layerBounds.height(),
+ layerAnchorPoint.x(), layerAnchorPoint.y(), layerAnchorPoint.z(), layer->superlayer());
+
+ // Print name if needed
+ String layerName = layer->name();
+ if (!layerName.isEmpty()) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(name %s)\n", layerName.utf8().data());
+ }
+
+ // Print masksToBounds if needed
+ bool layerMasksToBounds = layer->masksToBounds();
+ if (layerMasksToBounds) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(masksToBounds true)\n");
+ }
+
+ // Print opacity if needed
+ float layerOpacity = layer->opacity();
+ if (layerOpacity != 1) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(opacity %hf)\n", layerOpacity);
+ }
+
+ // Print sublayerTransform if needed
+ TransformationMatrix layerTransform = layer->sublayerTransform();
+ if (!layerTransform.isIdentity()) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(sublayerTransform ");
+ printTransform(layerTransform);
+ fprintf(stderr, ")\n");
+ }
+
+ // Print transform if needed
+ layerTransform = layer->transform();
+ if (!layerTransform.isIdentity()) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(transform ");
+ printTransform(layerTransform);
+ fprintf(stderr, ")\n");
+ }
+
+ // Print contents if needed
+ CFTypeRef layerContents = layer->contents();
+ if (layerContents) {
+ if (CFGetTypeID(layerContents) == CGImageGetTypeID()) {
+ CGImageRef imageContents = static_cast<CGImageRef>(const_cast<void*>(layerContents));
+ printIndent(indent + 1);
+ fprintf(stderr, "(contents (image [%d %d]))\n",
+ CGImageGetWidth(imageContents), CGImageGetHeight(imageContents));
+ }
+ }
+
+ // Print sublayers if needed
+ int n = layer->sublayerCount();
+ if (n > 0) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(sublayers\n");
+
+ CFArrayRef sublayers = CACFLayerGetSublayers(layer->platformLayer());
+ for (int i = 0; i < n; ++i) {
+ PlatformCALayer* sublayer = PlatformCALayer::platformCALayer(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, i)));
+ printLayer(sublayer, indent + 2);
+ }
+
+ printIndent(indent + 1);
+ fprintf(stderr, ")\n");
+ }
+
+ printIndent(indent);
+ fprintf(stderr, ")\n");
+}
+
+void PlatformCALayer::printTree() const
+{
+ // Print heading info
+ CGRect rootBounds = bounds();
+ fprintf(stderr, "\n\n** Render tree at time %g (bounds %g, %g %gx%g) **\n\n",
+ currentTime(), rootBounds.origin.x, rootBounds.origin.y, rootBounds.size.width, rootBounds.size.height);
+
+ // Print layer tree from the root
+ printLayer(this, 0);
+}
+#endif // #ifndef NDEBUG
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWinInternal.cpp b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWinInternal.cpp
new file mode 100644
index 0000000..0b7eea0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWinInternal.cpp
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2011 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "PlatformCALayerWinInternal.h"
+
+#include "Font.h"
+#include "PlatformCALayer.h"
+#include <QuartzCore/CACFLayer.h>
+
+using namespace std;
+using namespace WebCore;
+
+// The width and height of a single tile in a tiled layer. Should be large enough to
+// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
+// to keep the overall tile cost low.
+static const int cTiledLayerTileSize = 512;
+
+PlatformCALayerWinInternal::PlatformCALayerWinInternal(PlatformCALayer* owner)
+ : m_tileSize(CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize))
+ , m_constrainedSize(constrainedSize(owner->bounds().size()))
+ , m_owner(owner)
+{
+ if (m_owner->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) {
+ // Tiled layers are placed in a child layer that is always the first child of the TiledLayer
+ m_tileParent.adoptCF(CACFLayerCreate(kCACFLayer));
+ CACFLayerInsertSublayer(m_owner->platformLayer(), m_tileParent.get(), 0);
+ updateTiles();
+ }
+}
+
+PlatformCALayerWinInternal::~PlatformCALayerWinInternal()
+{
+}
+
+void PlatformCALayerWinInternal::displayCallback(CACFLayerRef caLayer, CGContextRef context)
+{
+ if (!owner() || !owner()->owner())
+ return;
+
+ CGContextSaveGState(context);
+
+ CGRect layerBounds = owner()->bounds();
+ if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
+ CGContextScaleCTM(context, 1, -1);
+ CGContextTranslateCTM(context, 0, -layerBounds.size.height);
+ }
+
+ if (owner()->owner()) {
+ GraphicsContext graphicsContext(context);
+
+ // It's important to get the clip from the context, because it may be significantly
+ // smaller than the layer bounds (e.g. tiled layers)
+ CGRect clipBounds = CGContextGetClipBoundingBox(context);
+ IntRect clip(enclosingIntRect(clipBounds));
+ owner()->owner()->platformCALayerPaintContents(graphicsContext, clip);
+ }
+#ifndef NDEBUG
+ else {
+ ASSERT_NOT_REACHED();
+
+ // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
+ // so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
+ CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
+ CGContextFillRect(context, layerBounds);
+ }
+#endif
+
+ if (owner()->owner()->platformCALayerShowRepaintCounter()) {
+ String text = String::number(owner()->owner()->platformCALayerIncrementRepaintCount());
+
+ CGContextSaveGState(context);
+
+ // Make the background of the counter the same as the border color,
+ // unless there is no border, then make it red
+ float borderWidth = CACFLayerGetBorderWidth(caLayer);
+ if (borderWidth > 0) {
+ CGColorRef borderColor = CACFLayerGetBorderColor(caLayer);
+ const CGFloat* colors = CGColorGetComponents(borderColor);
+ CGContextSetRGBFillColor(context, colors[0], colors[1], colors[2], colors[3]);
+ } else
+ CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
+
+ CGRect aBounds = layerBounds;
+
+ aBounds.size.width = 10 + 10 * text.length();
+ aBounds.size.height = 22;
+ CGContextFillRect(context, aBounds);
+
+ FontDescription desc;
+
+ NONCLIENTMETRICS metrics;
+ metrics.cbSize = sizeof(metrics);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
+ FontFamily family;
+ family.setFamily(metrics.lfSmCaptionFont.lfFaceName);
+ desc.setFamily(family);
+
+ desc.setComputedSize(18);
+
+ Font font = Font(desc, 0, 0);
+ font.update(0);
+
+ GraphicsContext cg(context);
+ cg.setFillColor(Color::black, ColorSpaceDeviceRGB);
+ cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 5, aBounds.origin.y + 17));
+
+ CGContextRestoreGState(context);
+ }
+
+ CGContextRestoreGState(context);
+
+ owner()->owner()->platformCALayerLayerDidDisplay(caLayer);
+}
+
+void PlatformCALayerWinInternal::internalSetNeedsDisplay(const FloatRect* dirtyRect)
+{
+ if (dirtyRect) {
+ CGRect rect = *dirtyRect;
+ CACFLayerSetNeedsDisplay(owner()->platformLayer(), &rect);
+ } else
+ CACFLayerSetNeedsDisplay(owner()->platformLayer(), 0);
+}
+
+void PlatformCALayerWinInternal::setNeedsDisplay(const FloatRect* dirtyRect)
+{
+ if (owner()->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) {
+ // FIXME: Only setNeedsDisplay for tiles that are currently visible
+ int numTileLayers = tileCount();
+ CGRect rect;
+ if (dirtyRect)
+ rect = *dirtyRect;
+ for (int i = 0; i < numTileLayers; ++i)
+ CACFLayerSetNeedsDisplay(tileAtIndex(i), dirtyRect ? &rect : 0);
+
+ if (m_owner->owner() && m_owner->owner()->platformCALayerShowRepaintCounter()) {
+ CGRect layerBounds = m_owner->bounds();
+ CGRect indicatorRect = CGRectMake(layerBounds.origin.x, layerBounds.origin.y, 80, 25);
+ CACFLayerSetNeedsDisplay(tileAtIndex(0), &indicatorRect);
+ }
+ } else if (owner()->layerType() == PlatformCALayer::LayerTypeWebLayer) {
+ if (owner() && owner()->owner()) {
+ if (owner()->owner()->platformCALayerShowRepaintCounter()) {
+ FloatRect layerBounds = owner()->bounds();
+ FloatRect repaintCounterRect = layerBounds;
+
+ // We assume a maximum of 4 digits and a font size of 18.
+ repaintCounterRect.setWidth(80);
+ repaintCounterRect.setHeight(22);
+ if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown)
+ repaintCounterRect.setY(layerBounds.height() - (layerBounds.y() + repaintCounterRect.height()));
+ internalSetNeedsDisplay(&repaintCounterRect);
+ }
+ if (dirtyRect && owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
+ FloatRect flippedDirtyRect = *dirtyRect;
+ flippedDirtyRect.setY(owner()->bounds().height() - (flippedDirtyRect.y() + flippedDirtyRect.height()));
+ internalSetNeedsDisplay(&flippedDirtyRect);
+ return;
+ }
+ }
+
+ internalSetNeedsDisplay(dirtyRect);
+ }
+ owner()->setNeedsCommit();
+}
+
+void PlatformCALayerWinInternal::setSublayers(const PlatformCALayerList& list)
+{
+ // Remove all the current sublayers and add the passed layers
+ CACFLayerSetSublayers(owner()->platformLayer(), 0);
+
+ // Perform removeFromSuperLayer in a separate pass. CACF requires superlayer to
+ // be null or CACFLayerInsertSublayer silently fails.
+ for (size_t i = 0; i < list.size(); i++)
+ CACFLayerRemoveFromSuperlayer(list[i]->platformLayer());
+
+ for (size_t i = 0; i < list.size(); i++)
+ CACFLayerInsertSublayer(owner()->platformLayer(), list[i]->platformLayer(), i);
+
+ owner()->setNeedsCommit();
+
+ if (owner()->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) {
+ // Preserve the tile parent after set
+ CACFLayerInsertSublayer(owner()->platformLayer(), m_tileParent.get(), 0);
+ }
+}
+
+void PlatformCALayerWinInternal::removeAllSublayers()
+{
+ CACFLayerSetSublayers(owner()->platformLayer(), 0);
+ owner()->setNeedsCommit();
+
+ if (owner()->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) {
+ // Restore the tile parent after removal
+ CACFLayerInsertSublayer(owner()->platformLayer(), m_tileParent.get(), 0);
+ }
+}
+
+void PlatformCALayerWinInternal::insertSublayer(PlatformCALayer* layer, size_t index)
+{
+ index = min(index, sublayerCount());
+ if (owner()->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) {
+ // Add 1 to account for the tile parent layer
+ index++;
+ }
+
+ layer->removeFromSuperlayer();
+ CACFLayerInsertSublayer(owner()->platformLayer(), layer->platformLayer(), index);
+ owner()->setNeedsCommit();
+}
+
+size_t PlatformCALayerWinInternal::sublayerCount() const
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
+ size_t count = sublayers ? CFArrayGetCount(sublayers) : 0;
+
+ if (owner()->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) {
+ // Subtract 1 to account for the tile parent layer
+ ASSERT(count > 0);
+ count--;
+ }
+
+ return count;
+}
+
+int PlatformCALayerWinInternal::indexOfSublayer(const PlatformCALayer* reference)
+{
+ CACFLayerRef ref = reference->platformLayer();
+ if (!ref)
+ return -1;
+
+ CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
+ if (!sublayers)
+ return -1;
+
+ size_t n = CFArrayGetCount(sublayers);
+
+ if (owner()->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) {
+ for (size_t i = 1; i < n; ++i) {
+ if (CFArrayGetValueAtIndex(sublayers, i) == ref)
+ return i - 1;
+ }
+ } else {
+ for (size_t i = 0; i < n; ++i) {
+ if (CFArrayGetValueAtIndex(sublayers, i) == ref)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+PlatformCALayer* PlatformCALayerWinInternal::sublayerAtIndex(int index) const
+{
+ if (owner()->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) {
+ // Add 1 to account for the tile parent layer
+ index++;
+ }
+
+ CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
+ if (!sublayers || index < 0 || CFArrayGetCount(sublayers) <= index)
+ return 0;
+
+ return PlatformCALayer::platformCALayer(static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index))));
+}
+
+void PlatformCALayerWinInternal::setBounds(const FloatRect& rect)
+{
+ if (CGRectEqualToRect(rect, owner()->bounds()))
+ return;
+
+ CACFLayerSetBounds(owner()->platformLayer(), rect);
+ owner()->setNeedsCommit();
+
+ if (owner()->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) {
+ m_constrainedSize = constrainedSize(rect.size());
+ updateTiles();
+ }
+}
+
+void PlatformCALayerWinInternal::setFrame(const FloatRect& rect)
+{
+ CGRect oldFrame = owner()->frame();
+ if (CGRectEqualToRect(rect, oldFrame))
+ return;
+
+ CACFLayerSetFrame(owner()->platformLayer(), rect);
+ owner()->setNeedsCommit();
+
+ if (owner()->layerType() == PlatformCALayer::LayerTypeWebTiledLayer)
+ updateTiles();
+}
+
+CGSize PlatformCALayerWinInternal::constrainedSize(const CGSize& size) const
+{
+ const int cMaxTileCount = 512;
+ const float cSqrtMaxTileCount = sqrtf(cMaxTileCount);
+
+ CGSize constrainedSize = size;
+
+ int tileColumns = ceilf(constrainedSize.width / m_tileSize.width);
+ int tileRows = ceilf(constrainedSize.height / m_tileSize.height);
+ int numTiles = tileColumns * tileRows;
+
+ // If number of tiles vertically or horizontally is < sqrt(cMaxTileCount)
+ // just shorten the longer dimension. Otherwise shorten both dimensions
+ // according to the ratio of width to height
+
+ if (numTiles > cMaxTileCount) {
+ if (tileRows < cSqrtMaxTileCount)
+ tileColumns = floorf(cMaxTileCount / tileRows);
+ else if (tileColumns < cSqrtMaxTileCount)
+ tileRows = floorf(cMaxTileCount / tileColumns);
+ else {
+ tileRows = ceilf(sqrtf(cMaxTileCount * constrainedSize.height / constrainedSize.width));
+ tileColumns = floorf(cMaxTileCount / tileRows);
+ }
+
+ constrainedSize.width = tileColumns * m_tileSize.width;
+ constrainedSize.height = tileRows * m_tileSize.height;
+ }
+
+ return constrainedSize;
+}
+
+void PlatformCALayerWinInternal::tileDisplayCallback(CACFLayerRef layer, CGContextRef context)
+{
+ static_cast<PlatformCALayerWinInternal*>(CACFLayerGetUserData(layer))->drawTile(layer, context);
+}
+
+void PlatformCALayerWinInternal::addTile()
+{
+ RetainPtr<CACFLayerRef> newLayer(AdoptCF, CACFLayerCreate(kCACFLayer));
+ CACFLayerSetAnchorPoint(newLayer.get(), CGPointMake(0, 1));
+ CACFLayerSetUserData(newLayer.get(), this);
+ CACFLayerSetDisplayCallback(newLayer.get(), tileDisplayCallback);
+
+ CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
+ CACFLayerInsertSublayer(m_tileParent.get(), newLayer.get(), sublayers ? CFArrayGetCount(sublayers) : 0);
+
+ if (owner()->owner()->platformCALayerShowDebugBorders()) {
+ CGColorRef borderColor = CGColorCreateGenericRGB(0.5, 0, 0.5, 0.7);
+ CACFLayerSetBorderColor(newLayer.get(), borderColor);
+ CGColorRelease(borderColor);
+ CACFLayerSetBorderWidth(newLayer.get(), 2);
+ }
+}
+
+void PlatformCALayerWinInternal::removeTile()
+{
+ CACFLayerRemoveFromSuperlayer(tileAtIndex(tileCount() - 1));
+}
+
+CACFLayerRef PlatformCALayerWinInternal::tileAtIndex(int index)
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
+ if (!sublayers || index < 0 || index >= tileCount())
+ return 0;
+
+ return static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index)));
+}
+
+int PlatformCALayerWinInternal::tileCount() const
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
+ return sublayers ? CFArrayGetCount(sublayers) : 0;
+}
+
+void PlatformCALayerWinInternal::updateTiles()
+{
+ // FIXME: In addition to redoing the number of tiles, we need to only render and have backing
+ // store for visible layers
+ int numTilesHorizontal = ceil(m_constrainedSize.width / m_tileSize.width);
+ int numTilesVertical = ceil(m_constrainedSize.height / m_tileSize.height);
+ int numTilesTotal = numTilesHorizontal * numTilesVertical;
+
+ int numTilesToChange = numTilesTotal - tileCount();
+ if (numTilesToChange >= 0) {
+ // Add new tiles
+ for (int i = 0; i < numTilesToChange; ++i)
+ addTile();
+ } else {
+ // Remove old tiles
+ numTilesToChange = -numTilesToChange;
+ for (int i = 0; i < numTilesToChange; ++i)
+ removeTile();
+ }
+
+ // Set coordinates for all tiles
+ CFArrayRef tileArray = CACFLayerGetSublayers(m_tileParent.get());
+
+ for (int i = 0; i < numTilesHorizontal; ++i) {
+ for (int j = 0; j < numTilesVertical; ++j) {
+ CACFLayerRef tile = static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(tileArray, i * numTilesVertical + j)));
+ CACFLayerSetPosition(tile, CGPointMake(i * m_tileSize.width, j * m_tileSize.height));
+ int width = min(m_tileSize.width, m_constrainedSize.width - i * m_tileSize.width);
+ int height = min(m_tileSize.height, m_constrainedSize.height - j * m_tileSize.height);
+ CACFLayerSetBounds(tile, CGRectMake(i * m_tileSize.width, j * m_tileSize.height, width, height));
+
+ // Flip Y to compensate for the flipping that happens during render to match the CG context coordinate space
+ CATransform3D transform = CATransform3DMakeScale(1, -1, 1);
+ CATransform3DTranslate(transform, 0, height, 0);
+ CACFLayerSetTransform(tile, transform);
+
+#ifndef NDEBUG
+ String name = "Tile (" + String::number(i) + "," + String::number(j) + ")";
+ CACFLayerSetName(tile, RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get());
+#endif
+ }
+ }
+}
+
+void PlatformCALayerWinInternal::drawTile(CACFLayerRef tile, CGContextRef context)
+{
+ CGPoint tilePosition = CACFLayerGetPosition(tile);
+ CGRect tileBounds = CACFLayerGetBounds(tile);
+
+ CGContextSaveGState(context);
+
+ // Transform context to be at the origin of the parent layer
+ CGContextTranslateCTM(context, -tilePosition.x, -tilePosition.y);
+
+ // Set the context clipping rectangle to the current tile
+ CGContextClipToRect(context, CGRectMake(tilePosition.x, tilePosition.y, tileBounds.size.width, tileBounds.size.height));
+
+ if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
+ // If the layer is rendering top-down, it will flip the coordinates in y. Tiled layers are
+ // already flipping, so we need to undo that here.
+ CGContextTranslateCTM(context, 0, owner()->bounds().height());
+ CGContextScaleCTM(context, 1, -1);
+ }
+
+ // Draw the tile
+ displayCallback(owner()->platformLayer(), context);
+
+ CGContextRestoreGState(context);
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWinInternal.h b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWinInternal.h
new file mode 100644
index 0000000..1be9d26
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWinInternal.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 PlatformCALayerWinInternal_h
+#define PlatformCALayerWinInternal_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include <CoreGraphics/CGGeometry.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+typedef struct _CACFLayer *CACFLayerRef;
+typedef struct CGContext *CGContextRef;
+
+namespace WebCore {
+
+class FloatRect;
+class PlatformCALayer;
+
+typedef Vector<RefPtr<PlatformCALayer> > PlatformCALayerList;
+
+class PlatformCALayerWinInternal {
+public:
+ PlatformCALayerWinInternal(PlatformCALayer*);
+ ~PlatformCALayerWinInternal();
+
+ void displayCallback(CACFLayerRef, CGContextRef);
+ void setNeedsDisplay(const FloatRect*);
+ PlatformCALayer* owner() const { return m_owner; }
+
+ void setSublayers(const PlatformCALayerList&);
+ void removeAllSublayers();
+ void insertSublayer(PlatformCALayer*, size_t);
+ size_t sublayerCount() const;
+ int indexOfSublayer(const PlatformCALayer* reference);
+
+ void setBounds(const FloatRect&);
+ void setFrame(const FloatRect&);
+
+private:
+ void internalSetNeedsDisplay(const FloatRect*);
+ PlatformCALayer* sublayerAtIndex(int) const;
+
+ static void tileDisplayCallback(CACFLayerRef, CGContextRef);
+
+ void drawTile(CACFLayerRef, CGContextRef);
+ CGSize constrainedSize(const CGSize&) const;
+ void addTile();
+ void removeTile();
+ CACFLayerRef tileAtIndex(int);
+ int tileCount() const;
+ void updateTiles();
+
+ PlatformCALayer* m_owner;
+
+ CGSize m_tileSize;
+ CGSize m_constrainedSize;
+ RetainPtr<CACFLayerRef> m_tileParent;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // PlatformCALayerWinInternal_h
diff --git a/Source/WebCore/platform/graphics/cairo/CairoPath.h b/Source/WebCore/platform/graphics/cairo/CairoPath.h
new file mode 100644
index 0000000..da7affb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/CairoPath.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
+ Copyright (C) 2010 Igalia S.L.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CairoPath_h
+#define CairoPath_h
+
+#include <cairo.h>
+
+namespace WebCore {
+
+// This is necessary since cairo_path_fixed_t isn't exposed in Cairo's public API.
+class CairoPath {
+public:
+ CairoPath()
+ {
+ static cairo_surface_t* pathSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1);
+ m_cr = cairo_create(pathSurface);
+ }
+
+ ~CairoPath()
+ {
+ cairo_destroy(m_cr);
+ }
+
+ cairo_t* context() { return m_cr; }
+
+private:
+ cairo_t* m_cr;
+};
+
+} // namespace WebCore
+
+#endif // CairoPath_h
diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp
new file mode 100644
index 0000000..013a4af
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "CairoUtilities.h"
+
+#include "AffineTransform.h"
+#include "CairoPath.h"
+#include "Color.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "OwnPtrCairo.h"
+#include "Path.h"
+#include "RefPtrCairo.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr)
+{
+ cairo_set_antialias(dstCr, cairo_get_antialias(srcCr));
+
+ size_t dashCount = cairo_get_dash_count(srcCr);
+ Vector<double> dashes(dashCount);
+
+ double offset;
+ cairo_get_dash(srcCr, dashes.data(), &offset);
+ cairo_set_dash(dstCr, dashes.data(), dashCount, offset);
+ cairo_set_line_cap(dstCr, cairo_get_line_cap(srcCr));
+ cairo_set_line_join(dstCr, cairo_get_line_join(srcCr));
+ cairo_set_line_width(dstCr, cairo_get_line_width(srcCr));
+ cairo_set_miter_limit(dstCr, cairo_get_miter_limit(srcCr));
+ cairo_set_fill_rule(dstCr, cairo_get_fill_rule(srcCr));
+}
+
+void setSourceRGBAFromColor(cairo_t* context, const Color& color)
+{
+ float red, green, blue, alpha;
+ color.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(context, red, green, blue, alpha);
+}
+
+void appendPathToCairoContext(cairo_t* to, cairo_t* from)
+{
+ OwnPtr<cairo_path_t> cairoPath(cairo_copy_path(from));
+ cairo_append_path(to, cairoPath.get());
+}
+
+void setPathOnCairoContext(cairo_t* to, cairo_t* from)
+{
+ cairo_new_path(to);
+ appendPathToCairoContext(to, from);
+}
+
+void appendWebCorePathToCairoContext(cairo_t* context, const Path& path)
+{
+ appendPathToCairoContext(context, path.platformPath()->context());
+}
+
+cairo_operator_t toCairoOperator(CompositeOperator op)
+{
+ switch (op) {
+ case CompositeClear:
+ return CAIRO_OPERATOR_CLEAR;
+ case CompositeCopy:
+ return CAIRO_OPERATOR_SOURCE;
+ case CompositeSourceOver:
+ return CAIRO_OPERATOR_OVER;
+ case CompositeSourceIn:
+ return CAIRO_OPERATOR_IN;
+ case CompositeSourceOut:
+ return CAIRO_OPERATOR_OUT;
+ case CompositeSourceAtop:
+ return CAIRO_OPERATOR_ATOP;
+ case CompositeDestinationOver:
+ return CAIRO_OPERATOR_DEST_OVER;
+ case CompositeDestinationIn:
+ return CAIRO_OPERATOR_DEST_IN;
+ case CompositeDestinationOut:
+ return CAIRO_OPERATOR_DEST_OUT;
+ case CompositeDestinationAtop:
+ return CAIRO_OPERATOR_DEST_ATOP;
+ case CompositeXOR:
+ return CAIRO_OPERATOR_XOR;
+ case CompositePlusDarker:
+ return CAIRO_OPERATOR_SATURATE;
+ case CompositeHighlight:
+ // There is no Cairo equivalent for CompositeHighlight.
+ return CAIRO_OPERATOR_OVER;
+ case CompositePlusLighter:
+ return CAIRO_OPERATOR_ADD;
+ default:
+ return CAIRO_OPERATOR_SOURCE;
+ }
+}
+
+void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSize& imageSize, const FloatRect& tileRect,
+ const AffineTransform& patternTransform, const FloatPoint& phase, cairo_operator_t op, const FloatRect& destRect)
+{
+ // Avoid NaN
+ if (!isfinite(phase.x()) || !isfinite(phase.y()))
+ return;
+
+ cairo_save(cr);
+
+ RefPtr<cairo_surface_t> clippedImageSurface = 0;
+ if (tileRect.size() != imageSize) {
+ IntRect imageRect = enclosingIntRect(tileRect);
+ clippedImageSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageRect.width(), imageRect.height()));
+ RefPtr<cairo_t> clippedImageContext = adoptRef(cairo_create(clippedImageSurface.get()));
+ cairo_set_source_surface(clippedImageContext.get(), image, -tileRect.x(), -tileRect.y());
+ cairo_paint(clippedImageContext.get());
+ image = clippedImageSurface.get();
+ }
+
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+
+ cairo_matrix_t patternMatrix = cairo_matrix_t(patternTransform);
+ cairo_matrix_t phaseMatrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()};
+ cairo_matrix_t combined;
+ cairo_matrix_multiply(&combined, &patternMatrix, &phaseMatrix);
+ cairo_matrix_invert(&combined);
+ cairo_pattern_set_matrix(pattern, &combined);
+
+ cairo_set_operator(cr, op);
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+ cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height());
+ cairo_fill(cr);
+
+ cairo_restore(cr);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.h b/Source/WebCore/platform/graphics/cairo/CairoUtilities.h
new file mode 100644
index 0000000..d8fff8d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 CairoUtilities_h
+#define CairoUtilities_h
+
+#include <GraphicsTypes.h>
+#include <cairo.h>
+
+namespace WebCore {
+class AffineTransform;
+class Color;
+class FloatRect;
+class FloatPoint;
+class IntSize;
+class Path;
+
+void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr);
+void setSourceRGBAFromColor(cairo_t*, const Color&);
+void appendPathToCairoContext(cairo_t* to, cairo_t* from);
+void setPathOnCairoContext(cairo_t* to, cairo_t* from);
+void appendWebCorePathToCairoContext(cairo_t* context, const Path& path);
+cairo_operator_t toCairoOperator(CompositeOperator op);
+void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSize& imageSize, const FloatRect& tileRect,
+ const AffineTransform& patternTransform, const FloatPoint& phase, cairo_operator_t op, const FloatRect& destRect);
+
+} // namespace WebCore
+
+#endif // CairoUtilities_h
diff --git a/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
new file mode 100644
index 0000000..b0588d6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2010 Sencha, Inc.
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ContextShadow.h"
+
+#include "AffineTransform.h"
+#include "CairoUtilities.h"
+#include "GraphicsContext.h"
+#include "OwnPtrCairo.h"
+#include "Path.h"
+#include "Timer.h"
+#include <cairo.h>
+
+using WTF::max;
+
+namespace WebCore {
+
+static cairo_surface_t* scratchBuffer = 0;
+static void purgeScratchBuffer()
+{
+ cairo_surface_destroy(scratchBuffer);
+ scratchBuffer = 0;
+}
+
+// ContextShadow needs a scratch image as the buffer for the blur filter.
+// Instead of creating and destroying the buffer for every operation,
+// we create a buffer which will be automatically purged via a timer.
+class PurgeScratchBufferTimer : public TimerBase {
+private:
+ virtual void fired() { purgeScratchBuffer(); }
+};
+static PurgeScratchBufferTimer purgeScratchBufferTimer;
+static void scheduleScratchBufferPurge()
+{
+ if (purgeScratchBufferTimer.isActive())
+ purgeScratchBufferTimer.stop();
+ purgeScratchBufferTimer.startOneShot(2);
+}
+
+static cairo_surface_t* getScratchBuffer(const IntSize& size)
+{
+ int width = size.width();
+ int height = size.height();
+ int scratchWidth = scratchBuffer ? cairo_image_surface_get_width(scratchBuffer) : 0;
+ int scratchHeight = scratchBuffer ? cairo_image_surface_get_height(scratchBuffer) : 0;
+
+ // We do not need to recreate the buffer if the current buffer is large enough.
+ if (scratchBuffer && scratchWidth >= width && scratchHeight >= height)
+ return scratchBuffer;
+
+ purgeScratchBuffer();
+
+ // Round to the nearest 32 pixels so we do not grow the buffer for similar sized requests.
+ width = (1 + (width >> 5)) << 5;
+ height = (1 + (height >> 5)) << 5;
+ scratchBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ return scratchBuffer;
+}
+
+PlatformContext ContextShadow::beginShadowLayer(GraphicsContext* context, const FloatRect& layerArea)
+{
+ adjustBlurDistance(context);
+
+ double x1, x2, y1, y2;
+ cairo_clip_extents(context->platformContext(), &x1, &y1, &x2, &y2);
+ IntRect layerRect = calculateLayerBoundingRect(context, layerArea, IntRect(x1, y1, x2 - x1, y2 - y1));
+
+ // Don't paint if we are totally outside the clip region.
+ if (layerRect.isEmpty())
+ return 0;
+
+ m_layerImage = getScratchBuffer(layerRect.size());
+ m_layerContext = cairo_create(m_layerImage);
+
+ // Always clear the surface first.
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_CLEAR);
+ cairo_paint(m_layerContext);
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER);
+
+ cairo_translate(m_layerContext, m_layerContextTranslation.x(), m_layerContextTranslation.y());
+ return m_layerContext;
+}
+
+void ContextShadow::endShadowLayer(GraphicsContext* context)
+{
+ cairo_destroy(m_layerContext);
+ m_layerContext = 0;
+
+ if (m_type == BlurShadow) {
+ cairo_surface_flush(m_layerImage);
+ blurLayerImage(cairo_image_surface_get_data(m_layerImage),
+ IntSize(cairo_image_surface_get_width(m_layerImage), cairo_image_surface_get_height(m_layerImage)),
+ cairo_image_surface_get_stride(m_layerImage));
+ cairo_surface_mark_dirty(m_layerImage);
+ }
+
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+ setSourceRGBAFromColor(cr, m_color);
+ cairo_mask_surface(cr, m_layerImage, m_layerOrigin.x(), m_layerOrigin.y());
+ cairo_restore(cr);
+
+ // Schedule a purge of the scratch buffer. We do not need to destroy the surface.
+ scheduleScratchBufferPurge();
+}
+
+void ContextShadow::drawRectShadowWithoutTiling(GraphicsContext* context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha)
+{
+ beginShadowLayer(context, shadowRect);
+
+ if (!m_layerContext)
+ return;
+
+ Path path;
+ path.addRoundedRect(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+
+ appendWebCorePathToCairoContext(m_layerContext, path);
+ cairo_set_source_rgba(m_layerContext, 0, 0, 0, alpha);
+ cairo_fill(m_layerContext);
+
+ endShadowLayer(context);
+}
+
+static inline FloatPoint getPhase(const FloatRect& dest, const FloatRect& tile)
+{
+ FloatPoint phase = dest.location();
+ phase.move(-tile.x(), -tile.y());
+
+ return phase;
+}
+
+/*
+ This function uses tiling to improve the performance of the shadow
+ drawing of rounded rectangles. The code basically does the following
+ steps:
+
+ 1. Calculate the size of the shadow template, a rectangle that
+ contains all the necessary tiles to draw the complete shadow.
+
+ 2. If that size is smaller than the real rectangle render the new
+ template rectangle and its shadow in a new surface, in other case
+ render the shadow of the real rectangle in the destination
+ surface.
+
+ 3. Calculate the sizes and positions of the tiles and their
+ destinations and use drawPattern to render the final shadow. The
+ code divides the rendering in 8 tiles:
+
+ 1 | 2 | 3
+ -----------
+ 4 | | 5
+ -----------
+ 6 | 7 | 8
+
+ The corners are directly copied from the template rectangle to the
+ real one and the side tiles are 1 pixel width, we use them as
+
+ tiles to cover the destination side. The corner tiles are bigger
+ than just the side of the rounded corner, we need to increase it
+ because the modifications caused by the corner over the blur
+ effect. We fill the central part with solid color to complete the
+ shadow.
+ */
+void ContextShadow::drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius)
+{
+
+ float radiusTwice = m_blurDistance * 2;
+
+ // Find the space the corners need inside the rect for its shadows.
+ int internalShadowWidth = radiusTwice + max(topLeftRadius.width(), bottomLeftRadius.width()) +
+ max(topRightRadius.width(), bottomRightRadius.width());
+ int internalShadowHeight = radiusTwice + max(topLeftRadius.height(), topRightRadius.height()) +
+ max(bottomLeftRadius.height(), bottomRightRadius.height());
+
+ cairo_t* cr = context->platformContext();
+
+ // drawShadowedRect still does not work with rotations.
+ // https://bugs.webkit.org/show_bug.cgi?id=45042
+ if ((!context->getCTM().isIdentityOrTranslationOrFlipped()) || (internalShadowWidth > rect.width())
+ || (internalShadowHeight > rect.height()) || (m_type != BlurShadow)) {
+ drawRectShadowWithoutTiling(context, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha());
+ return;
+ }
+
+ // Calculate size of the template shadow buffer.
+ IntSize shadowBufferSize = IntSize(rect.width() + radiusTwice, rect.height() + radiusTwice);
+
+ // Determine dimensions of shadow rect.
+ FloatRect shadowRect = FloatRect(rect.location(), shadowBufferSize);
+ shadowRect.move(- m_blurDistance, - m_blurDistance);
+
+ // Size of the tiling side.
+ int sideTileWidth = 1;
+
+ // The length of a side of the buffer is the enough space for four blur radii,
+ // the radii of the corners, and then 1 pixel to draw the side tiles.
+ IntSize shadowTemplateSize = IntSize(sideTileWidth + radiusTwice + internalShadowWidth,
+ sideTileWidth + radiusTwice + internalShadowHeight);
+
+ // Reduce the size of what we have to draw with the clip area.
+ double x1, x2, y1, y2;
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+ calculateLayerBoundingRect(context, shadowRect, IntRect(x1, y1, x2 - x1, y2 - y1));
+
+ if ((shadowTemplateSize.width() * shadowTemplateSize.height() > m_sourceRect.width() * m_sourceRect.height())) {
+ drawRectShadowWithoutTiling(context, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha());
+ return;
+ }
+
+ shadowRect.move(m_offset.width(), m_offset.height());
+
+ m_layerImage = getScratchBuffer(shadowTemplateSize);
+
+ // Draw shadow into a new ImageBuffer.
+ m_layerContext = cairo_create(m_layerImage);
+
+ // Clear the surface first.
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_CLEAR);
+ cairo_paint(m_layerContext);
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER);
+
+ // Draw the rectangle.
+ IntRect templateRect = IntRect(m_blurDistance, m_blurDistance, shadowTemplateSize.width() - radiusTwice, shadowTemplateSize.height() - radiusTwice);
+ Path path;
+ path.addRoundedRect(templateRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+ appendWebCorePathToCairoContext(m_layerContext, path);
+
+ cairo_set_source_rgba(m_layerContext, 0, 0, 0, context->getAlpha());
+ cairo_fill(m_layerContext);
+
+ // Blur the image.
+ cairo_surface_flush(m_layerImage);
+ blurLayerImage(cairo_image_surface_get_data(m_layerImage), shadowTemplateSize, cairo_image_surface_get_stride(m_layerImage));
+ cairo_surface_mark_dirty(m_layerImage);
+
+ // Mask the image with the shadow color.
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_IN);
+ setSourceRGBAFromColor(m_layerContext, m_color);
+ cairo_paint(m_layerContext);
+
+ cairo_destroy(m_layerContext);
+ m_layerContext = 0;
+
+ // Fill the internal part of the shadow.
+ shadowRect.inflate(-radiusTwice);
+ if (!shadowRect.isEmpty()) {
+ cairo_save(cr);
+ path.clear();
+ path.addRoundedRect(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+ appendWebCorePathToCairoContext(cr, path);
+ setSourceRGBAFromColor(cr, m_color);
+ cairo_fill(cr);
+ cairo_restore(cr);
+ }
+ shadowRect.inflate(radiusTwice);
+
+ // Draw top side.
+ FloatRect tileRect = FloatRect(radiusTwice + topLeftRadius.width(), 0, sideTileWidth, radiusTwice);
+ FloatRect destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y());
+ destRect.setWidth(shadowRect.width() - topLeftRadius.width() - topRightRadius.width() - m_blurDistance * 4);
+ FloatPoint phase = getPhase(destRect, tileRect);
+ AffineTransform patternTransform;
+ patternTransform.makeIdentity();
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the bottom side.
+ tileRect = FloatRect(radiusTwice + bottomLeftRadius.width(), shadowTemplateSize.height() - radiusTwice, sideTileWidth, radiusTwice);
+ destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y() + radiusTwice + rect.height() - shadowTemplateSize.height());
+ destRect.setWidth(shadowRect.width() - bottomLeftRadius.width() - bottomRightRadius.width() - m_blurDistance * 4);
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the right side.
+ tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice, radiusTwice + topRightRadius.height(), radiusTwice, sideTileWidth);
+ destRect = tileRect;
+ destRect.move(shadowRect.x() + radiusTwice + rect.width() - shadowTemplateSize.width(), shadowRect.y());
+ destRect.setHeight(shadowRect.height() - topRightRadius.height() - bottomRightRadius.height() - m_blurDistance * 4);
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the left side.
+ tileRect = FloatRect(0, radiusTwice + topLeftRadius.height(), radiusTwice, sideTileWidth);
+ destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y());
+ destRect.setHeight(shadowRect.height() - topLeftRadius.height() - bottomLeftRadius.height() - m_blurDistance * 4);
+ phase = FloatPoint(destRect.x() - tileRect.x(), destRect.y() - tileRect.y());
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the top left corner.
+ tileRect = FloatRect(0, 0, radiusTwice + topLeftRadius.width(), radiusTwice + topLeftRadius.height());
+ destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y());
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the top right corner.
+ tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice - topRightRadius.width(), 0, radiusTwice + topRightRadius.width(),
+ radiusTwice + topRightRadius.height());
+ destRect = tileRect;
+ destRect.move(shadowRect.x() + rect.width() - shadowTemplateSize.width() + radiusTwice, shadowRect.y());
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the bottom right corner.
+ tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice - bottomRightRadius.width(),
+ shadowTemplateSize.height() - radiusTwice - bottomRightRadius.height(),
+ radiusTwice + bottomRightRadius.width(), radiusTwice + bottomRightRadius.height());
+ destRect = tileRect;
+ destRect.move(shadowRect.x() + rect.width() - shadowTemplateSize.width() + radiusTwice,
+ shadowRect.y() + rect.height() - shadowTemplateSize.height() + radiusTwice);
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the bottom left corner.
+ tileRect = FloatRect(0, shadowTemplateSize.height() - radiusTwice - bottomLeftRadius.height(),
+ radiusTwice + bottomLeftRadius.width(), radiusTwice + bottomLeftRadius.height());
+ destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y() + rect.height() - shadowTemplateSize.height() + radiusTwice);
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Schedule a purge of the scratch buffer.
+ scheduleScratchBufferPurge();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h
new file mode 100644
index 0000000..1e0a846
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2004 Red Hat, Inc.
+ * Copyright (C) 2010 Brent Fulgham <bfulgham@webkit.org>
+ *
+ * Based on Pango sources (see pangocairo-render.c)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#if PLATFORM(CAIRO)
+
+#include <cairo.h>
+
+//
+// Draws an error underline that looks like one of:
+//
+// H E H
+// /\ /\ /\ /\ /\ -
+// A/ \ / \ / \ A/ \ / \ |
+// \ \ / \ / /D \ \ / \ |
+// \ \/ C \/ / \ \/ C \ | height = heightSquares * square
+// \ /\ F / \ F /\ \ |
+// \ / \ / \ / \ \G |
+// \ / \ / \ / \ / |
+// \/ \/ \/ \/ -
+// B B
+// |---|
+// unitWidth = (heightSquares - 1) * square
+//
+// The x, y, width, height passed in give the desired bounding box;
+// x/width are adjusted to make the underline a integer number of units
+// wide.
+//
+static inline void drawErrorUnderline(cairo_t* cr, double x, double y, double width, double height)
+{
+ static const double heightSquares = 2.5;
+
+ double square = height / heightSquares;
+ double halfSquare = 0.5 * square;
+
+ double unitWidth = (heightSquares - 1.0) * square;
+ int widthUnits = static_cast<int>((width + 0.5 * unitWidth) / unitWidth);
+
+ x += 0.5 * (width - widthUnits * unitWidth);
+ width = widthUnits * unitWidth;
+
+ double bottom = y + height;
+ double top = y;
+
+ // Bottom of squiggle
+ cairo_move_to(cr, x - halfSquare, top + halfSquare); // A
+
+ int i = 0;
+ for (i = 0; i < widthUnits; i += 2) {
+ double middle = x + (i + 1) * unitWidth;
+ double right = x + (i + 2) * unitWidth;
+
+ cairo_line_to(cr, middle, bottom); // B
+
+ if (i + 2 == widthUnits)
+ cairo_line_to(cr, right + halfSquare, top + halfSquare); // D
+ else if (i + 1 != widthUnits)
+ cairo_line_to(cr, right, top + square); // C
+ }
+
+ // Top of squiggle
+ for (i -= 2; i >= 0; i -= 2) {
+ double left = x + i * unitWidth;
+ double middle = x + (i + 1) * unitWidth;
+ double right = x + (i + 2) * unitWidth;
+
+ if (i + 1 == widthUnits)
+ cairo_line_to(cr, middle + halfSquare, bottom - halfSquare); // G
+ else {
+ if (i + 2 == widthUnits)
+ cairo_line_to(cr, right, top); // E
+
+ cairo_line_to(cr, middle, bottom - halfSquare); // F
+ }
+
+ cairo_line_to(cr, left, top); // H
+ }
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp b/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp
new file mode 100644
index 0000000..9f86f74
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+FloatRect::FloatRect(const cairo_rectangle_t& r)
+ : m_location(r.x, r.y)
+ , m_size(r.width, r.height)
+{
+}
+
+FloatRect::operator cairo_rectangle_t() const
+{
+ cairo_rectangle_t r = { x(), y(), width(), height() };
+ return r;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cairo/FontCairo.cpp b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp
new file mode 100644
index 0000000..2d79499
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "AffineTransform.h"
+#include "CairoUtilities.h"
+#include "ContextShadow.h"
+#include "GlyphBuffer.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "Pattern.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+static void prepareContextForGlyphDrawing(cairo_t* context, const SimpleFontData* font, const FloatPoint& point)
+{
+ static const float syntheticObliqueSkew = -tanf(14 * acosf(0) / 90);
+ cairo_set_scaled_font(context, font->platformData().scaledFont());
+ if (font->platformData().syntheticOblique()) {
+ cairo_matrix_t mat = {1, 0, syntheticObliqueSkew, 1, point.x(), point.y()};
+ cairo_transform(context, &mat);
+ } else
+ cairo_translate(context, point.x(), point.y());
+}
+
+static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
+{
+ cairo_show_glyphs(context, glyphs, numGlyphs);
+ if (font->syntheticBoldOffset()) {
+ // We could use cairo_save/cairo_restore here, but two translations are likely faster.
+ cairo_translate(context, font->syntheticBoldOffset(), 0);
+ cairo_show_glyphs(context, glyphs, numGlyphs);
+ cairo_translate(context, -font->syntheticBoldOffset(), 0);
+ }
+}
+
+static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
+{
+ ContextShadow* shadow = graphicsContext->contextShadow();
+ ASSERT(shadow);
+
+ if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow->m_type == ContextShadow::NoShadow)
+ return;
+
+ if (!shadow->mustUseContextShadow(graphicsContext)) {
+ // Optimize non-blurry shadows, by just drawing text without the ContextShadow.
+ cairo_save(context);
+ cairo_translate(context, shadow->m_offset.width(), shadow->m_offset.height());
+ setSourceRGBAFromColor(context, shadow->m_color);
+ prepareContextForGlyphDrawing(context, font, point);
+ cairo_show_glyphs(context, glyphs, numGlyphs);
+ cairo_restore(context);
+ return;
+ }
+
+ cairo_text_extents_t extents;
+ cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents);
+ FloatRect fontExtentsRect(point.x(), point.y() - extents.height, extents.width, extents.height);
+ cairo_t* shadowContext = shadow->beginShadowLayer(graphicsContext, fontExtentsRect);
+ if (shadowContext) {
+ prepareContextForGlyphDrawing(shadowContext, font, point);
+ drawGlyphsToContext(shadowContext, font, glyphs, numGlyphs);
+ shadow->endShadowLayer(graphicsContext);
+ }
+}
+
+void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
+
+ float offset = 0.0f;
+ for (int i = 0; i < numGlyphs; i++) {
+ glyphs[i].x = offset;
+ glyphs[i].y = 0.0f;
+ offset += glyphBuffer.advanceAt(from + i);
+ }
+
+ cairo_t* cr = context->platformContext();
+ drawGlyphsShadow(context, cr, point, font, glyphs, numGlyphs);
+
+ cairo_save(cr);
+ prepareContextForGlyphDrawing(cr, font, point);
+ if (context->textDrawingMode() & TextModeFill) {
+ if (context->fillGradient()) {
+ cairo_set_source(cr, context->fillGradient()->platformGradient());
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else if (context->fillPattern()) {
+ AffineTransform affine;
+ cairo_pattern_t* pattern = context->fillPattern()->createPlatformPattern(affine);
+ cairo_set_source(cr, pattern);
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ cairo_pattern_destroy(pattern);
+ } else {
+ float red, green, blue, alpha;
+ context->fillColor().getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
+ }
+ drawGlyphsToContext(cr, font, glyphs, numGlyphs);
+ }
+
+ // Prevent running into a long computation within cairo. If the stroke width is
+ // twice the size of the width of the text we will not ask cairo to stroke
+ // the text as even one single stroke would cover the full wdth of the text.
+ // See https://bugs.webkit.org/show_bug.cgi?id=33759.
+ if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) {
+ if (context->strokeGradient()) {
+ cairo_set_source(cr, context->strokeGradient()->platformGradient());
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else if (context->strokePattern()) {
+ AffineTransform affine;
+ cairo_pattern_t* pattern = context->strokePattern()->createPlatformPattern(affine);
+ cairo_set_source(cr, pattern);
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ cairo_pattern_destroy(pattern);
+ } else {
+ float red, green, blue, alpha;
+ context->strokeColor().getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
+ }
+ cairo_glyph_path(cr, glyphs, numGlyphs);
+ cairo_set_line_width(cr, context->strokeThickness());
+ cairo_stroke(cr);
+ }
+
+ cairo_restore(cr);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h
new file mode 100644
index 0000000..dac31f8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+typedef struct FT_FaceRec_* FT_Face;
+typedef struct _cairo_font_face cairo_font_face_t;
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+public:
+ FontCustomPlatformData(FT_Face, SharedBuffer*);
+ ~FontCustomPlatformData();
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+ static bool supportsFormat(const String&);
+
+private:
+ FT_Face m_freeTypeFace;
+ cairo_font_face_t* m_fontFace;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp b/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp
new file mode 100644
index 0000000..4e6ed07
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+#include <cairo.h>
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ if (m_gradient) {
+ cairo_pattern_destroy(m_gradient);
+ m_gradient = 0;
+ }
+}
+
+cairo_pattern_t* Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ if (m_radial)
+ m_gradient = cairo_pattern_create_radial(m_p0.x(), m_p0.y(), m_r0, m_p1.x(), m_p1.y(), m_r1);
+ else
+ m_gradient = cairo_pattern_create_linear(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y());
+
+ Vector<ColorStop>::iterator stopIterator = m_stops.begin();
+ while (stopIterator != m_stops.end()) {
+ cairo_pattern_add_color_stop_rgba(m_gradient, stopIterator->stop, stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha);
+ ++stopIterator;
+ }
+
+ switch (m_spreadMethod) {
+ case SpreadMethodPad:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_PAD);
+ break;
+ case SpreadMethodReflect:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REFLECT);
+ break;
+ case SpreadMethodRepeat:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REPEAT);
+ break;
+ }
+
+ cairo_matrix_t matrix = m_gradientSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(m_gradient, &matrix);
+
+ return m_gradient;
+}
+
+void Gradient::setPlatformGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation)
+{
+ if (m_gradient) {
+ cairo_matrix_t matrix = gradientSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(m_gradient, &matrix);
+ }
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ cairo_t* cr = context->platformContext();
+
+ context->save();
+ cairo_set_source(cr, platformGradient());
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_fill(cr);
+ context->restore();
+}
+
+} //namespace
diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
new file mode 100644
index 0000000..cdbfc57
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -0,0 +1,1149 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org>
+ * Copyright (C) 2010 Igalia S.L.
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#if PLATFORM(CAIRO)
+
+#include "AffineTransform.h"
+#include "CairoPath.h"
+#include "CairoUtilities.h"
+#include "ContextShadow.h"
+#include "FloatRect.h"
+#include "Font.h"
+#include "GraphicsContextPlatformPrivateCairo.h"
+#include "OwnPtrCairo.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "Pattern.h"
+#include "RefPtrCairo.h"
+#include "SimpleFontData.h"
+#include <cairo.h>
+#include <math.h>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+#if PLATFORM(GTK)
+#include <gdk/gdk.h>
+#include <pango/pango.h>
+#elif PLATFORM(WIN)
+#include <cairo-win32.h>
+#endif
+
+using namespace std;
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+namespace WebCore {
+
+static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr)
+{
+ cairo_pattern_t* pattern = 0;
+ cairo_save(cr);
+
+ const GraphicsContextState& state = context->state();
+ if (state.fillPattern) {
+ AffineTransform affine;
+ pattern = state.fillPattern->createPlatformPattern(affine);
+ cairo_set_source(cr, pattern);
+ } else if (state.fillGradient)
+ cairo_set_source(cr, state.fillGradient->platformGradient());
+ else
+ setSourceRGBAFromColor(cr, context->fillColor());
+ cairo_clip_preserve(cr);
+ cairo_paint_with_alpha(cr, state.globalAlpha);
+ cairo_restore(cr);
+ if (pattern)
+ cairo_pattern_destroy(pattern);
+}
+
+static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr)
+{
+ cairo_pattern_t* pattern = 0;
+ cairo_save(cr);
+
+ const GraphicsContextState& state = context->state();
+ if (state.strokePattern) {
+ AffineTransform affine;
+ pattern = state.strokePattern->createPlatformPattern(affine);
+ cairo_set_source(cr, pattern);
+ } else if (state.strokeGradient)
+ cairo_set_source(cr, state.strokeGradient->platformGradient());
+ else {
+ Color strokeColor = colorWithOverrideAlpha(context->strokeColor().rgb(), context->strokeColor().alpha() / 255.f * state.globalAlpha);
+ setSourceRGBAFromColor(cr, strokeColor);
+ }
+ if (state.globalAlpha < 1.0f && (state.strokePattern || state.strokeGradient)) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, state.globalAlpha);
+ cairo_pop_group_to_source(cr);
+ }
+ cairo_stroke_preserve(cr);
+ cairo_restore(cr);
+ if (pattern)
+ cairo_pattern_destroy(pattern);
+}
+
+// A fillRect helper
+static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col)
+{
+ setSourceRGBAFromColor(cr, col);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_fill(cr);
+}
+
+static void addConvexPolygonToContext(cairo_t* context, size_t numPoints, const FloatPoint* points)
+{
+ cairo_move_to(context, points[0].x(), points[0].y());
+ for (size_t i = 1; i < numPoints; i++)
+ cairo_line_to(context, points[i].x(), points[i].y());
+ cairo_close_path(context);
+}
+
+enum PathDrawingStyle {
+ Fill = 1,
+ Stroke = 2,
+ FillAndStroke = Fill + Stroke
+};
+
+static inline void drawPathShadow(GraphicsContext* context, PathDrawingStyle drawingStyle)
+{
+ ContextShadow* shadow = context->contextShadow();
+ ASSERT(shadow);
+ if (shadow->m_type == ContextShadow::NoShadow)
+ return;
+
+ // Calculate the extents of the rendered solid paths.
+ cairo_t* cairoContext = context->platformContext();
+ OwnPtr<cairo_path_t> path(cairo_copy_path(cairoContext));
+
+ FloatRect solidFigureExtents;
+ double x0 = 0;
+ double x1 = 0;
+ double y0 = 0;
+ double y1 = 0;
+ if (drawingStyle & Stroke) {
+ cairo_stroke_extents(cairoContext, &x0, &y0, &x1, &y1);
+ solidFigureExtents = FloatRect(x0, y0, x1 - x0, y1 - y0);
+ }
+ if (drawingStyle & Fill) {
+ cairo_fill_extents(cairoContext, &x0, &y0, &x1, &y1);
+ FloatRect fillExtents(x0, y0, x1 - x0, y1 - y0);
+ solidFigureExtents.unite(fillExtents);
+ }
+
+ cairo_t* shadowContext = shadow->beginShadowLayer(context, solidFigureExtents);
+ if (!shadowContext)
+ return;
+
+ // It's important to copy the context properties to the new shadow
+ // context to preserve things such as the fill rule and stroke width.
+ copyContextProperties(cairoContext, shadowContext);
+ cairo_append_path(shadowContext, path.get());
+
+ if (drawingStyle & Fill)
+ setPlatformFill(context, shadowContext);
+ if (drawingStyle & Stroke)
+ setPlatformStroke(context, shadowContext);
+
+ shadow->endShadowLayer(context);
+}
+
+static void fillCurrentCairoPath(GraphicsContext* context, cairo_t* cairoContext)
+{
+ cairo_set_fill_rule(cairoContext, context->fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+ drawPathShadow(context, Fill);
+
+ setPlatformFill(context, cairoContext);
+ cairo_new_path(cairoContext);
+}
+
+static void strokeCurrentCairoPath(GraphicsContext* context, cairo_t* cairoContext)
+{
+ drawPathShadow(context, Stroke);
+ setPlatformStroke(context, cairoContext);
+ cairo_new_path(cairoContext);
+}
+
+void GraphicsContext::platformInit(PlatformGraphicsContext* cr)
+{
+ m_data = new GraphicsContextPlatformPrivate;
+ m_data->cr = cairo_reference(cr);
+ m_data->syncContext(cr);
+ setPaintingDisabled(!cr);
+}
+
+void GraphicsContext::platformDestroy()
+{
+ delete m_data;
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ cairo_t* cr = platformContext();
+ cairo_matrix_t m;
+ cairo_get_matrix(cr, &m);
+ return AffineTransform(m.xx, m.yx, m.xy, m.yy, m.x0, m.y0);
+}
+
+cairo_t* GraphicsContext::platformContext() const
+{
+ return m_data->cr;
+}
+
+void GraphicsContext::savePlatformState()
+{
+ cairo_save(m_data->cr);
+ m_data->save();
+ m_data->shadowStack.append(m_data->shadow);
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ cairo_restore(m_data->cr);
+ m_data->restore();
+
+ if (m_data->shadowStack.isEmpty())
+ m_data->shadow = ContextShadow();
+ else {
+ m_data->shadow = m_data->shadowStack.last();
+ m_data->shadowStack.removeLast();
+ }
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ if (fillColor().alpha())
+ fillRectSourceOver(cr, rect, fillColor());
+
+ if (strokeStyle() != NoStroke) {
+ setSourceRGBAFromColor(cr, strokeColor());
+ FloatRect r(rect);
+ r.inflate(-.5f);
+ cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());
+ cairo_set_line_width(cr, 1.0);
+ cairo_stroke(cr);
+ }
+
+ cairo_restore(cr);
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle style = strokeStyle();
+ if (style == NoStroke)
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ float width = strokeThickness();
+ if (width < 1)
+ width = 1;
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
+
+ adjustLineToPixelBoundaries(p1, p2, width, style);
+ cairo_set_line_width(cr, width);
+
+ int patWidth = 0;
+ switch (style) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DottedStroke:
+ patWidth = static_cast<int>(width);
+ break;
+ case DashedStroke:
+ patWidth = 3*static_cast<int>(width);
+ break;
+ }
+
+ setSourceRGBAFromColor(cr, strokeColor());
+
+ cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+
+ if (patWidth) {
+ // Do a rect fill of our endpoints. This ensures we always have the
+ // appearance of being a border. We then draw the actual dotted/dashed line.
+ if (isVerticalLine) {
+ fillRectSourceOver(cr, FloatRect(p1.x() - width/2, p1.y() - width, width, width), strokeColor());
+ fillRectSourceOver(cr, FloatRect(p2.x() - width/2, p2.y(), width, width), strokeColor());
+ } else {
+ fillRectSourceOver(cr, FloatRect(p1.x() - width, p1.y() - width/2, width, width), strokeColor());
+ fillRectSourceOver(cr, FloatRect(p2.x(), p2.y() - width/2, width, width), strokeColor());
+ }
+
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*static_cast<int>(width);
+ int remainder = distance%patWidth;
+ int coverage = distance-remainder;
+ int numSegments = coverage/patWidth;
+
+ float patternOffset = 0;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0;
+ else {
+ bool evenNumberOfSegments = !(numSegments % 2);
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2;
+ } else
+ patternOffset = patWidth / 2;
+ } else if (!evenNumberOfSegments) {
+ if (remainder)
+ patternOffset = (patWidth - remainder) / 2;
+ }
+ }
+
+ double dash = patWidth;
+ cairo_set_dash(cr, &dash, 1, patternOffset);
+ }
+
+ cairo_move_to(cr, p1.x(), p1.y());
+ cairo_line_to(cr, p2.x(), p2.y());
+
+ cairo_stroke(cr);
+ cairo_restore(cr);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ float yRadius = .5 * rect.height();
+ float xRadius = .5 * rect.width();
+ cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius);
+ cairo_scale(cr, xRadius, yRadius);
+ cairo_arc(cr, 0., 0., 1., 0., 2 * M_PI);
+ cairo_restore(cr);
+
+ if (fillColor().alpha()) {
+ setSourceRGBAFromColor(cr, fillColor());
+ cairo_fill_preserve(cr);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ setSourceRGBAFromColor(cr, strokeColor());
+ cairo_set_line_width(cr, strokeThickness());
+ cairo_stroke(cr);
+ } else
+ cairo_new_path(cr);
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled() || strokeStyle() == NoStroke)
+ return;
+
+ int x = rect.x();
+ int y = rect.y();
+ float w = rect.width();
+ float h = rect.height();
+ float scaleFactor = h / w;
+ float reverseScaleFactor = w / h;
+
+ float hRadius = w / 2;
+ float vRadius = h / 2;
+ float fa = startAngle;
+ float falen = fa + angleSpan;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ if (w != h)
+ cairo_scale(cr, 1., scaleFactor);
+
+ cairo_arc_negative(cr, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, -fa * M_PI/180, -falen * M_PI/180);
+
+ if (w != h)
+ cairo_scale(cr, 1., reverseScaleFactor);
+
+ float width = strokeThickness();
+ int patWidth = 0;
+
+ switch (strokeStyle()) {
+ case DottedStroke:
+ patWidth = static_cast<int>(width / 2);
+ break;
+ case DashedStroke:
+ patWidth = 3 * static_cast<int>(width / 2);
+ break;
+ default:
+ break;
+ }
+
+ setSourceRGBAFromColor(cr, strokeColor());
+
+ if (patWidth) {
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance;
+ if (hRadius == vRadius)
+ distance = static_cast<int>((M_PI * hRadius) / 2.0);
+ else // We are elliptical and will have to estimate the distance
+ distance = static_cast<int>((M_PI * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0)) / 2.0);
+
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0;
+ else {
+ bool evenNumberOfSegments = !(numSegments % 2);
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2.0;
+ } else
+ patternOffset = patWidth / 2.0;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder) / 2.0;
+ }
+ }
+
+ double dash = patWidth;
+ cairo_set_dash(cr, &dash, 1, patternOffset);
+ }
+
+ cairo_stroke(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (npoints <= 1)
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_save(cr);
+ cairo_set_antialias(cr, shouldAntialias ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
+ addConvexPolygonToContext(cr, npoints, points);
+
+ if (fillColor().alpha()) {
+ setSourceRGBAFromColor(cr, fillColor());
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_fill_preserve(cr);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ setSourceRGBAFromColor(cr, strokeColor());
+ cairo_set_line_width(cr, strokeThickness());
+ cairo_stroke(cr);
+ } else
+ cairo_new_path(cr);
+
+ cairo_restore(cr);
+}
+
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_new_path(cr);
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_antialias_t savedAntialiasRule = cairo_get_antialias(cr);
+
+ cairo_set_antialias(cr, antialiased ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ addConvexPolygonToContext(cr, numPoints, points);
+ cairo_clip(cr);
+
+ cairo_set_antialias(cr, savedAntialiasRule);
+ cairo_set_fill_rule(cr, savedFillRule);
+}
+
+void GraphicsContext::fillPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ setPathOnCairoContext(cr, path.platformPath()->context());
+ fillCurrentCairoPath(this, cr);
+}
+
+void GraphicsContext::strokePath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ setPathOnCairoContext(cr, path.platformPath()->context());
+ strokeCurrentCairoPath(this, cr);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ fillCurrentCairoPath(this, cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ if (hasShadow())
+ m_data->shadow.drawRectShadow(this, enclosingIntRect(rect));
+
+ if (color.alpha())
+ fillRectSourceOver(m_data->cr, rect, color);
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+ m_data->clip(rect);
+}
+
+void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ setPathOnCairoContext(cr, path.platformPath()->context());
+ cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+ cairo_clip(cr);
+}
+
+static inline void adjustFocusRingColor(Color& color)
+{
+#if !PLATFORM(GTK)
+ // Force the alpha to 50%. This matches what the Mac does with outline rings.
+ color.setRGB(makeRGBA(color.red(), color.green(), color.blue(), 127));
+#endif
+}
+
+static inline void adjustFocusRingLineWidth(int& width)
+{
+#if PLATFORM(GTK)
+ width = 2;
+#endif
+}
+
+static inline StrokeStyle focusRingStrokeStyle()
+{
+#if PLATFORM(GTK)
+ return DottedStroke;
+#else
+ return SolidStroke;
+#endif
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int /* offset */, const Color& color)
+{
+ // FIXME: We should draw paths that describe a rectangle with rounded corners
+ // so as to be consistent with how we draw rectangular focus rings.
+ Color ringColor = color;
+ adjustFocusRingColor(ringColor);
+ adjustFocusRingLineWidth(width);
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ appendWebCorePathToCairoContext(cr, path);
+ setSourceRGBAFromColor(cr, ringColor);
+ cairo_set_line_width(cr, width);
+ setPlatformStrokeStyle(focusRingStrokeStyle());
+ cairo_stroke(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int /* offset */, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ unsigned rectCount = rects.size();
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ cairo_push_group(cr);
+ cairo_new_path(cr);
+
+#if PLATFORM(GTK)
+#ifdef GTK_API_VERSION_2
+ GdkRegion* reg = gdk_region_new();
+#else
+ cairo_region_t* reg = cairo_region_create();
+#endif
+
+ for (unsigned i = 0; i < rectCount; i++) {
+#ifdef GTK_API_VERSION_2
+ GdkRectangle rect = rects[i];
+ gdk_region_union_with_rect(reg, &rect);
+#else
+ cairo_rectangle_int_t rect = rects[i];
+ cairo_region_union_rectangle(reg, &rect);
+#endif
+ }
+ gdk_cairo_region(cr, reg);
+#ifdef GTK_API_VERSION_2
+ gdk_region_destroy(reg);
+#else
+ cairo_region_destroy(reg);
+#endif
+#else
+ int radius = (width - 1) / 2;
+ Path path;
+ for (unsigned i = 0; i < rectCount; ++i) {
+ if (i > 0)
+ path.clear();
+ path.addRoundedRect(rects[i], FloatSize(radius, radius));
+ appendWebCorePathToCairoContext(cr, path);
+ }
+#endif
+ Color ringColor = color;
+ adjustFocusRingColor(ringColor);
+ adjustFocusRingLineWidth(width);
+ setSourceRGBAFromColor(cr, ringColor);
+ cairo_set_line_width(cr, width);
+ setPlatformStrokeStyle(focusRingStrokeStyle());
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_stroke_preserve(cr);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ cairo_fill(cr);
+
+ cairo_pop_group_to_source(cr);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_paint(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ IntPoint endPoint = origin + IntSize(width, 0);
+ drawLine(origin, endPoint);
+}
+
+#if !PLATFORM(GTK)
+#include "DrawErrorUnderline.h"
+#endif
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ switch (style) {
+ case TextCheckingSpellingLineStyle:
+ cairo_set_source_rgb(cr, 1, 0, 0);
+ break;
+ case TextCheckingGrammarLineStyle:
+ cairo_set_source_rgb(cr, 0, 1, 0);
+ break;
+ default:
+ cairo_restore(cr);
+ return;
+ }
+
+#if PLATFORM(GTK)
+ // We ignore most of the provided constants in favour of the platform style
+ pango_cairo_show_error_underline(cr, origin.x(), origin.y(), width, cMisspellingLineThickness);
+#else
+ drawErrorUnderline(cr, origin.x(), origin.y(), width, cMisspellingLineThickness);
+#endif
+
+ cairo_restore(cr);
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ FloatRect result;
+ double x = frect.x();
+ double y = frect.y();
+ cairo_t* cr = m_data->cr;
+ cairo_user_to_device(cr, &x, &y);
+ x = round(x);
+ y = round(y);
+ cairo_device_to_user(cr, &x, &y);
+ result.setX(static_cast<float>(x));
+ result.setY(static_cast<float>(y));
+ x = frect.width();
+ y = frect.height();
+ cairo_user_to_device_distance(cr, &x, &y);
+ x = round(x);
+ y = round(y);
+ cairo_device_to_user_distance(cr, &x, &y);
+ result.setWidth(static_cast<float>(x));
+ result.setHeight(static_cast<float>(y));
+ return result;
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_translate(cr, x, y);
+ m_data->translate(x, y);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace)
+{
+ // Cairo contexts can't hold separate fill and stroke colors
+ // so we set them just before we actually fill or stroke
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace)
+{
+ // Cairo contexts can't hold separate fill and stroke colors
+ // so we set them just before we actually fill or stroke
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_set_line_width(m_data->cr, strokeThickness);
+}
+
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle)
+{
+ static double dashPattern[] = {5.0, 5.0};
+ static double dotPattern[] = {1.0, 1.0};
+
+ if (paintingDisabled())
+ return;
+
+ switch (strokeStyle) {
+ case NoStroke:
+ // FIXME: is it the right way to emulate NoStroke?
+ cairo_set_line_width(m_data->cr, 0);
+ break;
+ case SolidStroke:
+ cairo_set_dash(m_data->cr, 0, 0, 0);
+ break;
+ case DottedStroke:
+ cairo_set_dash(m_data->cr, dotPattern, 2, 0);
+ break;
+ case DashedStroke:
+ cairo_set_dash(m_data->cr, dashPattern, 2, 0);
+ break;
+ }
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ notImplemented();
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ const cairo_matrix_t matrix = cairo_matrix_t(transform);
+ cairo_transform(cr, &matrix);
+ m_data->concatCTM(transform);
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ clip(rect);
+
+ Path p;
+ FloatRect r(rect);
+ // Add outer ellipse
+ p.addEllipse(r);
+ // Add inner ellipse
+ r.inflate(-thickness);
+ p.addEllipse(r);
+ appendWebCorePathToCairoContext(cr, p);
+
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+}
+
+void GraphicsContext::setPlatformShadow(FloatSize const& size, float blur, Color const& color, ColorSpace)
+{
+ // Cairo doesn't support shadows natively, they are drawn manually in the draw* functions
+ if (m_state.shadowsIgnoreTransforms) {
+ // Meaning that this graphics context is associated with a CanvasRenderingContext
+ // We flip the height since CG and HTML5 Canvas have opposite Y axis
+ m_state.shadowOffset = FloatSize(size.width(), -size.height());
+ m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
+ } else
+ m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
+
+ m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
+}
+
+ContextShadow* GraphicsContext::contextShadow()
+{
+ return &m_data->shadow;
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ m_data->shadow.clear();
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_push_group(cr);
+ m_data->layers.append(opacity);
+ m_data->beginTransparencyLayer();
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_pop_group_to_source(cr);
+ cairo_paint_with_alpha(cr, m_data->layers.last());
+ m_data->layers.removeLast();
+ m_data->endTransparencyLayer();
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_save(cr);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+ cairo_fill(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float width)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_set_line_width(cr, width);
+ strokeCurrentCairoPath(this, cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::setLineCap(LineCap lineCap)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_line_cap_t cairoCap = CAIRO_LINE_CAP_BUTT;
+ switch (lineCap) {
+ case ButtCap:
+ // no-op
+ break;
+ case RoundCap:
+ cairoCap = CAIRO_LINE_CAP_ROUND;
+ break;
+ case SquareCap:
+ cairoCap = CAIRO_LINE_CAP_SQUARE;
+ break;
+ }
+ cairo_set_line_cap(m_data->cr, cairoCap);
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ cairo_set_dash(m_data->cr, dashes.data(), dashes.size(), dashOffset);
+}
+
+void GraphicsContext::setLineJoin(LineJoin lineJoin)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_line_join_t cairoJoin = CAIRO_LINE_JOIN_MITER;
+ switch (lineJoin) {
+ case MiterJoin:
+ // no-op
+ break;
+ case RoundJoin:
+ cairoJoin = CAIRO_LINE_JOIN_ROUND;
+ break;
+ case BevelJoin:
+ cairoJoin = CAIRO_LINE_JOIN_BEVEL;
+ break;
+ }
+ cairo_set_line_join(m_data->cr, cairoJoin);
+}
+
+void GraphicsContext::setMiterLimit(float miter)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_set_miter_limit(m_data->cr, miter);
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ m_state.globalAlpha = alpha;
+}
+
+float GraphicsContext::getAlpha()
+{
+ return m_state.globalAlpha;
+}
+
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_set_operator(m_data->cr, toCairoOperator(op));
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ OwnPtr<cairo_path_t> p(cairo_copy_path(path.platformPath()->context()));
+ cairo_append_path(cr, p.get());
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+ m_data->clip(path);
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ double x1, y1, x2, y2;
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+ cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
+ appendWebCorePathToCairoContext(cr, path);
+
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_rotate(m_data->cr, radians);
+ m_data->rotate(radians);
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_scale(m_data->cr, size.width(), size.height());
+ m_data->scale(size);
+}
+
+void GraphicsContext::clipOut(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ double x1, y1, x2, y2;
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+ cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
+ cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+}
+
+static inline FloatPoint getPhase(const FloatRect& dest, const FloatRect& tile)
+{
+ FloatPoint phase = dest.location();
+ phase.move(-tile.x(), -tile.y());
+
+ return phase;
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ if (hasShadow())
+ m_data->shadow.drawRectShadow(this, r, topLeft, topRight, bottomLeft, bottomRight);
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ Path path;
+ path.addRoundedRect(r, topLeft, topRight, bottomLeft, bottomRight);
+ appendWebCorePathToCairoContext(cr, path);
+ setSourceRGBAFromColor(cr, color);
+ cairo_fill(cr);
+ cairo_restore(cr);
+}
+
+#if PLATFORM(GTK)
+void GraphicsContext::setGdkExposeEvent(GdkEventExpose* expose)
+{
+ m_data->expose = expose;
+}
+
+GdkEventExpose* GraphicsContext::gdkExposeEvent() const
+{
+ return m_data->expose;
+}
+
+GdkWindow* GraphicsContext::gdkWindow() const
+{
+ if (!m_data->expose)
+ return 0;
+
+ return m_data->expose->window;
+}
+#endif
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+
+ // When true, use the default Cairo backend antialias mode (usually this
+ // enables standard 'grayscale' antialiasing); false to explicitly disable
+ // antialiasing. This is the same strategy as used in drawConvexPolygon().
+ cairo_set_antialias(m_data->cr, enable ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ return InterpolationDefault;
+}
+
+} // namespace WebCore
+
+#endif // PLATFORM(CAIRO)
diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
new file mode 100644
index 0000000..5602b6c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Brent Fulgham <bfulgham@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "GraphicsContext.h"
+
+#include "ContextShadow.h"
+#include <cairo.h>
+#include <math.h>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+#if PLATFORM(GTK)
+#include <pango/pango.h>
+typedef struct _GdkExposeEvent GdkExposeEvent;
+#elif PLATFORM(WIN)
+#include <cairo-win32.h>
+#endif
+
+namespace WebCore {
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContextPlatformPrivate()
+ : cr(0)
+#if PLATFORM(GTK)
+ , expose(0)
+#elif PLATFORM(WIN)
+ // NOTE: These may note be needed: review and remove once Cairo implementation is complete
+ , m_hdc(0)
+ , m_transparencyCount(0)
+ , m_shouldIncludeChildWindows(false)
+#endif
+ {
+ }
+
+ ~GraphicsContextPlatformPrivate()
+ {
+ cairo_destroy(cr);
+ }
+
+#if PLATFORM(WIN)
+ // On Windows, we need to update the HDC for form controls to draw in the right place.
+ void save();
+ void restore();
+ void flush();
+ void clip(const FloatRect&);
+ void clip(const Path&);
+ void scale(const FloatSize&);
+ void rotate(float);
+ void translate(float, float);
+ void concatCTM(const AffineTransform&);
+ void concatCTM(const TransformationMatrix&);
+ void beginTransparencyLayer() { m_transparencyCount++; }
+ void endTransparencyLayer() { m_transparencyCount--; }
+ void syncContext(PlatformGraphicsContext* cr);
+#else
+ // On everything else, we do nothing.
+ void save() {}
+ void restore() {}
+ void flush() {}
+ void clip(const FloatRect&) {}
+ void clip(const Path&) {}
+ void scale(const FloatSize&) {}
+ void rotate(float) {}
+ void translate(float, float) {}
+ void concatCTM(const AffineTransform&) {}
+ void concatCTM(const TransformationMatrix&) {}
+ void beginTransparencyLayer() {}
+ void endTransparencyLayer() {}
+ void syncContext(PlatformGraphicsContext* cr) {}
+#endif
+
+ cairo_t* cr;
+ Vector<float> layers;
+
+ ContextShadow shadow;
+ Vector<ContextShadow> shadowStack;
+
+#if PLATFORM(GTK)
+ GdkEventExpose* expose;
+#elif PLATFORM(WIN)
+ HDC m_hdc;
+ unsigned m_transparencyCount;
+ bool m_shouldIncludeChildWindows;
+#endif
+};
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
new file mode 100644
index 0000000..ac5da3d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Holger Hans Peter Freyther <zecke@selfish.org>
+ * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "Base64.h"
+#include "BitmapImage.h"
+#include "Color.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "Pattern.h"
+#include "PlatformString.h"
+#include <cairo.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+// Cairo doesn't provide a way to copy a cairo_surface_t.
+// See http://lists.cairographics.org/archives/cairo/2007-June/010877.html
+// Once cairo provides the way, use the function instead of this.
+static inline cairo_surface_t* copySurface(cairo_surface_t* surface)
+{
+ cairo_format_t format = cairo_image_surface_get_format(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ cairo_surface_t* newsurface = cairo_image_surface_create(format, width, height);
+
+ cairo_t* cr = cairo_create(newsurface);
+ cairo_set_source_surface(cr, surface, 0, 0);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+
+ return newsurface;
+}
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_surface(0)
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ success = false; // Make early return mean error.
+ m_data.m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ size.width(),
+ size.height());
+ if (cairo_surface_status(m_data.m_surface) != CAIRO_STATUS_SUCCESS)
+ return; // create will notice we didn't set m_initialized and fail.
+
+ cairo_t* cr = cairo_create(m_data.m_surface);
+ m_context.set(new GraphicsContext(cr));
+ cairo_destroy(cr); // The context is now owned by the GraphicsContext.
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+ cairo_surface_destroy(m_data.m_surface);
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+bool ImageBuffer::drawsUsingCopy() const
+{
+ return false;
+}
+
+PassRefPtr<Image> ImageBuffer::copyImage() const
+{
+ // BitmapImage will release the passed in surface on destruction
+ return BitmapImage::create(copySurface(m_data.m_surface));
+}
+
+void ImageBuffer::clip(GraphicsContext*, const FloatRect&) const
+{
+ notImplemented();
+ // See https://bugs.webkit.org/show_bug.cgi?id=23526 for why this is unimplemented.
+}
+
+void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
+ CompositeOperator op , bool useLowQualityScale)
+{
+ // BitmapImage will release the passed in surface on destruction
+ RefPtr<Image> image = BitmapImage::create(cairo_surface_reference(m_data.m_surface));
+ context->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
+}
+
+void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ // BitmapImage will release the passed in surface on destruction
+ RefPtr<Image> image = BitmapImage::create(cairo_surface_reference(m_data.m_surface));
+ image->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface);
+ int stride = cairo_image_surface_get_stride(m_data.m_surface);
+ for (int y = 0; y < m_size.height(); ++y) {
+ unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * y);
+ for (int x = 0; x < m_size.width(); x++) {
+ unsigned* pixel = row + x;
+ Color pixelColor = colorFromPremultipliedARGB(*pixel);
+ pixelColor = Color(lookUpTable[pixelColor.red()],
+ lookUpTable[pixelColor.green()],
+ lookUpTable[pixelColor.blue()],
+ pixelColor.alpha());
+ *pixel = premultipliedARGBFromColor(pixelColor);
+ }
+ }
+ cairo_surface_mark_dirty_rectangle (m_data.m_surface, 0, 0, m_size.width(), m_size.height());
+}
+
+template <Multiply multiplied>
+PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& data, const IntSize& size)
+{
+ ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4);
+ unsigned char* dataSrc = cairo_image_surface_get_data(data.m_surface);
+ unsigned char* dataDst = result->data();
+
+ if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height())
+ memset(dataDst, 0, result->length());
+
+ int originx = rect.x();
+ int destx = 0;
+ if (originx < 0) {
+ destx = -originx;
+ originx = 0;
+ }
+ int endx = rect.right();
+ if (endx > size.width())
+ endx = size.width();
+ int numColumns = endx - originx;
+
+ int originy = rect.y();
+ int desty = 0;
+ if (originy < 0) {
+ desty = -originy;
+ originy = 0;
+ }
+ int endy = rect.bottom();
+ if (endy > size.height())
+ endy = size.height();
+ int numRows = endy - originy;
+
+ int stride = cairo_image_surface_get_stride(data.m_surface);
+ unsigned destBytesPerRow = 4 * rect.width();
+
+ unsigned char* destRows = dataDst + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * (y + originy));
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ unsigned* pixel = row + x + originx;
+ Color pixelColor;
+ if (multiplied == Unmultiplied)
+ pixelColor = colorFromPremultipliedARGB(*pixel);
+ else
+ pixelColor = Color(*pixel);
+ destRows[basex] = pixelColor.red();
+ destRows[basex + 1] = pixelColor.green();
+ destRows[basex + 2] = pixelColor.blue();
+ destRows[basex + 3] = pixelColor.alpha();
+ }
+ destRows += destBytesPerRow;
+ }
+
+ return result.release();
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<Unmultiplied>(rect, m_data, m_size);
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<Premultiplied>(rect, m_data, m_size);
+}
+
+template <Multiply multiplied>
+void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size)
+{
+ ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ unsigned char* dataDst = cairo_image_surface_get_data(data.m_surface);
+
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originx = sourceRect.x();
+ int destx = destPoint.x() + sourceRect.x();
+ ASSERT(destx >= 0);
+ ASSERT(destx < size.width());
+ ASSERT(originx >= 0);
+ ASSERT(originx <= sourceRect.right());
+
+ int endx = destPoint.x() + sourceRect.right();
+ ASSERT(endx <= size.width());
+
+ int numColumns = endx - destx;
+
+ int originy = sourceRect.y();
+ int desty = destPoint.y() + sourceRect.y();
+ ASSERT(desty >= 0);
+ ASSERT(desty < size.height());
+ ASSERT(originy >= 0);
+ ASSERT(originy <= sourceRect.bottom());
+
+ int endy = destPoint.y() + sourceRect.bottom();
+ ASSERT(endy <= size.height());
+ int numRows = endy - desty;
+
+ unsigned srcBytesPerRow = 4 * sourceSize.width();
+ int stride = cairo_image_surface_get_stride(data.m_surface);
+
+ unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ unsigned* row = reinterpret_cast<unsigned*>(dataDst + stride * (y + desty));
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ unsigned* pixel = row + x + destx;
+ Color pixelColor(srcRows[basex],
+ srcRows[basex + 1],
+ srcRows[basex + 2],
+ srcRows[basex + 3]);
+ if (multiplied == Unmultiplied)
+ *pixel = premultipliedARGBFromColor(pixelColor);
+ else
+ *pixel = pixelColor.rgb();
+ }
+ srcRows += srcBytesPerRow;
+ }
+ cairo_surface_mark_dirty_rectangle (data.m_surface,
+ destx, desty,
+ numColumns, numRows);
+}
+
+void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
+}
+
+void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
+}
+
+#if !PLATFORM(GTK)
+static cairo_status_t writeFunction(void* closure, const unsigned char* data, unsigned int length)
+{
+ Vector<char>* in = reinterpret_cast<Vector<char>*>(closure);
+ in->append(data, length);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+String ImageBuffer::toDataURL(const String& mimeType, const double*) const
+{
+ cairo_surface_t* image = cairo_get_target(context()->platformContext());
+ if (!image)
+ return "data:,";
+
+ String actualMimeType("image/png");
+ if (MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType))
+ actualMimeType = mimeType;
+
+ Vector<char> in;
+ // Only PNG output is supported for now.
+ cairo_surface_write_to_png_stream(image, writeFunction, &in);
+
+ Vector<char> out;
+ base64Encode(in, out);
+
+ return "data:" + actualMimeType + ";base64," + String(out.data(), out.size());
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferData.h b/Source/WebCore/platform/graphics/cairo/ImageBufferData.h
new file mode 100644
index 0000000..49f15df
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/ImageBufferData.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ImageBufferData_h
+#define ImageBufferData_h
+
+#include "cairo.h"
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ cairo_surface_t* m_surface;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp
new file mode 100644
index 0000000..e51d65a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "BitmapImage.h"
+
+#if PLATFORM(CAIRO)
+
+#include "AffineTransform.h"
+#include "CairoUtilities.h"
+#include "Color.h"
+#include "ContextShadow.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "ImageObserver.h"
+#include "RefPtrCairo.h"
+#include <cairo.h>
+#include <math.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ cairo_surface_destroy(m_frame);
+ m_frame = 0;
+ return true;
+ }
+ return false;
+}
+
+BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
+ , m_animationFinished(true)
+ , m_allDataReceived(true)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ // TODO: check to be sure this is an image surface
+
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ m_decodedSize = width * height * 4;
+ m_size = IntSize(width, height);
+
+ m_frames.grow(1);
+ m_frames[0].m_frame = surface;
+ m_frames[0].m_hasAlpha = cairo_surface_get_content(surface) != CAIRO_CONTENT_COLOR;
+ m_frames[0].m_haveMetadata = true;
+ checkForSolidColor();
+}
+
+void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ FloatRect srcRect(src);
+ FloatRect dstRect(dst);
+
+ if (dstRect.width() == 0.0f || dstRect.height() == 0.0f ||
+ srcRect.width() == 0.0f || srcRect.height() == 0.0f)
+ return;
+
+ startAnimation();
+
+ cairo_surface_t* image = frameAtIndex(m_currentFrame);
+ if (!image) // If it's too early we won't have an image yet.
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(context, dstRect, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+ IntSize selfSize = size();
+
+ cairo_t* cr = context->platformContext();
+ context->save();
+
+ // Set the compositing operation.
+ if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame))
+ context->setCompositeOperation(CompositeCopy);
+ else
+ context->setCompositeOperation(op);
+
+ // If we're drawing a sub portion of the image or scaling then create
+ // a pattern transformation on the image and draw the transformed pattern.
+ // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
+
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
+
+ float scaleX = srcRect.width() / dstRect.width();
+ float scaleY = srcRect.height() / dstRect.height();
+ cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() };
+ cairo_pattern_set_matrix(pattern, &matrix);
+
+ ContextShadow* shadow = context->contextShadow();
+ ASSERT(shadow);
+ if (shadow->m_type != ContextShadow::NoShadow) {
+ cairo_t* shadowContext = shadow->beginShadowLayer(context, dstRect);
+ if (shadowContext) {
+ cairo_translate(shadowContext, dstRect.x(), dstRect.y());
+ cairo_set_source(shadowContext, pattern);
+ cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height());
+ cairo_fill(shadowContext);
+ shadow->endShadowLayer(context);
+ }
+ }
+
+ // Draw the image.
+ cairo_translate(cr, dstRect.x(), dstRect.y());
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+ cairo_rectangle(cr, 0, 0, dstRect.width(), dstRect.height());
+ cairo_clip(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+
+ context->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace colorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ cairo_surface_t* image = nativeImageForCurrentFrame();
+ if (!image) // If it's too early we won't have an image yet.
+ return;
+
+ cairo_t* cr = context->platformContext();
+
+ drawPatternToCairoContext(cr, image, size(), tileRect, patternTransform, phase, toCairoOperator(op), destRect);
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_isSolidColor = false;
+ m_checkedForSolidColor = true;
+
+ if (frameCount() > 1)
+ return;
+
+ cairo_surface_t* frameSurface = frameAtIndex(0);
+ if (!frameSurface)
+ return;
+
+ ASSERT(cairo_surface_get_type(frameSurface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ int width = cairo_image_surface_get_width(frameSurface);
+ int height = cairo_image_surface_get_height(frameSurface);
+
+ if (width != 1 || height != 1)
+ return;
+
+ unsigned* pixelColor = reinterpret_cast<unsigned*>(cairo_image_surface_get_data(frameSurface));
+ m_solidColor = colorFromPremultipliedARGB(*pixelColor);
+
+ m_isSolidColor = true;
+}
+
+}
+
+#endif // PLATFORM(CAIRO)
diff --git a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp
new file mode 100644
index 0000000..94f6809
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "OwnPtrCairo.h"
+
+#if defined(USE_FREETYPE)
+#include <cairo-ft.h>
+#include <fontconfig/fcfreetype.h>
+#endif
+
+#include <cairo.h>
+
+namespace WTF {
+
+#if defined(USE_FREETYPE)
+template <> void deleteOwnedPtr<FcObjectSet>(FcObjectSet* ptr)
+{
+ if (ptr)
+ FcObjectSetDestroy(ptr);
+}
+
+template <> void deleteOwnedPtr<FcFontSet>(FcFontSet* ptr)
+{
+ if (ptr)
+ FcFontSetDestroy(ptr);
+}
+#endif
+
+template <> void deleteOwnedPtr<cairo_path_t>(cairo_path_t* ptr)
+{
+ if (ptr)
+ cairo_path_destroy(ptr);
+}
+
+} // namespace WTF
diff --git a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h
new file mode 100644
index 0000000..035d80e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef OwnPtrCairo_h
+#define OwnPtrCairo_h
+
+#include "OwnPtr.h"
+
+#if defined(USE_FREETYPE)
+typedef struct _FcObjectSet FcObjectSet;
+typedef struct _FcFontSet FcFontSet;
+#endif
+
+typedef struct cairo_path cairo_path_t;
+
+namespace WTF {
+
+#if defined(USE_FREETYPE)
+template <> void deleteOwnedPtr<FcObjectSet>(FcObjectSet*);
+template <> void deleteOwnedPtr<FcFontSet>(FcFontSet*);
+#endif
+
+template <> void deleteOwnedPtr<cairo_path_t>(cairo_path_t*);
+
+} // namespace WTF
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cairo/PathCairo.cpp b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp
new file mode 100644
index 0000000..03f1d10
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp
@@ -0,0 +1,342 @@
+/*
+ Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+ Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org>
+ 2004, 2005, 2006 Rob Buis <buis@kde.org>
+ 2005, 2007 Apple Inc. All Rights reserved.
+ 2007 Alp Toker <alp@atoker.com>
+ 2008 Dirk Schulze <krit@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "CairoPath.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "OwnPtrCairo.h"
+#include "PlatformString.h"
+#include "StrokeStyleApplier.h"
+#include <cairo.h>
+#include <math.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+Path::Path()
+ : m_path(new CairoPath())
+{
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path::Path(const Path& other)
+ : m_path(new CairoPath())
+{
+ cairo_t* cr = platformPath()->context();
+ OwnPtr<cairo_path_t> p(cairo_copy_path(other.platformPath()->context()));
+ cairo_append_path(cr, p.get());
+}
+
+Path& Path::operator=(const Path& other)
+{
+ if (&other == this)
+ return *this;
+
+ clear();
+ cairo_t* cr = platformPath()->context();
+ OwnPtr<cairo_path_t> p(cairo_copy_path(other.platformPath()->context()));
+ cairo_append_path(cr, p.get());
+ return *this;
+}
+
+void Path::clear()
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_new_path(cr);
+}
+
+bool Path::isEmpty() const
+{
+ return !cairo_has_current_point(platformPath()->context());
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
+
+FloatPoint Path::currentPoint() const
+{
+ // FIXME: Is this the correct way?
+ double x;
+ double y;
+ cairo_get_current_point(platformPath()->context(), &x, &y);
+ return FloatPoint(x, y);
+}
+
+void Path::translate(const FloatSize& p)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_translate(cr, -p.width(), -p.height());
+}
+
+void Path::moveTo(const FloatPoint& p)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_move_to(cr, p.x(), p.y());
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_line_to(cr, p.x(), p.y());
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+/*
+ * inspired by libsvg-cairo
+ */
+void Path::addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point)
+{
+ cairo_t* cr = platformPath()->context();
+ double x, y;
+ double x1 = controlPoint.x();
+ double y1 = controlPoint.y();
+ double x2 = point.x();
+ double y2 = point.y();
+ cairo_get_current_point(cr, &x, &y);
+ cairo_curve_to(cr,
+ x + 2.0 / 3.0 * (x1 - x), y + 2.0 / 3.0 * (y1 - y),
+ x2 + 2.0 / 3.0 * (x1 - x2), y2 + 2.0 / 3.0 * (y1 - y2),
+ x2, y2);
+}
+
+void Path::addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& controlPoint3)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_curve_to(cr, controlPoint1.x(), controlPoint1.y(),
+ controlPoint2.x(), controlPoint2.y(),
+ controlPoint3.x(), controlPoint3.y());
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlockwise)
+{
+ // http://bugs.webkit.org/show_bug.cgi?id=16449
+ // cairo_arc() functions hang or crash when passed inf as radius or start/end angle
+ if (!isfinite(r) || !isfinite(sa) || !isfinite(ea))
+ return;
+
+ cairo_t* cr = platformPath()->context();
+ if (anticlockwise)
+ cairo_arc_negative(cr, p.x(), p.y(), r, sa, ea);
+ else
+ cairo_arc(cr, p.x(), p.y(), r, sa, ea);
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ if (isEmpty())
+ return;
+
+ cairo_t* cr = platformPath()->context();
+
+ double x0, y0;
+ cairo_get_current_point(cr, &x0, &y0);
+ FloatPoint p0(x0, y0);
+ if ((p1.x() == p0.x() && p1.y() == p0.y()) || (p1.x() == p2.x() && p1.y() == p2.y()) || radius == 0.f) {
+ cairo_line_to(cr, p1.x(), p1.y());
+ return;
+ }
+
+ FloatPoint p1p0((p0.x() - p1.x()),(p0.y() - p1.y()));
+ FloatPoint p1p2((p2.x() - p1.x()),(p2.y() - p1.y()));
+ float p1p0_length = sqrtf(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
+ float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+
+ double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+ // all points on a line logic
+ if (cos_phi == -1) {
+ cairo_line_to(cr, p1.x(), p1.y());
+ return;
+ }
+ if (cos_phi == 1) {
+ // add infinite far away point
+ unsigned int max_length = 65535;
+ double factor_max = max_length / p1p0_length;
+ FloatPoint ep((p0.x() + factor_max * p1p0.x()), (p0.y() + factor_max * p1p0.y()));
+ cairo_line_to(cr, ep.x(), ep.y());
+ return;
+ }
+
+ float tangent = radius / tan(acos(cos_phi) / 2);
+ float factor_p1p0 = tangent / p1p0_length;
+ FloatPoint t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
+
+ FloatPoint orth_p1p0(p1p0.y(), -p1p0.x());
+ float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
+ float factor_ra = radius / orth_p1p0_length;
+
+ // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
+ double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ if (cos_alpha < 0.f)
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+
+ FloatPoint p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
+
+ // calculate angles for addArc
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+ float sa = acos(orth_p1p0.x() / orth_p1p0_length);
+ if (orth_p1p0.y() < 0.f)
+ sa = 2 * piDouble - sa;
+
+ // anticlockwise logic
+ bool anticlockwise = false;
+
+ float factor_p1p2 = tangent / p1p2_length;
+ FloatPoint t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
+ FloatPoint orth_p1p2((t_p1p2.x() - p.x()),(t_p1p2.y() - p.y()));
+ float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
+ float ea = acos(orth_p1p2.x() / orth_p1p2_length);
+ if (orth_p1p2.y() < 0)
+ ea = 2 * piDouble - ea;
+ if ((sa > ea) && ((sa - ea) < piDouble))
+ anticlockwise = true;
+ if ((sa < ea) && ((ea - sa) > piDouble))
+ anticlockwise = true;
+
+ cairo_line_to(cr, t_p1p0.x(), t_p1p0.y());
+
+ addArc(p, radius, sa, ea, anticlockwise);
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_save(cr);
+ float yRadius = .5 * rect.height();
+ float xRadius = .5 * rect.width();
+ cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius);
+ cairo_scale(cr, xRadius, yRadius);
+ cairo_arc(cr, 0., 0., 1., 0., 2 * piDouble);
+ cairo_restore(cr);
+}
+
+void Path::closeSubpath()
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_close_path(cr);
+}
+
+FloatRect Path::boundingRect() const
+{
+ cairo_t* cr = platformPath()->context();
+ double x0, x1, y0, y1;
+ cairo_path_extents(cr, &x0, &y0, &x1, &y1);
+ return FloatRect(x0, y0, x1 - x0, y1 - y0);
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ cairo_t* cr = platformPath()->context();
+ if (applier) {
+ GraphicsContext gc(cr);
+ applier->strokeStyle(&gc);
+ }
+
+ double x0, x1, y0, y1;
+ cairo_stroke_extents(cr, &x0, &y0, &x1, &y1);
+ return FloatRect(x0, y0, x1 - x0, y1 - y0);
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ if (!isfinite(point.x()) || !isfinite(point.y()))
+ return false;
+ cairo_t* cr = platformPath()->context();
+ cairo_fill_rule_t cur = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, rule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+ bool contains = cairo_in_fill(cr, point.x(), point.y());
+ cairo_set_fill_rule(cr, cur);
+ return contains;
+}
+
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+ cairo_t* cr = platformPath()->context();
+ GraphicsContext gc(cr);
+ applier->strokeStyle(&gc);
+
+ return cairo_in_stroke(cr, point.x(), point.y());
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ cairo_t* cr = platformPath()->context();
+ OwnPtr<cairo_path_t> path(cairo_copy_path(cr));
+ cairo_path_data_t* data;
+ PathElement pelement;
+ FloatPoint points[3];
+ pelement.points = points;
+
+ for (int i = 0; i < path->num_data; i += path->data[i].header.length) {
+ data = &path->data[i];
+ switch (data->header.type) {
+ case CAIRO_PATH_MOVE_TO:
+ pelement.type = PathElementMoveToPoint;
+ pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y);
+ function(info, &pelement);
+ break;
+ case CAIRO_PATH_LINE_TO:
+ pelement.type = PathElementAddLineToPoint;
+ pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y);
+ function(info, &pelement);
+ break;
+ case CAIRO_PATH_CURVE_TO:
+ pelement.type = PathElementAddCurveToPoint;
+ pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y);
+ pelement.points[1] = FloatPoint(data[2].point.x,data[2].point.y);
+ pelement.points[2] = FloatPoint(data[3].point.x,data[3].point.y);
+ function(info, &pelement);
+ break;
+ case CAIRO_PATH_CLOSE_PATH:
+ pelement.type = PathElementCloseSubpath;
+ function(info, &pelement);
+ break;
+ }
+ }
+}
+
+void Path::transform(const AffineTransform& trans)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_matrix_t c_matrix = cairo_matrix_t(trans);
+ cairo_matrix_invert(&c_matrix);
+ cairo_transform(cr, &c_matrix);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp b/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp
new file mode 100644
index 0000000..b067acc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Pattern.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+cairo_pattern_t* Pattern::createPlatformPattern(const AffineTransform&) const
+{
+ cairo_surface_t* surface = tileImage()->nativeImageForCurrentFrame();
+ if (!surface)
+ return 0;
+
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
+
+ // cairo merges patter space and user space itself
+ cairo_matrix_t matrix = m_patternSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(pattern, &matrix);
+
+ if (m_repeatX || m_repeatY)
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+ return pattern;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp
new file mode 100644
index 0000000..c8b242c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "RefPtrCairo.h"
+
+#include <cairo.h>
+
+#if defined(USE_FREETYPE)
+#include <cairo-ft.h>
+#include <fontconfig/fcfreetype.h>
+#endif
+
+namespace WTF {
+
+template<> void refIfNotNull(cairo_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_destroy(ptr);
+}
+
+template<> void refIfNotNull(cairo_surface_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_surface_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_surface_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_surface_destroy(ptr);
+}
+
+template<> void refIfNotNull(cairo_font_face_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_font_face_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_font_face_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_font_face_reference(ptr);
+}
+
+template<> void refIfNotNull(cairo_scaled_font_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_scaled_font_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_scaled_font_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_scaled_font_destroy(ptr);
+}
+
+template<> void refIfNotNull(cairo_pattern_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_pattern_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_pattern_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_pattern_destroy(ptr);
+}
+
+#if defined(USE_FREETYPE)
+template<> void refIfNotNull(FcPattern* ptr)
+{
+ if (LIKELY(ptr != 0))
+ FcPatternReference(ptr);
+}
+
+template<> void derefIfNotNull(FcPattern* ptr)
+{
+ if (LIKELY(ptr != 0))
+ FcPatternDestroy(ptr);
+}
+
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h
new file mode 100644
index 0000000..204d1e3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef RefPtrCairo_h
+#define RefPtrCairo_h
+
+#include "RefPtr.h"
+
+typedef struct _cairo cairo_t;
+typedef struct _cairo_surface cairo_surface_t;
+typedef struct _cairo_font_face cairo_font_face_t;
+typedef struct _cairo_scaled_font cairo_scaled_font_t;
+typedef struct _cairo_pattern cairo_pattern_t;
+
+#if defined(USE_FREETYPE)
+typedef struct _FcPattern FcPattern;
+#endif
+
+namespace WTF {
+
+template<> void refIfNotNull(cairo_t* ptr);
+template<> void derefIfNotNull(cairo_t* ptr);
+
+template<> void refIfNotNull(cairo_surface_t* ptr);
+template<> void derefIfNotNull(cairo_surface_t* ptr);
+
+template<> void refIfNotNull(cairo_font_face_t* ptr);
+template<> void derefIfNotNull(cairo_font_face_t* ptr);
+
+template<> void refIfNotNull(cairo_scaled_font_t* ptr);
+template<> void derefIfNotNull(cairo_scaled_font_t* ptr);
+
+template<> void refIfNotNull(cairo_pattern_t*);
+template<> void derefIfNotNull(cairo_pattern_t*);
+
+#if defined(USE_FREETYPE)
+template<> void refIfNotNull(FcPattern* ptr);
+template<> void derefIfNotNull(FcPattern* ptr);
+#endif
+
+}
+
+#endif // RefPtrCairo_h
diff --git a/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp b/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
new file mode 100644
index 0000000..c73dd02
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+#include "TransformationMatrix.h"
+
+#include "IntRect.h"
+#include "FloatRect.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+TransformationMatrix::operator cairo_matrix_t() const
+{
+ cairo_matrix_t m;
+
+ cairo_matrix_init (&m,
+ a(),
+ b(),
+ c(),
+ d(),
+ e(),
+ f());
+ return m;
+}
+
+AffineTransform::operator cairo_matrix_t() const
+{
+ cairo_matrix_t m;
+
+ cairo_matrix_init (&m,
+ a(),
+ b(),
+ c(),
+ d(),
+ e(),
+ f());
+ return m;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/cairo/rgb24-hacks.txt b/Source/WebCore/platform/graphics/cairo/rgb24-hacks.txt
new file mode 100644
index 0000000..59f8070
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/rgb24-hacks.txt
@@ -0,0 +1,32 @@
+Index: cairo/src/cairo-win32-surface.c
+===================================================================
+--- cairo/src/cairo-win32-surface.c (revision 14498)
++++ cairo/src/cairo-win32-surface.c (working copy)
+@@ -824,8 +824,13 @@
+ * to figure out when we can use GDI. We don't have that checking
+ * anywhere at the moment, so just bail and use the fallback
+ * paths. */
+- if (surface->format != CAIRO_FORMAT_RGB24)
+- return CAIRO_INT_STATUS_UNSUPPORTED;
++ //if (surface->format != CAIRO_FORMAT_RGB24)
++ // return CAIRO_INT_STATUS_UNSUPPORTED;
++ // FIXME: We'll go ahead and optimize this now and just assume we're ok if
++ // the color has no alpha. Probably need to check various composite operators to
++ // get this exactly right.
++ if (color->alpha != 1.0)
++ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
+ * surfaces with alpha.)
+@@ -1016,8 +1021,9 @@
+
+ /* We can only handle operator SOURCE or OVER with the destination
+ * having no alpha */
+- if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
+- (dst->format != CAIRO_FORMAT_RGB24))
++ if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER))
++ // FIXME: It's not clear why ExtTextOut can't be called when the
++ // destination has alpha. Remove the RGB24 restriction. || (dst->format != CAIRO_FORMAT_RGB24))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* If we have a fallback mask clip set on the dst, we have
diff --git a/Source/WebCore/platform/graphics/cairo/scale-removal.txt b/Source/WebCore/platform/graphics/cairo/scale-removal.txt
new file mode 100644
index 0000000..47c0d70
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/scale-removal.txt
@@ -0,0 +1,13 @@
+Index: cairo/src/cairo-win32-private.h
+===================================================================
+--- cairo/src/cairo-win32-private.h (revision 14582)
++++ cairo/src/cairo-win32-private.h (working copy)
+@@ -39,7 +39,7 @@
+ #include <cairo-win32.h>
+ #include <cairoint.h>
+
+-#define WIN32_FONT_LOGICAL_SCALE 32
++#define WIN32_FONT_LOGICAL_SCALE 1
+
+ typedef struct _cairo_win32_surface {
+ cairo_surface_t base;
diff --git a/Source/WebCore/platform/graphics/cg/ColorCG.cpp b/Source/WebCore/platform/graphics/cg/ColorCG.cpp
new file mode 100644
index 0000000..c9b05da
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/ColorCG.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#if PLATFORM(CG)
+
+#include "GraphicsContextCG.h"
+#include <wtf/Assertions.h>
+#include <wtf/RetainPtr.h>
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+Color::Color(CGColorRef color)
+{
+ if (!color) {
+ m_color = 0;
+ m_valid = false;
+ return;
+ }
+
+ size_t numComponents = CGColorGetNumberOfComponents(color);
+ const CGFloat* components = CGColorGetComponents(color);
+
+ float r = 0;
+ float g = 0;
+ float b = 0;
+ float a = 0;
+
+ switch (numComponents) {
+ case 2:
+ r = g = b = components[0];
+ a = components[1];
+ break;
+ case 4:
+ r = components[0];
+ g = components[1];
+ b = components[2];
+ a = components[3];
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ m_color = makeRGBA(r * 255, g * 255, b * 255, a * 255);
+ m_valid = true;
+}
+
+static inline CGColorSpaceRef cachedCGColorSpace(ColorSpace colorSpace)
+{
+ switch (colorSpace) {
+ case ColorSpaceDeviceRGB:
+ return deviceRGBColorSpaceRef();
+ case ColorSpaceSRGB:
+ return sRGBColorSpaceRef();
+ case ColorSpaceLinearRGB:
+ return linearRGBColorSpaceRef();
+ }
+ ASSERT_NOT_REACHED();
+ return deviceRGBColorSpaceRef();
+}
+
+static CGColorRef leakCGColor(const Color& color, ColorSpace colorSpace)
+{
+ CGFloat components[4];
+ color.getRGBA(components[0], components[1], components[2], components[3]);
+ return CGColorCreate(cachedCGColorSpace(colorSpace), components);
+}
+
+template<ColorSpace colorSpace> static CGColorRef cachedCGColor(const Color& color)
+{
+ switch (color.rgb()) {
+ case Color::transparent: {
+ static CGColorRef transparentCGColor = leakCGColor(color, colorSpace);
+ return transparentCGColor;
+ }
+ case Color::black: {
+ static CGColorRef blackCGColor = leakCGColor(color, colorSpace);
+ return blackCGColor;
+ }
+ case Color::white: {
+ static CGColorRef whiteCGColor = leakCGColor(color, colorSpace);
+ return whiteCGColor;
+ }
+ }
+
+ ASSERT(color.rgb());
+
+ const size_t cacheSize = 32;
+ static RGBA32 cachedRGBAValues[cacheSize];
+ static RetainPtr<CGColorRef>* cachedCGColors = new RetainPtr<CGColorRef>[cacheSize];
+
+ for (size_t i = 0; i < cacheSize; ++i) {
+ if (cachedRGBAValues[i] == color.rgb())
+ return cachedCGColors[i].get();
+ }
+
+ CGColorRef newCGColor = leakCGColor(color, colorSpace);
+
+ static size_t cursor;
+ cachedRGBAValues[cursor] = color.rgb();
+ cachedCGColors[cursor].adoptCF(newCGColor);
+ if (++cursor == cacheSize)
+ cursor = 0;
+
+ return newCGColor;
+}
+
+CGColorRef cachedCGColor(const Color& color, ColorSpace colorSpace)
+{
+ switch (colorSpace) {
+ case ColorSpaceDeviceRGB:
+ return cachedCGColor<ColorSpaceDeviceRGB>(color);
+ case ColorSpaceSRGB:
+ return cachedCGColor<ColorSpaceSRGB>(color);
+ case ColorSpaceLinearRGB:
+ return cachedCGColor<ColorSpaceLinearRGB>(color);
+ }
+ ASSERT_NOT_REACHED();
+ return cachedCGColor(color, ColorSpaceDeviceRGB);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp b/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp
new file mode 100644
index 0000000..f9c3353
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatPoint.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const CGPoint& p) : m_x(p.x), m_y(p.y)
+{
+}
+
+FloatPoint::operator CGPoint() const
+{
+ return CGPointMake(m_x, m_y);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp b/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp
new file mode 100644
index 0000000..a1ce367
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+FloatRect::FloatRect(const CGRect& r) : m_location(r.origin), m_size(r.size)
+{
+}
+
+FloatRect::operator CGRect() const
+{
+ return CGRectMake(x(), y(), width(), height());
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp b/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp
new file mode 100644
index 0000000..383af21
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatSize.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+FloatSize::FloatSize(const CGSize& s) : m_width(s.width), m_height(s.height)
+{
+}
+
+FloatSize::operator CGSize() const
+{
+ return CGSizeMake(m_width, m_height);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/FontPlatformData.h b/Source/WebCore/platform/graphics/cg/FontPlatformData.h
new file mode 100644
index 0000000..e21b444
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/FontPlatformData.h
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+#include "FontOrientation.h"
+#include "RefCountedGDIHandle.h"
+#include "StringImpl.h"
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RetainPtr.h>
+
+typedef struct HFONT__* HFONT;
+typedef struct CGFont* CGFontRef;
+
+namespace WebCore {
+
+class FontDescription;
+
+class FontPlatformData {
+public:
+ FontPlatformData()
+ : m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_useGDI(false)
+ {
+ }
+
+ FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI);
+ FontPlatformData(float size, bool bold, bool oblique);
+
+ FontPlatformData(HFONT, CGFontRef, float size, bool bold, bool oblique, bool useGDI);
+ ~FontPlatformData();
+
+ FontPlatformData(WTF::HashTableDeletedValueType) : m_font(WTF::HashTableDeletedValue) { }
+ bool isHashTableDeletedValue() const { return m_font.isHashTableDeletedValue(); }
+
+ HFONT hfont() const { return m_font->handle(); }
+ CGFontRef cgFont() const { return m_cgFont.get(); }
+
+ float size() const { return m_size; }
+ void setSize(float size) { m_size = size; }
+ bool syntheticBold() const { return m_syntheticBold; }
+ bool syntheticOblique() const { return m_syntheticOblique; }
+ bool useGDI() const { return m_useGDI; }
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+ unsigned hash() const
+ {
+ return m_font->hash();
+ }
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ return m_font == other.m_font
+ && m_cgFont == other.m_cgFont
+ && m_size == other.m_size
+ && m_syntheticBold == other.m_syntheticBold
+ && m_syntheticOblique == other.m_syntheticOblique
+ && m_useGDI == other.m_useGDI;
+ }
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+private:
+ void platformDataInit(HFONT, float size, HDC, WCHAR* faceName);
+
+ RefPtr<RefCountedGDIHandle<HFONT> > m_font;
+ RetainPtr<CGFontRef> m_cgFont;
+
+ float m_size;
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+ bool m_useGDI;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cg/GradientCG.cpp b/Source/WebCore/platform/graphics/cg/GradientCG.cpp
new file mode 100644
index 0000000..974dd6b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/GradientCG.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "GraphicsContextCG.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+#if USE_CG_SHADING
+ CGShadingRelease(m_gradient);
+#else
+ CGGradientRelease(m_gradient);
+#endif
+ m_gradient = 0;
+}
+
+#if USE_CG_SHADING
+static void gradientCallback(void* info, const CGFloat* in, CGFloat* out)
+{
+ float r, g, b, a;
+ static_cast<const Gradient*>(info)->getColor(*in, &r, &g, &b, &a);
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = a;
+}
+
+CGShadingRef Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ const CGFloat intervalRanges[2] = { 0, 1 };
+ const CGFloat colorComponentRanges[4 * 2] = { 0, 1, 0, 1, 0, 1, 0, 1 };
+ const CGFunctionCallbacks gradientCallbacks = { 0, gradientCallback, 0 };
+ RetainPtr<CGFunctionRef> colorFunction(AdoptCF, CGFunctionCreate(this, 1, intervalRanges, 4, colorComponentRanges, &gradientCallbacks));
+
+ CGColorSpaceRef colorSpace = deviceRGBColorSpaceRef();
+
+ if (m_radial)
+ m_gradient = CGShadingCreateRadial(colorSpace, m_p0, m_r0, m_p1, m_r1, colorFunction.get(), true, true);
+ else
+ m_gradient = CGShadingCreateAxial(colorSpace, m_p0, m_p1, colorFunction.get(), true, true);
+
+ return m_gradient;
+}
+#else
+CGGradientRef Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ sortStopsIfNecessary();
+
+ const int cReservedStops = 3;
+ Vector<CGFloat, 4 * cReservedStops> colorComponents;
+ colorComponents.reserveCapacity(m_stops.size() * 4); // RGBA components per stop
+
+ Vector<CGFloat, cReservedStops> locations;
+ locations.reserveCapacity(m_stops.size());
+
+ for (size_t i = 0; i < m_stops.size(); ++i) {
+ colorComponents.uncheckedAppend(m_stops[i].red);
+ colorComponents.uncheckedAppend(m_stops[i].green);
+ colorComponents.uncheckedAppend(m_stops[i].blue);
+ colorComponents.uncheckedAppend(m_stops[i].alpha);
+
+ locations.uncheckedAppend(m_stops[i].stop);
+ }
+
+ m_gradient = CGGradientCreateWithColorComponents(deviceRGBColorSpaceRef(), colorComponents.data(), locations.data(), m_stops.size());
+
+ return m_gradient;
+}
+#endif
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ context->clip(rect);
+ paint(context);
+}
+
+void Gradient::paint(GraphicsContext* context)
+{
+ CGContextRef ctx = context->platformContext();
+ paint(ctx);
+}
+
+void Gradient::paint(CGContextRef context)
+{
+#if USE_CG_SHADING
+ CGContextDrawShading(context, platformGradient());
+#else
+ CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
+ if (m_radial) {
+ bool needScaling = aspectRatio() != 1;
+ if (needScaling) {
+ CGContextSaveGState(context);
+ // Scale from the center of the gradient. We only ever scale non-deprecated gradients,
+ // for which m_p0 == m_p1.
+ ASSERT(m_p0 == m_p1);
+ CGContextTranslateCTM(context, m_p0.x(), m_p0.y());
+ CGContextScaleCTM(context, 1, 1 / aspectRatio());
+ CGContextTranslateCTM(context, -m_p0.x(), -m_p0.y());
+ }
+
+ CGContextDrawRadialGradient(context, platformGradient(), m_p0, m_r0, m_p1, m_r1, extendOptions);
+
+ if (needScaling)
+ CGContextRestoreGState(context);
+ } else
+ CGContextDrawLinearGradient(context, platformGradient(), m_p0, m_p1, extendOptions);
+#endif
+}
+
+} //namespace
diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
new file mode 100644
index 0000000..c19bd72
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+#include "GraphicsContextCG.h"
+
+#include "Image.h"
+
+#include <CoreGraphics/CGBitmapContext.h>
+#include <CoreGraphics/CGContext.h>
+#include <CoreGraphics/CGDataProvider.h>
+#include <CoreGraphics/CGImage.h>
+
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+enum SourceDataFormatBase {
+ SourceFormatBaseR = 0,
+ SourceFormatBaseA,
+ SourceFormatBaseRA,
+ SourceFormatBaseAR,
+ SourceFormatBaseRGB,
+ SourceFormatBaseRGBA,
+ SourceFormatBaseARGB,
+ SourceFormatBaseNumFormats
+};
+
+enum AlphaFormat {
+ AlphaFormatNone = 0,
+ AlphaFormatFirst,
+ AlphaFormatLast,
+ AlphaFormatNumFormats
+};
+
+// This returns SourceFormatNumFormats if the combination of input parameters is unsupported.
+static GraphicsContext3D::SourceDataFormat getSourceDataFormat(unsigned int componentsPerPixel, AlphaFormat alphaFormat, bool is16BitFormat, bool bigEndian)
+{
+ const static SourceDataFormatBase formatTableBase[4][AlphaFormatNumFormats] = { // componentsPerPixel x AlphaFormat
+ // AlphaFormatNone AlphaFormatFirst AlphaFormatLast
+ { SourceFormatBaseR, SourceFormatBaseA, SourceFormatBaseA }, // 1 componentsPerPixel
+ { SourceFormatBaseNumFormats, SourceFormatBaseAR, SourceFormatBaseRA }, // 2 componentsPerPixel
+ { SourceFormatBaseRGB, SourceFormatBaseNumFormats, SourceFormatBaseNumFormats }, // 3 componentsPerPixel
+ { SourceFormatBaseNumFormats, SourceFormatBaseARGB, SourceFormatBaseRGBA } // 4 componentsPerPixel
+ };
+ const static GraphicsContext3D::SourceDataFormat formatTable[SourceFormatBaseNumFormats][4] = { // SourceDataFormatBase x bitsPerComponent x endian
+ // 8bits, little endian 8bits, big endian 16bits, little endian 16bits, big endian
+ { GraphicsContext3D::SourceFormatR8, GraphicsContext3D::SourceFormatR8, GraphicsContext3D::SourceFormatR16Little, GraphicsContext3D::SourceFormatR16Big },
+ { GraphicsContext3D::SourceFormatA8, GraphicsContext3D::SourceFormatA8, GraphicsContext3D::SourceFormatA16Little, GraphicsContext3D::SourceFormatA16Big },
+ { GraphicsContext3D::SourceFormatAR8, GraphicsContext3D::SourceFormatRA8, GraphicsContext3D::SourceFormatRA16Little, GraphicsContext3D::SourceFormatRA16Big },
+ { GraphicsContext3D::SourceFormatRA8, GraphicsContext3D::SourceFormatAR8, GraphicsContext3D::SourceFormatAR16Little, GraphicsContext3D::SourceFormatAR16Big },
+ { GraphicsContext3D::SourceFormatBGR8, GraphicsContext3D::SourceFormatRGB8, GraphicsContext3D::SourceFormatRGB16Little, GraphicsContext3D::SourceFormatRGB16Big },
+ { GraphicsContext3D::SourceFormatABGR8, GraphicsContext3D::SourceFormatRGBA8, GraphicsContext3D::SourceFormatRGBA16Little, GraphicsContext3D::SourceFormatRGBA16Big },
+ { GraphicsContext3D::SourceFormatBGRA8, GraphicsContext3D::SourceFormatARGB8, GraphicsContext3D::SourceFormatARGB16Little, GraphicsContext3D::SourceFormatARGB16Big }
+ };
+
+ ASSERT(componentsPerPixel <= 4 && componentsPerPixel > 0);
+ SourceDataFormatBase formatBase = formatTableBase[componentsPerPixel - 1][alphaFormat];
+ if (formatBase == SourceFormatBaseNumFormats)
+ return GraphicsContext3D::SourceFormatNumFormats;
+ return formatTable[formatBase][(is16BitFormat ? 2 : 0) + (bigEndian ? 1 : 0)];
+}
+
+bool GraphicsContext3D::getImageData(Image* image,
+ GC3Denum format,
+ GC3Denum type,
+ bool premultiplyAlpha,
+ bool ignoreGammaAndColorProfile,
+ Vector<uint8_t>& outputVector)
+{
+ if (!image)
+ return false;
+ CGImageRef cgImage;
+ RetainPtr<CGImageRef> decodedImage;
+ if (image->data()) {
+ ImageSource decoder(ImageSource::AlphaNotPremultiplied,
+ ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied);
+ decoder.setData(image->data(), true);
+ if (!decoder.frameCount())
+ return false;
+ decodedImage = decoder.createFrameAtIndex(0);
+ cgImage = decodedImage.get();
+ } else
+ cgImage = image->nativeImageForCurrentFrame();
+ if (!cgImage)
+ return false;
+
+ size_t width = CGImageGetWidth(cgImage);
+ size_t height = CGImageGetHeight(cgImage);
+ if (!width || !height)
+ return false;
+ size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage);
+ size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage);
+ if (bitsPerComponent != 8 && bitsPerComponent != 16)
+ return false;
+ if (bitsPerPixel % bitsPerComponent)
+ return false;
+ size_t componentsPerPixel = bitsPerPixel / bitsPerComponent;
+
+ CGBitmapInfo bitInfo = CGImageGetBitmapInfo(cgImage);
+ bool bigEndianSource = false;
+ // These could technically be combined into one large switch
+ // statement, but we prefer not to so that we fail fast if we
+ // encounter an unexpected image configuration.
+ if (bitsPerComponent == 16) {
+ switch (bitInfo & kCGBitmapByteOrderMask) {
+ case kCGBitmapByteOrder16Big:
+ bigEndianSource = true;
+ break;
+ case kCGBitmapByteOrder16Little:
+ bigEndianSource = false;
+ break;
+ case kCGBitmapByteOrderDefault:
+ // This is a bug in earlier version of cg where the default endian
+ // is little whereas the decoded 16-bit png image data is actually
+ // Big. Later version (10.6.4) no longer returns ByteOrderDefault.
+ bigEndianSource = true;
+ break;
+ default:
+ return false;
+ }
+ } else {
+ switch (bitInfo & kCGBitmapByteOrderMask) {
+ case kCGBitmapByteOrder32Big:
+ bigEndianSource = true;
+ break;
+ case kCGBitmapByteOrder32Little:
+ bigEndianSource = false;
+ break;
+ case kCGBitmapByteOrderDefault:
+ // It appears that the default byte order is actually big
+ // endian even on little endian architectures.
+ bigEndianSource = true;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ AlphaOp neededAlphaOp = AlphaDoNothing;
+ AlphaFormat alphaFormat = AlphaFormatNone;
+ switch (CGImageGetAlphaInfo(cgImage)) {
+ case kCGImageAlphaPremultipliedFirst:
+ // This path is only accessible for MacOS earlier than 10.6.4.
+ // This is a special case for texImage2D with HTMLCanvasElement input,
+ // in which case image->data() should be null.
+ ASSERT(!image->data());
+ if (!premultiplyAlpha)
+ neededAlphaOp = AlphaDoUnmultiply;
+ alphaFormat = AlphaFormatFirst;
+ break;
+ case kCGImageAlphaFirst:
+ // This path is only accessible for MacOS earlier than 10.6.4.
+ if (premultiplyAlpha)
+ neededAlphaOp = AlphaDoPremultiply;
+ alphaFormat = AlphaFormatFirst;
+ break;
+ case kCGImageAlphaNoneSkipFirst:
+ // This path is only accessible for MacOS earlier than 10.6.4.
+ alphaFormat = AlphaFormatFirst;
+ break;
+ case kCGImageAlphaPremultipliedLast:
+ // This is a special case for texImage2D with HTMLCanvasElement input,
+ // in which case image->data() should be null.
+ ASSERT(!image->data());
+ if (!premultiplyAlpha)
+ neededAlphaOp = AlphaDoUnmultiply;
+ alphaFormat = AlphaFormatLast;
+ break;
+ case kCGImageAlphaLast:
+ if (premultiplyAlpha)
+ neededAlphaOp = AlphaDoPremultiply;
+ alphaFormat = AlphaFormatLast;
+ break;
+ case kCGImageAlphaNoneSkipLast:
+ alphaFormat = AlphaFormatLast;
+ break;
+ case kCGImageAlphaNone:
+ alphaFormat = AlphaFormatNone;
+ break;
+ default:
+ return false;
+ }
+ SourceDataFormat srcDataFormat = getSourceDataFormat(componentsPerPixel, alphaFormat, bitsPerComponent == 16, bigEndianSource);
+ if (srcDataFormat == SourceFormatNumFormats)
+ return false;
+
+ RetainPtr<CFDataRef> pixelData;
+ pixelData.adoptCF(CGDataProviderCopyData(CGImageGetDataProvider(cgImage)));
+ if (!pixelData)
+ return false;
+ const UInt8* rgba = CFDataGetBytePtr(pixelData.get());
+ outputVector.resize(width * height * 4);
+ unsigned int srcUnpackAlignment = 0;
+ size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
+ unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width;
+ if (padding) {
+ srcUnpackAlignment = padding + 1;
+ while (bytesPerRow % srcUnpackAlignment)
+ ++srcUnpackAlignment;
+ }
+ bool rt = packPixels(rgba, srcDataFormat, width, height, srcUnpackAlignment,
+ format, type, neededAlphaOp, outputVector.data());
+ return rt;
+}
+
+void GraphicsContext3D::paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, int canvasWidth, int canvasHeight, CGContextRef context)
+{
+ if (!imagePixels || imageWidth <= 0 || imageHeight <= 0 || canvasWidth <= 0 || canvasHeight <= 0 || !context)
+ return;
+ int rowBytes = imageWidth * 4;
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithData(0, imagePixels, rowBytes * imageHeight, 0));
+ RetainPtr<CGImageRef> cgImage(AdoptCF, CGImageCreate(imageWidth, imageHeight, 8, 32, rowBytes, deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
+ dataProvider.get(), 0, false, kCGRenderingIntentDefault));
+ // CSS styling may cause the canvas's content to be resized on
+ // the page. Go back to the Canvas to figure out the correct
+ // width and height to draw.
+ CGRect rect = CGRectMake(0, 0, canvasWidth, canvasHeight);
+ // We want to completely overwrite the previous frame's
+ // rendering results.
+ CGContextSaveGState(context);
+ CGContextSetBlendMode(context, kCGBlendModeCopy);
+ CGContextSetInterpolationQuality(context, kCGInterpolationNone);
+ CGContextDrawImage(context, rect, cgImage.get());
+ CGContextRestoreGState(context);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
new file mode 100644
index 0000000..acd912f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -0,0 +1,1260 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#define _USE_MATH_DEFINES 1
+#include "config.h"
+#include "GraphicsContextCG.h"
+
+#include "AffineTransform.h"
+#include "FloatConversion.h"
+#include "GraphicsContextPlatformPrivateCG.h"
+#include "ImageBuffer.h"
+#include "KURL.h"
+#include "Path.h"
+#include "Pattern.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/UnusedParam.h>
+
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
+#include "WebCoreSystemInterface.h"
+#endif
+
+#if PLATFORM(WIN)
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
+
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+// Building on 10.6 or later: kCGInterpolationMedium is defined in the CGInterpolationQuality enum.
+#define HAVE_CG_INTERPOLATION_MEDIUM 1
+#endif
+
+#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD)
+// Targeting 10.6 or later: use kCGInterpolationMedium.
+#define WTF_USE_CG_INTERPOLATION_MEDIUM 1
+#endif
+
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+static void setCGFillColor(CGContextRef context, const Color& color, ColorSpace colorSpace)
+{
+ CGContextSetFillColorWithColor(context, cachedCGColor(color, colorSpace));
+}
+
+static void setCGStrokeColor(CGContextRef context, const Color& color, ColorSpace colorSpace)
+{
+ CGContextSetStrokeColorWithColor(context, cachedCGColor(color, colorSpace));
+}
+
+CGColorSpaceRef deviceRGBColorSpaceRef()
+{
+ static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB();
+ return deviceSpace;
+}
+
+CGColorSpaceRef sRGBColorSpaceRef()
+{
+ // FIXME: Windows should be able to use kCGColorSpaceSRGB, this is tracked by http://webkit.org/b/31363.
+#if PLATFORM(WIN) || defined(BUILDING_ON_TIGER)
+ return deviceRGBColorSpaceRef();
+#else
+ static CGColorSpaceRef sRGBSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
+ return sRGBSpace;
+#endif
+}
+
+CGColorSpaceRef linearRGBColorSpaceRef()
+{
+ // FIXME: Windows should be able to use kCGColorSpaceGenericRGBLinear, this is tracked by http://webkit.org/b/31363.
+#if PLATFORM(WIN) || defined(BUILDING_ON_TIGER)
+ return deviceRGBColorSpaceRef();
+#else
+ static CGColorSpaceRef linearRGBSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear);
+ return linearRGBSpace;
+#endif
+}
+
+void GraphicsContext::platformInit(CGContextRef cgContext)
+{
+ m_data = new GraphicsContextPlatformPrivate(cgContext);
+ setPaintingDisabled(!cgContext);
+ if (cgContext) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor(), fillColorSpace());
+ setPlatformStrokeColor(strokeColor(), strokeColorSpace());
+ }
+}
+
+void GraphicsContext::platformDestroy()
+{
+ delete m_data;
+}
+
+CGContextRef GraphicsContext::platformContext() const
+{
+ ASSERT(!paintingDisabled());
+ ASSERT(m_data->m_cgContext);
+ return m_data->m_cgContext.get();
+}
+
+void GraphicsContext::savePlatformState()
+{
+ // Note: Do not use this function within this class implementation, since we want to avoid the extra
+ // save of the secondary context (in GraphicsContextPlatformPrivateCG.h).
+ CGContextSaveGState(platformContext());
+ m_data->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ // Note: Do not use this function within this class implementation, since we want to avoid the extra
+ // restore of the secondary context (in GraphicsContextPlatformPrivateCG.h).
+ CGContextRestoreGState(platformContext());
+ m_data->restore();
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ // FIXME: this function does not handle patterns and gradients
+ // like drawPath does, it probably should.
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+
+ CGContextFillRect(context, rect);
+
+ if (strokeStyle() != NoStroke) {
+ // We do a fill of four rects to simulate the stroke of a border.
+ Color oldFillColor = fillColor();
+ if (oldFillColor != strokeColor())
+ setCGFillColor(context, strokeColor(), strokeColorSpace());
+ CGRect rects[4] = {
+ FloatRect(rect.x(), rect.y(), rect.width(), 1),
+ FloatRect(rect.x(), rect.bottom() - 1, rect.width(), 1),
+ FloatRect(rect.x(), rect.y() + 1, 1, rect.height() - 2),
+ FloatRect(rect.right() - 1, rect.y() + 1, 1, rect.height() - 2)
+ };
+ CGContextFillRects(context, rects, 4);
+ if (oldFillColor != strokeColor())
+ setCGFillColor(context, oldFillColor, fillColorSpace());
+ }
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ if (strokeStyle() == NoStroke)
+ return;
+
+ float width = strokeThickness();
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
+
+ // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
+ // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g.,
+ // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave
+ // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
+ if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
+ if (isVerticalLine) {
+ p1.move(0, width);
+ p2.move(0, -width);
+ } else {
+ p1.move(width, 0);
+ p2.move(-width, 0);
+ }
+ }
+
+ if (((int)width) % 2) {
+ if (isVerticalLine) {
+ // We're a vertical line. Adjust our x.
+ p1.move(0.5f, 0.0f);
+ p2.move(0.5f, 0.0f);
+ } else {
+ // We're a horizontal line. Adjust our y.
+ p1.move(0.0f, 0.5f);
+ p2.move(0.0f, 0.5f);
+ }
+ }
+
+ int patWidth = 0;
+ switch (strokeStyle()) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DottedStroke:
+ patWidth = (int)width;
+ break;
+ case DashedStroke:
+ patWidth = 3 * (int)width;
+ break;
+ }
+
+ CGContextRef context = platformContext();
+
+ if (shouldAntialias())
+ CGContextSetShouldAntialias(context, false);
+
+ if (patWidth) {
+ CGContextSaveGState(context);
+
+ // Do a rect fill of our endpoints. This ensures we always have the
+ // appearance of being a border. We then draw the actual dotted/dashed line.
+ setCGFillColor(context, strokeColor(), strokeColorSpace()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color.
+ if (isVerticalLine) {
+ CGContextFillRect(context, FloatRect(p1.x() - width / 2, p1.y() - width, width, width));
+ CGContextFillRect(context, FloatRect(p2.x() - width / 2, p2.y(), width, width));
+ } else {
+ CGContextFillRect(context, FloatRect(p1.x() - width, p1.y() - width / 2, width, width));
+ CGContextFillRect(context, FloatRect(p2.x(), p2.y() - width / 2, width, width));
+ }
+
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width;
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0f;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0f;
+ else {
+ bool evenNumberOfSegments = !(numSegments % 2);
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2;
+ } else
+ patternOffset = patWidth / 2;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder)/2;
+ }
+ }
+
+ const CGFloat dottedLine[2] = { patWidth, patWidth };
+ CGContextSetLineDash(context, patternOffset, dottedLine, 2);
+ }
+
+ CGContextBeginPath(context);
+ CGContextMoveToPoint(context, p1.x(), p1.y());
+ CGContextAddLineToPoint(context, p2.x(), p2.y());
+
+ CGContextStrokePath(context);
+
+ if (patWidth)
+ CGContextRestoreGState(context);
+
+ if (shouldAntialias())
+ CGContextSetShouldAntialias(context, true);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ Path path;
+ path.addEllipse(rect);
+ drawPath(path);
+}
+
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f)
+ return;
+
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+ CGContextBeginPath(context);
+ CGContextSetShouldAntialias(context, false);
+
+ int x = rect.x();
+ int y = rect.y();
+ float w = (float)rect.width();
+ float h = (float)rect.height();
+ float scaleFactor = h / w;
+ float reverseScaleFactor = w / h;
+
+ if (w != h)
+ scale(FloatSize(1, scaleFactor));
+
+ float hRadius = w / 2;
+ float vRadius = h / 2;
+ float fa = startAngle;
+ float falen = fa + angleSpan;
+ float start = -fa * piFloat / 180.0f;
+ float end = -falen * piFloat / 180.0f;
+ CGContextAddArc(context, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, start, end, true);
+
+ if (w != h)
+ scale(FloatSize(1, reverseScaleFactor));
+
+ float width = strokeThickness();
+ int patWidth = 0;
+
+ switch (strokeStyle()) {
+ case DottedStroke:
+ patWidth = (int)(width / 2);
+ break;
+ case DashedStroke:
+ patWidth = 3 * (int)(width / 2);
+ break;
+ default:
+ break;
+ }
+
+ if (patWidth) {
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance;
+ if (hRadius == vRadius)
+ distance = static_cast<int>((piFloat * hRadius) / 2.0f);
+ else // We are elliptical and will have to estimate the distance
+ distance = static_cast<int>((piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0f)) / 2.0f);
+
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0f;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0f;
+ else {
+ bool evenNumberOfSegments = !(numSegments % 2);
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2.0f;
+ } else
+ patternOffset = patWidth / 2.0f;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder) / 2.0f;
+ }
+ }
+
+ const CGFloat dottedLine[2] = { patWidth, patWidth };
+ CGContextSetLineDash(context, patternOffset, dottedLine, 2);
+ }
+
+ CGContextStrokePath(context);
+
+ CGContextRestoreGState(context);
+}
+
+static void addConvexPolygonToPath(Path& path, size_t numberOfPoints, const FloatPoint* points)
+{
+ ASSERT(numberOfPoints > 0);
+
+ path.moveTo(points[0]);
+ for (size_t i = 1; i < numberOfPoints; ++i)
+ path.addLineTo(points[i]);
+ path.closeSubpath();
+}
+
+void GraphicsContext::drawConvexPolygon(size_t numberOfPoints, const FloatPoint* points, bool antialiased)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numberOfPoints <= 1)
+ return;
+
+ CGContextRef context = platformContext();
+
+ if (antialiased != shouldAntialias())
+ CGContextSetShouldAntialias(context, antialiased);
+
+ Path path;
+ addConvexPolygonToPath(path, numberOfPoints, points);
+ drawPath(path);
+
+ if (antialiased != shouldAntialias())
+ CGContextSetShouldAntialias(context, shouldAntialias());
+}
+
+void GraphicsContext::clipConvexPolygon(size_t numberOfPoints, const FloatPoint* points, bool antialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numberOfPoints <= 1)
+ return;
+
+ CGContextRef context = platformContext();
+
+ if (antialias != shouldAntialias())
+ CGContextSetShouldAntialias(context, antialias);
+
+ Path path;
+ addConvexPolygonToPath(path, numberOfPoints, points);
+ clipPath(path, RULE_NONZERO);
+
+ if (antialias != shouldAntialias())
+ CGContextSetShouldAntialias(context, shouldAntialias());
+}
+
+void GraphicsContext::applyStrokePattern()
+{
+ CGContextRef cgContext = platformContext();
+
+ RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_state.strokePattern->createPlatformPattern(getCTM()));
+ if (!platformPattern)
+ return;
+
+ RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0));
+ CGContextSetStrokeColorSpace(cgContext, patternSpace.get());
+
+ const CGFloat patternAlpha = 1;
+ CGContextSetStrokePattern(cgContext, platformPattern.get(), &patternAlpha);
+}
+
+void GraphicsContext::applyFillPattern()
+{
+ CGContextRef cgContext = platformContext();
+
+ RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_state.fillPattern->createPlatformPattern(getCTM()));
+ if (!platformPattern)
+ return;
+
+ RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0));
+ CGContextSetFillColorSpace(cgContext, patternSpace.get());
+
+ const CGFloat patternAlpha = 1;
+ CGContextSetFillPattern(cgContext, platformPattern.get(), &patternAlpha);
+}
+
+static inline bool calculateDrawingMode(const GraphicsContextState& state, CGPathDrawingMode& mode)
+{
+ bool shouldFill = state.fillPattern || state.fillColor.alpha();
+ bool shouldStroke = state.strokePattern || (state.strokeStyle != NoStroke && state.strokeColor.alpha());
+ bool useEOFill = state.fillRule == RULE_EVENODD;
+
+ if (shouldFill) {
+ if (shouldStroke) {
+ if (useEOFill)
+ mode = kCGPathEOFillStroke;
+ else
+ mode = kCGPathFillStroke;
+ } else { // fill, no stroke
+ if (useEOFill)
+ mode = kCGPathEOFill;
+ else
+ mode = kCGPathFill;
+ }
+ } else {
+ // Setting mode to kCGPathStroke even if shouldStroke is false. In that case, we return false and mode will not be used,
+ // but the compiler will not complain about an uninitialized variable.
+ mode = kCGPathStroke;
+ }
+
+ return shouldFill || shouldStroke;
+}
+
+void GraphicsContext::drawPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+ const GraphicsContextState& state = m_state;
+
+ if (state.fillGradient || state.strokeGradient) {
+ // We don't have any optimized way to fill & stroke a path using gradients
+ // FIXME: Be smarter about this.
+ fillPath(path);
+ strokePath(path);
+ return;
+ }
+
+ CGContextBeginPath(context);
+ CGContextAddPath(context, path.platformPath());
+
+ if (state.fillPattern)
+ applyFillPattern();
+ if (state.strokePattern)
+ applyStrokePattern();
+
+ CGPathDrawingMode drawingMode;
+ if (calculateDrawingMode(state, drawingMode))
+ CGContextDrawPath(context, drawingMode);
+}
+
+static inline void fillPathWithFillRule(CGContextRef context, WindRule fillRule)
+{
+ if (fillRule == RULE_EVENODD)
+ CGContextEOFillPath(context);
+ else
+ CGContextFillPath(context);
+}
+
+void GraphicsContext::fillPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+
+ CGContextBeginPath(context);
+ CGContextAddPath(context, path.platformPath());
+
+ if (m_state.fillGradient) {
+ CGContextSaveGState(context);
+ if (fillRule() == RULE_EVENODD)
+ CGContextEOClip(context);
+ else
+ CGContextClip(context);
+ CGContextConcatCTM(context, m_state.fillGradient->gradientSpaceTransform());
+ m_state.fillGradient->paint(this);
+ CGContextRestoreGState(context);
+ return;
+ }
+
+ if (m_state.fillPattern)
+ applyFillPattern();
+ fillPathWithFillRule(context, fillRule());
+}
+
+void GraphicsContext::strokePath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+
+ CGContextBeginPath(context);
+ CGContextAddPath(context, path.platformPath());
+
+ if (m_state.strokeGradient) {
+ CGContextSaveGState(context);
+ CGContextReplacePathWithStrokedPath(context);
+ CGContextClip(context);
+ CGContextConcatCTM(context, m_state.strokeGradient->gradientSpaceTransform());
+ m_state.strokeGradient->paint(this);
+ CGContextRestoreGState(context);
+ return;
+ }
+
+ if (m_state.strokePattern)
+ applyStrokePattern();
+ CGContextStrokePath(context);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+
+ if (m_state.fillGradient) {
+ CGContextSaveGState(context);
+ CGContextConcatCTM(context, m_state.fillGradient->gradientSpaceTransform());
+ if (hasShadow()) {
+ CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0);
+ CGContextRef layerContext = CGLayerGetContext(layer);
+ m_state.fillGradient->paint(layerContext);
+ CGContextDrawLayerAtPoint(context, CGPointMake(rect.left(), rect.top()), layer);
+ CGLayerRelease(layer);
+ } else {
+ CGContextClipToRect(context, rect);
+ m_state.fillGradient->paint(this);
+ }
+ CGContextRestoreGState(context);
+ return;
+ }
+
+ if (m_state.fillPattern)
+ applyFillPattern();
+ CGContextFillRect(context, rect);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+ Color oldFillColor = fillColor();
+ ColorSpace oldColorSpace = fillColorSpace();
+
+ if (oldFillColor != color || oldColorSpace != colorSpace)
+ setCGFillColor(context, color, colorSpace);
+
+ CGContextFillRect(context, rect);
+
+ if (oldFillColor != color || oldColorSpace != colorSpace)
+ setCGFillColor(context, oldFillColor, oldColorSpace);
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+ Color oldFillColor = fillColor();
+ ColorSpace oldColorSpace = fillColorSpace();
+
+ if (oldFillColor != color || oldColorSpace != colorSpace)
+ setCGFillColor(context, color, colorSpace);
+
+ Path path;
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ fillPath(path);
+
+ if (oldFillColor != color || oldColorSpace != colorSpace)
+ setCGFillColor(context, oldFillColor, oldColorSpace);
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+ CGContextClipToRect(platformContext(), rect);
+ m_data->clip(rect);
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ CGRect rects[2] = { CGContextGetClipBoundingBox(platformContext()), rect };
+ CGContextBeginPath(platformContext());
+ CGContextAddRects(platformContext(), rects, 2);
+ CGContextEOClip(platformContext());
+}
+
+void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ if (path.isEmpty())
+ return;
+
+ CGContextRef context = platformContext();
+
+ CGContextBeginPath(platformContext());
+ CGContextAddPath(platformContext(), path.platformPath());
+
+ if (clipRule == RULE_EVENODD)
+ CGContextEOClip(context);
+ else
+ CGContextClip(context);
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ clip(rect);
+ CGContextRef context = platformContext();
+
+ // Add outer ellipse
+ CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()));
+ // Add inner ellipse.
+ CGContextAddEllipseInRect(context, CGRectMake(rect.x() + thickness, rect.y() + thickness,
+ rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
+
+ CGContextEOClip(context);
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+ CGContextSetAlpha(context, opacity);
+ CGContextBeginTransparencyLayer(context, 0);
+ m_data->beginTransparencyLayer();
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+ CGContextRef context = platformContext();
+ CGContextEndTransparencyLayer(context);
+ CGContextRestoreGState(context);
+ m_data->endTransparencyLayer();
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+ CGFloat xOffset = offset.width();
+ CGFloat yOffset = offset.height();
+ CGFloat blurRadius = blur;
+ CGContextRef context = platformContext();
+
+ if (!m_state.shadowsIgnoreTransforms) {
+ CGAffineTransform userToBaseCTM = wkGetUserToBaseCTM(context);
+
+ CGFloat A = userToBaseCTM.a * userToBaseCTM.a + userToBaseCTM.b * userToBaseCTM.b;
+ CGFloat B = userToBaseCTM.a * userToBaseCTM.c + userToBaseCTM.b * userToBaseCTM.d;
+ CGFloat C = B;
+ CGFloat D = userToBaseCTM.c * userToBaseCTM.c + userToBaseCTM.d * userToBaseCTM.d;
+
+ CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D)))));
+
+ // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp
+ blurRadius = min(blur * smallEigenvalue, narrowPrecisionToCGFloat(1000.0));
+
+ CGSize offsetInBaseSpace = CGSizeApplyAffineTransform(offset, userToBaseCTM);
+
+ xOffset = offsetInBaseSpace.width;
+ yOffset = offsetInBaseSpace.height;
+ }
+
+ // Work around <rdar://problem/5539388> by ensuring that the offsets will get truncated
+ // to the desired integer.
+ static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128);
+ if (xOffset > 0)
+ xOffset += extraShadowOffset;
+ else if (xOffset < 0)
+ xOffset -= extraShadowOffset;
+
+ if (yOffset > 0)
+ yOffset += extraShadowOffset;
+ else if (yOffset < 0)
+ yOffset -= extraShadowOffset;
+
+ // Check for an invalid color, as this means that the color was not set for the shadow
+ // and we should therefore just use the default shadow color.
+ if (!color.isValid())
+ CGContextSetShadow(context, CGSizeMake(xOffset, yOffset), blurRadius);
+ else
+ CGContextSetShadowWithColor(context, CGSizeMake(xOffset, yOffset), blurRadius, cachedCGColor(color, colorSpace));
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0);
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetMiterLimit(platformContext(), limit);
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetAlpha(platformContext(), alpha);
+}
+
+void GraphicsContext::clearRect(const FloatRect& r)
+{
+ if (paintingDisabled())
+ return;
+ CGContextClearRect(platformContext(), r);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+
+ if (m_state.strokeGradient) {
+ CGContextSaveGState(context);
+ setStrokeThickness(lineWidth);
+ CGContextAddRect(context, r);
+ CGContextReplacePathWithStrokedPath(context);
+ CGContextClip(context);
+ m_state.strokeGradient->paint(this);
+ CGContextRestoreGState(context);
+ return;
+ }
+
+ if (m_state.strokePattern)
+ applyStrokePattern();
+ CGContextStrokeRectWithWidth(context, r, lineWidth);
+}
+
+void GraphicsContext::setLineCap(LineCap cap)
+{
+ if (paintingDisabled())
+ return;
+ switch (cap) {
+ case ButtCap:
+ CGContextSetLineCap(platformContext(), kCGLineCapButt);
+ break;
+ case RoundCap:
+ CGContextSetLineCap(platformContext(), kCGLineCapRound);
+ break;
+ case SquareCap:
+ CGContextSetLineCap(platformContext(), kCGLineCapSquare);
+ break;
+ }
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ CGContextSetLineDash(platformContext(), dashOffset, dashes.data(), dashes.size());
+}
+
+void GraphicsContext::setLineJoin(LineJoin join)
+{
+ if (paintingDisabled())
+ return;
+ switch (join) {
+ case MiterJoin:
+ CGContextSetLineJoin(platformContext(), kCGLineJoinMiter);
+ break;
+ case RoundJoin:
+ CGContextSetLineJoin(platformContext(), kCGLineJoinRound);
+ break;
+ case BevelJoin:
+ CGContextSetLineJoin(platformContext(), kCGLineJoinBevel);
+ break;
+ }
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+ CGContextRef context = platformContext();
+
+ // CGContextClip does nothing if the path is empty, so in this case, we
+ // instead clip against a zero rect to reduce the clipping region to
+ // nothing - which is the intended behavior of clip() if the path is empty.
+ if (path.isEmpty())
+ CGContextClipToRect(context, CGRectZero);
+ else {
+ CGContextBeginPath(context);
+ CGContextAddPath(context, path.platformPath());
+ CGContextClip(context);
+ }
+ m_data->clip(path);
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextBeginPath(platformContext());
+ CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext()));
+ CGContextAddPath(platformContext(), path.platformPath());
+ CGContextEOClip(platformContext());
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+ CGContextScaleCTM(platformContext(), size.width(), size.height());
+ m_data->scale(size);
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::rotate(float angle)
+{
+ if (paintingDisabled())
+ return;
+ CGContextRotateCTM(platformContext(), angle);
+ m_data->rotate(angle);
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+ CGContextTranslateCTM(platformContext(), x, y);
+ m_data->translate(x, y);
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+ CGContextConcatCTM(platformContext(), transform);
+ m_data->concatCTM(transform);
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ CGAffineTransform t = CGContextGetCTM(platformContext());
+ return AffineTransform(t.a, t.b, t.c, t.d, t.tx, t.ty);
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ // It is not enough just to round to pixels in device space. The rotation part of the
+ // affine transform matrix to device space can mess with this conversion if we have a
+ // rotating image like the hands of the world clock widget. We just need the scale, so
+ // we get the affine transform matrix and extract the scale.
+
+ if (m_data->m_userToDeviceTransformKnownToBeIdentity)
+ return rect;
+
+ CGAffineTransform deviceMatrix = CGContextGetUserSpaceToDeviceSpaceTransform(platformContext());
+ if (CGAffineTransformIsIdentity(deviceMatrix)) {
+ m_data->m_userToDeviceTransformKnownToBeIdentity = true;
+ return rect;
+ }
+
+ float deviceScaleX = sqrtf(deviceMatrix.a * deviceMatrix.a + deviceMatrix.b * deviceMatrix.b);
+ float deviceScaleY = sqrtf(deviceMatrix.c * deviceMatrix.c + deviceMatrix.d * deviceMatrix.d);
+
+ CGPoint deviceOrigin = CGPointMake(rect.x() * deviceScaleX, rect.y() * deviceScaleY);
+ CGPoint deviceLowerRight = CGPointMake((rect.x() + rect.width()) * deviceScaleX,
+ (rect.y() + rect.height()) * deviceScaleY);
+
+ deviceOrigin.x = roundf(deviceOrigin.x);
+ deviceOrigin.y = roundf(deviceOrigin.y);
+ deviceLowerRight.x = roundf(deviceLowerRight.x);
+ deviceLowerRight.y = roundf(deviceLowerRight.y);
+
+ // Don't let the height or width round to 0 unless either was originally 0
+ if (deviceOrigin.y == deviceLowerRight.y && rect.height())
+ deviceLowerRight.y += 1;
+ if (deviceOrigin.x == deviceLowerRight.x && rect.width())
+ deviceLowerRight.x += 1;
+
+ FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x / deviceScaleX, deviceOrigin.y / deviceScaleY);
+ FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x / deviceScaleX, deviceLowerRight.y / deviceScaleY);
+ return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ if (width <= 0)
+ return;
+
+ float x = point.x();
+ float y = point.y();
+ float lineLength = width;
+
+ // Use a minimum thickness of 0.5 in user space.
+ // See http://bugs.webkit.org/show_bug.cgi?id=4255 for details of why 0.5 is the right minimum thickness to use.
+ float thickness = max(strokeThickness(), 0.5f);
+
+ bool restoreAntialiasMode = false;
+
+ if (!printing) {
+ // On screen, use a minimum thickness of 1.0 in user space (later rounded to an integral number in device space).
+ float adjustedThickness = max(thickness, 1.0f);
+
+ // FIXME: This should be done a better way.
+ // We try to round all parameters to integer boundaries in device space. If rounding pixels in device space
+ // makes our thickness more than double, then there must be a shrinking-scale factor and rounding to pixels
+ // in device space will make the underlines too thick.
+ CGRect lineRect = roundToDevicePixels(FloatRect(x, y, lineLength, adjustedThickness));
+ if (lineRect.size.height < thickness * 2.0) {
+ x = lineRect.origin.x;
+ y = lineRect.origin.y;
+ lineLength = lineRect.size.width;
+ thickness = lineRect.size.height;
+ if (shouldAntialias()) {
+ CGContextSetShouldAntialias(platformContext(), false);
+ restoreAntialiasMode = true;
+ }
+ }
+ }
+
+ if (fillColor() != strokeColor())
+ setCGFillColor(platformContext(), strokeColor(), strokeColorSpace());
+ CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness));
+ if (fillColor() != strokeColor())
+ setCGFillColor(platformContext(), fillColor(), fillColorSpace());
+
+ if (restoreAntialiasMode)
+ CGContextSetShouldAntialias(platformContext(), true);
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ if (paintingDisabled())
+ return;
+
+ RetainPtr<CFURLRef> urlRef(AdoptCF, link.createCFURL());
+ if (!urlRef)
+ return;
+
+ CGContextRef context = platformContext();
+
+ // Get the bounding box to handle clipping.
+ CGRect box = CGContextGetClipBoundingBox(context);
+
+ IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
+ IntRect rect = destRect;
+ rect.intersect(intBox);
+
+ CGPDFContextSetURLForRect(context, urlRef.get(),
+ CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode)
+{
+ if (paintingDisabled())
+ return;
+
+ CGInterpolationQuality quality = kCGInterpolationDefault;
+ switch (mode) {
+ case InterpolationDefault:
+ quality = kCGInterpolationDefault;
+ break;
+ case InterpolationNone:
+ quality = kCGInterpolationNone;
+ break;
+ case InterpolationLow:
+ quality = kCGInterpolationLow;
+ break;
+
+ // Fall through to InterpolationHigh if kCGInterpolationMedium is not usable.
+ case InterpolationMedium:
+#if USE(CG_INTERPOLATION_MEDIUM)
+ quality = kCGInterpolationMedium;
+ break;
+#endif
+ case InterpolationHigh:
+ quality = kCGInterpolationHigh;
+ break;
+ }
+ CGContextSetInterpolationQuality(platformContext(), quality);
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ if (paintingDisabled())
+ return InterpolationDefault;
+
+ CGInterpolationQuality quality = CGContextGetInterpolationQuality(platformContext());
+ switch (quality) {
+ case kCGInterpolationDefault:
+ return InterpolationDefault;
+ case kCGInterpolationNone:
+ return InterpolationNone;
+ case kCGInterpolationLow:
+ return InterpolationLow;
+#if HAVE(CG_INTERPOLATION_MEDIUM)
+ // kCGInterpolationMedium is known to be present in the CGInterpolationQuality enum.
+ case kCGInterpolationMedium:
+#if USE(CG_INTERPOLATION_MEDIUM)
+ // Only map to InterpolationMedium if targeting a system that understands it.
+ return InterpolationMedium;
+#else
+ return InterpolationDefault;
+#endif // USE(CG_INTERPOLATION_MEDIUM)
+#endif // HAVE(CG_INTERPOLATION_MEDIUM)
+ case kCGInterpolationHigh:
+ return InterpolationHigh;
+ }
+ return InterpolationDefault;
+}
+
+void GraphicsContext::setAllowsFontSmoothing(bool allowsFontSmoothing)
+{
+ UNUSED_PARAM(allowsFontSmoothing);
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ CGContextRef context = platformContext();
+ CGContextSetAllowsFontSmoothing(context, allowsFontSmoothing);
+#endif
+}
+
+void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
+{
+ if (paintingDisabled())
+ return;
+
+ // Wow, wish CG had used bits here.
+ CGContextRef context = platformContext();
+ switch (mode) {
+ case TextModeInvisible:
+ CGContextSetTextDrawingMode(context, kCGTextInvisible);
+ break;
+ case TextModeFill:
+ CGContextSetTextDrawingMode(context, kCGTextFill);
+ break;
+ case TextModeStroke:
+ CGContextSetTextDrawingMode(context, kCGTextStroke);
+ break;
+ case TextModeFill | TextModeStroke:
+ CGContextSetTextDrawingMode(context, kCGTextFillStroke);
+ break;
+ case TextModeClip:
+ CGContextSetTextDrawingMode(context, kCGTextClip);
+ break;
+ case TextModeFill | TextModeClip:
+ CGContextSetTextDrawingMode(context, kCGTextFillClip);
+ break;
+ case TextModeStroke | TextModeClip:
+ CGContextSetTextDrawingMode(context, kCGTextStrokeClip);
+ break;
+ case TextModeFill | TextModeStroke | TextModeClip:
+ CGContextSetTextDrawingMode(context, kCGTextFillStrokeClip);
+ break;
+ default:
+ break;
+ }
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+ setCGStrokeColor(platformContext(), color, colorSpace);
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetLineWidth(platformContext(), thickness);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+ setCGFillColor(platformContext(), color, colorSpace);
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetShouldAntialias(platformContext(), enable);
+}
+
+void GraphicsContext::setPlatformShouldSmoothFonts(bool enable)
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetShouldSmoothFonts(platformContext(), enable);
+}
+
+#ifndef BUILDING_ON_TIGER // Tiger's setPlatformCompositeOperation() is defined in GraphicsContextMac.mm.
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator mode)
+{
+ if (paintingDisabled())
+ return;
+
+ CGBlendMode target = kCGBlendModeNormal;
+ switch (mode) {
+ case CompositeClear:
+ target = kCGBlendModeClear;
+ break;
+ case CompositeCopy:
+ target = kCGBlendModeCopy;
+ break;
+ case CompositeSourceOver:
+ //kCGBlendModeNormal
+ break;
+ case CompositeSourceIn:
+ target = kCGBlendModeSourceIn;
+ break;
+ case CompositeSourceOut:
+ target = kCGBlendModeSourceOut;
+ break;
+ case CompositeSourceAtop:
+ target = kCGBlendModeSourceAtop;
+ break;
+ case CompositeDestinationOver:
+ target = kCGBlendModeDestinationOver;
+ break;
+ case CompositeDestinationIn:
+ target = kCGBlendModeDestinationIn;
+ break;
+ case CompositeDestinationOut:
+ target = kCGBlendModeDestinationOut;
+ break;
+ case CompositeDestinationAtop:
+ target = kCGBlendModeDestinationAtop;
+ break;
+ case CompositeXOR:
+ target = kCGBlendModeXOR;
+ break;
+ case CompositePlusDarker:
+ target = kCGBlendModePlusDarker;
+ break;
+ case CompositeHighlight:
+ // currently unsupported
+ break;
+ case CompositePlusLighter:
+ target = kCGBlendModePlusLighter;
+ break;
+ }
+ CGContextSetBlendMode(platformContext(), target);
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.h b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.h
new file mode 100644
index 0000000..5de95ef
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 GraphicsContextCG_h
+#define GraphicsContextCG_h
+
+#include "GraphicsContext.h"
+
+typedef struct CGColorSpace *CGColorSpaceRef;
+
+namespace WebCore {
+
+CGColorSpaceRef deviceRGBColorSpaceRef();
+CGColorSpaceRef sRGBColorSpaceRef();
+CGColorSpaceRef linearRGBColorSpaceRef();
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
new file mode 100644
index 0000000..1d0a99f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include <wtf/RetainPtr.h>
+#include <CoreGraphics/CGContext.h>
+
+namespace WebCore {
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContextPlatformPrivate(CGContextRef cgContext)
+ : m_cgContext(cgContext)
+#if PLATFORM(WIN)
+ , m_hdc(0)
+ , m_transparencyCount(0)
+ , m_shouldIncludeChildWindows(false)
+#endif
+ , m_userToDeviceTransformKnownToBeIdentity(false)
+ {
+ }
+
+ ~GraphicsContextPlatformPrivate()
+ {
+ }
+
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
+ // These methods do nothing on Mac.
+ void save() {}
+ void restore() {}
+ void flush() {}
+ void clip(const FloatRect&) {}
+ void clip(const Path&) {}
+ void scale(const FloatSize&) {}
+ void rotate(float) {}
+ void translate(float, float) {}
+ void concatCTM(const AffineTransform&) {}
+ void beginTransparencyLayer() {}
+ void endTransparencyLayer() {}
+#endif
+
+#if PLATFORM(WIN)
+ // On Windows, we need to update the HDC for form controls to draw in the right place.
+ void save();
+ void restore();
+ void flush();
+ void clip(const FloatRect&);
+ void clip(const Path&);
+ void scale(const FloatSize&);
+ void rotate(float);
+ void translate(float, float);
+ void concatCTM(const AffineTransform&);
+ void beginTransparencyLayer() { m_transparencyCount++; }
+ void endTransparencyLayer() { m_transparencyCount--; }
+
+ HDC m_hdc;
+ unsigned m_transparencyCount;
+ bool m_shouldIncludeChildWindows;
+#endif
+
+ RetainPtr<CGContextRef> m_cgContext;
+ bool m_userToDeviceTransformKnownToBeIdentity;
+};
+
+}
diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp
new file mode 100644
index 0000000..75a36e5
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "Base64.h"
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include "GraphicsContextCG.h"
+#include "MIMETypeRegistry.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/Assertions.h>
+#include <wtf/text/StringConcatenate.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Threading.h>
+#include <math.h>
+
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+#include <IOSurface/IOSurface.h>
+#endif
+
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
+#include "WebCoreSystemInterface.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+static RetainPtr<IOSurfaceRef> createIOSurface(const IntSize& size)
+{
+ unsigned pixelFormat = 'BGRA';
+ unsigned bytesPerElement = 4;
+ int width = size.width();
+ int height = size.height();
+
+ unsigned long bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size.width() * bytesPerElement);
+ if (!bytesPerRow)
+ return 0;
+
+ unsigned long allocSize = IOSurfaceAlignProperty(kIOSurfaceAllocSize, size.height() * bytesPerRow);
+ if (!allocSize)
+ return 0;
+
+ const void *keys[6];
+ const void *values[6];
+ keys[0] = kIOSurfaceWidth;
+ values[0] = CFNumberCreate(0, kCFNumberIntType, &width);
+ keys[1] = kIOSurfaceHeight;
+ values[1] = CFNumberCreate(0, kCFNumberIntType, &height);
+ keys[2] = kIOSurfacePixelFormat;
+ values[2] = CFNumberCreate(0, kCFNumberIntType, &pixelFormat);
+ keys[3] = kIOSurfaceBytesPerElement;
+ values[3] = CFNumberCreate(0, kCFNumberIntType, &bytesPerElement);
+ keys[4] = kIOSurfaceBytesPerRow;
+ values[4] = CFNumberCreate(0, kCFNumberLongType, &bytesPerRow);
+ keys[5] = kIOSurfaceAllocSize;
+ values[5] = CFNumberCreate(0, kCFNumberLongType, &allocSize);
+
+ RetainPtr<CFDictionaryRef> dict(AdoptCF, CFDictionaryCreate(0, keys, values, 6, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ for (unsigned i = 0; i < 6; i++)
+ CFRelease(values[i]);
+
+ return RetainPtr<IOSurfaceRef>(AdoptCF, IOSurfaceCreate(dict.get()));
+}
+#endif
+
+static void releaseImageData(void*, const void* data, size_t)
+{
+ fastFree(const_cast<void*>(data));
+}
+
+ImageBufferData::ImageBufferData(const IntSize&)
+ : m_data(0)
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+ , m_surface(0)
+#endif
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success)
+ : m_data(size)
+ , m_size(size)
+ , m_accelerateRendering(renderingMode == Accelerated)
+{
+#if !USE(IOSURFACE_CANVAS_BACKING_STORE)
+ ASSERT(renderingMode == Unaccelerated);
+#endif
+ success = false; // Make early return mean failure.
+ if (size.width() < 0 || size.height() < 0)
+ return;
+
+ unsigned bytesPerRow = size.width();
+ if (bytesPerRow > 0x3FFFFFFF) // Protect against overflow
+ return;
+ bytesPerRow *= 4;
+ m_data.m_bytesPerRow = bytesPerRow;
+ size_t dataSize = size.height() * bytesPerRow;
+
+ switch (imageColorSpace) {
+ case ColorSpaceDeviceRGB:
+ m_data.m_colorSpace = deviceRGBColorSpaceRef();
+ break;
+ case ColorSpaceSRGB:
+ m_data.m_colorSpace = sRGBColorSpaceRef();
+ break;
+ case ColorSpaceLinearRGB:
+ m_data.m_colorSpace = linearRGBColorSpaceRef();
+ break;
+ }
+
+ RetainPtr<CGContextRef> cgContext;
+ if (!m_accelerateRendering) {
+ if (!tryFastCalloc(size.height(), bytesPerRow).getValue(m_data.m_data))
+ return;
+ ASSERT(!(reinterpret_cast<size_t>(m_data.m_data) & 2));
+
+ m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast;
+ cgContext.adoptCF(CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow, m_data.m_colorSpace, m_data.m_bitmapInfo));
+ // Create a live image that wraps the data.
+ m_data.m_dataProvider.adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, dataSize, releaseImageData));
+ } else {
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+ m_data.m_surface = createIOSurface(size);
+ cgContext.adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), size.width(), size.height(), m_data.m_colorSpace));
+#else
+ m_accelerateRendering = false; // Force to false on older platforms
+#endif
+ }
+
+ if (!cgContext)
+ return;
+
+ m_context.set(new GraphicsContext(cgContext.get()));
+ m_context->scale(FloatSize(1, -1));
+ m_context->translate(0, -size.height());
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+bool ImageBuffer::drawsUsingCopy() const
+{
+ return false;
+}
+
+PassRefPtr<Image> ImageBuffer::copyImage() const
+{
+ // BitmapImage will release the passed in CGImage on destruction
+ CGImageRef ctxImage = 0;
+ if (!m_accelerateRendering)
+ ctxImage = CGBitmapContextCreateImage(context()->platformContext());
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+ else
+ ctxImage = wkIOSurfaceContextCreateImage(context()->platformContext());
+#endif
+ return BitmapImage::create(ctxImage);
+}
+
+static CGImageRef cgImage(const IntSize& size, const ImageBufferData& data)
+{
+ return CGImageCreate(size.width(), size.height(), 8, 32, data.m_bytesPerRow,
+ data.m_colorSpace, data.m_bitmapInfo, data.m_dataProvider.get(), 0, true, kCGRenderingIntentDefault);
+}
+
+void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
+ CompositeOperator op, bool useLowQualityScale)
+{
+ if (!m_accelerateRendering) {
+ if (destContext == context()) {
+ // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first.
+ RefPtr<Image> copy = copyImage();
+ destContext->drawImage(copy.get(), ColorSpaceDeviceRGB, destRect, srcRect, op, useLowQualityScale);
+ } else {
+ RefPtr<Image> imageForRendering = BitmapImage::create(cgImage(m_size, m_data));
+ destContext->drawImage(imageForRendering.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
+ }
+ } else {
+ RefPtr<Image> copy = copyImage();
+ ColorSpace colorSpace = (destContext == context()) ? ColorSpaceDeviceRGB : styleColorSpace;
+ destContext->drawImage(copy.get(), colorSpace, destRect, srcRect, op, useLowQualityScale);
+ }
+}
+
+void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ if (!m_accelerateRendering) {
+ if (destContext == context()) {
+ // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first.
+ RefPtr<Image> copy = copyImage();
+ copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+ } else {
+ RefPtr<Image> imageForRendering = BitmapImage::create(cgImage(m_size, m_data));
+ imageForRendering->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+ }
+ } else {
+ RefPtr<Image> copy = copyImage();
+ copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+ }
+}
+
+void ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const
+{
+ CGContextRef platformContext = context->platformContext();
+ RetainPtr<CGImageRef> image;
+ if (!m_accelerateRendering)
+ image.adoptCF(cgImage(m_size, m_data));
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+ else
+ image.adoptCF(wkIOSurfaceContextCreateImage(platformContext));
+#endif
+ CGContextTranslateCTM(platformContext, rect.x(), rect.y() + rect.height());
+ CGContextScaleCTM(platformContext, 1, -1);
+ CGContextClipToMask(platformContext, FloatRect(FloatPoint(), rect.size()), image.get());
+ CGContextScaleCTM(platformContext, 1, -1);
+ CGContextTranslateCTM(platformContext, -rect.x(), -rect.y() - rect.height());
+}
+
+template <Multiply multiplied>
+PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size, bool accelerateRendering)
+{
+ RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4);
+ unsigned char* data = result->data();
+
+ if (rect.x() < 0 || rect.y() < 0 || rect.right() > size.width() || rect.bottom() > size.height())
+ memset(data, 0, result->length());
+
+ int originx = rect.x();
+ int destx = 0;
+ if (originx < 0) {
+ destx = -originx;
+ originx = 0;
+ }
+ int endx = rect.right();
+ if (endx > size.width())
+ endx = size.width();
+ int numColumns = endx - originx;
+
+ int originy = rect.y();
+ int desty = 0;
+ if (originy < 0) {
+ desty = -originy;
+ originy = 0;
+ }
+ int endy = rect.bottom();
+ if (endy > size.height())
+ endy = size.height();
+ int numRows = endy - originy;
+
+ unsigned destBytesPerRow = 4 * rect.width();
+ unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
+
+ unsigned srcBytesPerRow;
+ unsigned char* srcRows;
+
+ if (!accelerateRendering) {
+ srcBytesPerRow = 4 * size.width();
+ srcRows = reinterpret_cast<unsigned char*>(imageData.m_data) + originy * srcBytesPerRow + originx * 4;
+
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ unsigned char alpha = srcRows[basex + 3];
+ if (multiplied == Unmultiplied && alpha) {
+ destRows[basex] = (srcRows[basex] * 255) / alpha;
+ destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha;
+ destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha;
+ destRows[basex + 3] = alpha;
+ } else
+ reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0];
+ }
+ srcRows += srcBytesPerRow;
+ destRows += destBytesPerRow;
+ }
+ } else {
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+ IOSurfaceRef surface = imageData.m_surface.get();
+ IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0);
+ srcBytesPerRow = IOSurfaceGetBytesPerRow(surface);
+ srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4;
+
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ unsigned char alpha = srcRows[basex + 3];
+ if (multiplied == Unmultiplied && alpha) {
+ destRows[basex] = (srcRows[basex + 2] * 255) / alpha;
+ destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha;
+ destRows[basex + 2] = (srcRows[basex] * 255) / alpha;
+ destRows[basex + 3] = alpha;
+ } else {
+ destRows[basex] = srcRows[basex + 2];
+ destRows[basex + 1] = srcRows[basex + 1];
+ destRows[basex + 2] = srcRows[basex];
+ destRows[basex + 3] = alpha;
+ }
+ }
+ srcRows += srcBytesPerRow;
+ destRows += destBytesPerRow;
+ }
+ IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0);
+#else
+ ASSERT_NOT_REACHED();
+#endif
+ }
+
+ return result.release();
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ if (m_accelerateRendering)
+ CGContextFlush(context()->platformContext());
+ return getImageData<Unmultiplied>(rect, m_data, m_size, m_accelerateRendering);
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ if (m_accelerateRendering)
+ CGContextFlush(context()->platformContext());
+ return getImageData<Premultiplied>(rect, m_data, m_size, m_accelerateRendering);
+}
+
+template <Multiply multiplied>
+void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size, bool accelerateRendering)
+{
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originx = sourceRect.x();
+ int destx = destPoint.x() + sourceRect.x();
+ ASSERT(destx >= 0);
+ ASSERT(destx < size.width());
+ ASSERT(originx >= 0);
+ ASSERT(originx <= sourceRect.right());
+
+ int endx = destPoint.x() + sourceRect.right();
+ ASSERT(endx <= size.width());
+
+ int numColumns = endx - destx;
+
+ int originy = sourceRect.y();
+ int desty = destPoint.y() + sourceRect.y();
+ ASSERT(desty >= 0);
+ ASSERT(desty < size.height());
+ ASSERT(originy >= 0);
+ ASSERT(originy <= sourceRect.bottom());
+
+ int endy = destPoint.y() + sourceRect.bottom();
+ ASSERT(endy <= size.height());
+ int numRows = endy - desty;
+
+ unsigned srcBytesPerRow = 4 * sourceSize.width();
+ unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4;
+ unsigned destBytesPerRow;
+ unsigned char* destRows;
+
+ if (!accelerateRendering) {
+ destBytesPerRow = 4 * size.width();
+ destRows = reinterpret_cast<unsigned char*>(imageData.m_data) + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ unsigned char alpha = srcRows[basex + 3];
+ if (multiplied == Unmultiplied && alpha != 255) {
+ destRows[basex] = (srcRows[basex] * alpha + 254) / 255;
+ destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255;
+ destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255;
+ destRows[basex + 3] = alpha;
+ } else
+ reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0];
+ }
+ destRows += destBytesPerRow;
+ srcRows += srcBytesPerRow;
+ }
+ } else {
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+ IOSurfaceRef surface = imageData.m_surface.get();
+ IOSurfaceLock(surface, 0, 0);
+ destBytesPerRow = IOSurfaceGetBytesPerRow(surface);
+ destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + desty * destBytesPerRow + destx * 4;
+
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ unsigned char alpha = srcRows[basex + 3];
+ if (multiplied == Unmultiplied && alpha != 255) {
+ destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255;
+ destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255;
+ destRows[basex + 2] = (srcRows[basex] * alpha + 254) / 255;
+ destRows[basex + 3] = alpha;
+ } else {
+ destRows[basex] = srcRows[basex + 2];
+ destRows[basex + 1] = srcRows[basex + 1];
+ destRows[basex + 2] = srcRows[basex];
+ destRows[basex + 3] = alpha;
+ }
+ }
+ destRows += destBytesPerRow;
+ srcRows += srcBytesPerRow;
+ }
+ IOSurfaceUnlock(surface, 0, 0);
+#else
+ ASSERT_NOT_REACHED();
+#endif
+ }
+}
+
+void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ if (m_accelerateRendering)
+ CGContextFlush(context()->platformContext());
+ putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size, m_accelerateRendering);
+}
+
+void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ if (m_accelerateRendering)
+ CGContextFlush(context()->platformContext());
+ putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size, m_accelerateRendering);
+}
+
+static inline CFStringRef jpegUTI()
+{
+#if PLATFORM(WIN)
+ static const CFStringRef kUTTypeJPEG = CFSTR("public.jpeg");
+#endif
+ return kUTTypeJPEG;
+}
+
+static RetainPtr<CFStringRef> utiFromMIMEType(const String& mimeType)
+{
+#if PLATFORM(MAC)
+ RetainPtr<CFStringRef> mimeTypeCFString(AdoptCF, mimeType.createCFString());
+ return RetainPtr<CFStringRef>(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeTypeCFString.get(), 0));
+#else
+ ASSERT(isMainThread()); // It is unclear if CFSTR is threadsafe.
+
+ // FIXME: Add Windows support for all the supported UTIs when a way to convert from MIMEType to UTI reliably is found.
+ // For now, only support PNG, JPEG, and GIF. See <rdar://problem/6095286>.
+ static const CFStringRef kUTTypePNG = CFSTR("public.png");
+ static const CFStringRef kUTTypeGIF = CFSTR("com.compuserve.gif");
+
+ if (equalIgnoringCase(mimeType, "image/png"))
+ return kUTTypePNG;
+ if (equalIgnoringCase(mimeType, "image/jpeg"))
+ return jpegUTI();
+ if (equalIgnoringCase(mimeType, "image/gif"))
+ return kUTTypeGIF;
+
+ ASSERT_NOT_REACHED();
+ return kUTTypePNG;
+#endif
+}
+
+String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const
+{
+ ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+
+ RetainPtr<CGImageRef> image;
+ if (!m_accelerateRendering)
+ image.adoptCF(CGBitmapContextCreateImage(context()->platformContext()));
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+ else
+ image.adoptCF(wkIOSurfaceContextCreateImage(context()->platformContext()));
+#endif
+
+ if (!image)
+ return "data:,";
+
+ RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(kCFAllocatorDefault, 0));
+ if (!data)
+ return "data:,";
+
+ RetainPtr<CFStringRef> uti = utiFromMIMEType(mimeType);
+ ASSERT(uti);
+
+ RetainPtr<CGImageDestinationRef> destination(AdoptCF, CGImageDestinationCreateWithData(data.get(), uti.get(), 1, 0));
+ if (!destination)
+ return "data:,";
+
+ RetainPtr<CFDictionaryRef> imageProperties = 0;
+ if (CFEqual(uti.get(), jpegUTI()) && quality && *quality >= 0.0 && *quality <= 1.0) {
+ // Apply the compression quality to the image destination.
+ RetainPtr<CFNumberRef> compressionQuality(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, quality));
+ const void* key = kCGImageDestinationLossyCompressionQuality;
+ const void* value = compressionQuality.get();
+ imageProperties.adoptCF(CFDictionaryCreate(0, &key, &value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ }
+
+ CGImageDestinationAddImage(destination.get(), image.get(), imageProperties.get());
+ CGImageDestinationFinalize(destination.get());
+
+ Vector<char> out;
+ base64Encode(reinterpret_cast<const char*>(CFDataGetBytePtr(data.get())), CFDataGetLength(data.get()), out);
+
+ return makeString("data:", mimeType, ";base64,", out);
+}
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferData.h b/Source/WebCore/platform/graphics/cg/ImageBufferData.h
new file mode 100644
index 0000000..1f706ec
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/ImageBufferData.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ImageBufferData_h
+#define ImageBufferData_h
+
+#include "Image.h"
+#include <wtf/RefPtr.h>
+#include <wtf/RetainPtr.h>
+
+typedef struct __IOSurface *IOSurfaceRef;
+typedef struct CGColorSpace *CGColorSpaceRef;
+typedef struct CGDataProvider *CGDataProviderRef;
+typedef uint32_t CGBitmapInfo;
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ void* m_data;
+
+ RetainPtr<CGDataProviderRef> m_dataProvider;
+ CGBitmapInfo m_bitmapInfo;
+ unsigned m_bytesPerRow;
+ CGColorSpaceRef m_colorSpace;
+ RetainPtr<IOSurfaceRef> m_surface;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/Source/WebCore/platform/graphics/cg/ImageCG.cpp b/Source/WebCore/platform/graphics/cg/ImageCG.cpp
new file mode 100644
index 0000000..dfee96a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/ImageCG.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "BitmapImage.h"
+
+#if PLATFORM(CG)
+
+#include "AffineTransform.h"
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "GraphicsContextCG.h"
+#include "ImageObserver.h"
+#include "PDFDocumentImage.h"
+#include "PlatformString.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/RetainPtr.h>
+
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
+#include "WebCoreSystemInterface.h"
+#endif
+
+#if PLATFORM(WIN)
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
+
+namespace WebCore {
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ CGImageRelease(m_frame);
+ m_frame = 0;
+ return true;
+ }
+ return false;
+}
+
+// ================================================
+// Image Class
+// ================================================
+
+BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
+ , m_animationFinished(true)
+ , m_allDataReceived(true)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ CGFloat width = CGImageGetWidth(cgImage);
+ CGFloat height = CGImageGetHeight(cgImage);
+ m_decodedSize = width * height * 4;
+ m_size = IntSize(width, height);
+
+ m_frames.grow(1);
+ m_frames[0].m_frame = cgImage;
+ m_frames[0].m_hasAlpha = true;
+ m_frames[0].m_haveMetadata = true;
+ checkForSolidColor();
+}
+
+// Drawing Routines
+
+void BitmapImage::checkForSolidColor()
+{
+ m_checkedForSolidColor = true;
+ if (frameCount() > 1) {
+ m_isSolidColor = false;
+ return;
+ }
+
+ CGImageRef image = frameAtIndex(0);
+
+ // Currently we only check for solid color in the important special case of a 1x1 image.
+ if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) {
+ unsigned char pixel[4]; // RGBA
+ RetainPtr<CGContextRef> bmap(AdoptCF, CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), deviceRGBColorSpaceRef(),
+ kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big));
+ if (!bmap)
+ return;
+ GraphicsContext(bmap.get()).setCompositeOperation(CompositeCopy);
+ CGRect dst = { {0, 0}, {1, 1} };
+ CGContextDrawImage(bmap.get(), dst, image);
+ if (pixel[3] == 0)
+ m_solidColor = Color(0, 0, 0, 0);
+ else
+ m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]);
+ m_isSolidColor = true;
+ }
+}
+
+static RetainPtr<CGImageRef> imageWithColorSpace(CGImageRef originalImage, ColorSpace colorSpace)
+{
+ CGColorSpaceRef originalColorSpace = CGImageGetColorSpace(originalImage);
+
+ // If the image already has a (non-device) color space, we don't want to
+ // override it, so return.
+ if (!originalColorSpace || !CFEqual(originalColorSpace, deviceRGBColorSpaceRef()))
+ return originalImage;
+
+ switch (colorSpace) {
+ case ColorSpaceDeviceRGB:
+ return originalImage;
+ case ColorSpaceSRGB:
+ return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, sRGBColorSpaceRef()));
+ case ColorSpaceLinearRGB:
+ return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, linearRGBColorSpaceRef()));
+ }
+
+ ASSERT_NOT_REACHED();
+ return originalImage;
+}
+
+CGImageRef BitmapImage::getCGImageRef()
+{
+ return frameAtIndex(0);
+}
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ startAnimation();
+
+ RetainPtr<CGImageRef> image = frameAtIndex(m_currentFrame);
+ if (!image) // If it's too early we won't have an image yet.
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp);
+ return;
+ }
+
+ float currHeight = CGImageGetHeight(image.get());
+ if (currHeight <= srcRect.y())
+ return;
+
+ CGContextRef context = ctxt->platformContext();
+ ctxt->save();
+
+ bool shouldUseSubimage = false;
+
+ // If the source rect is a subportion of the image, then we compute an inflated destination rect that will hold the entire image
+ // and then set a clip to the portion that we want to display.
+ FloatRect adjustedDestRect = destRect;
+ FloatSize selfSize = currentFrameSize();
+ if (srcRect.size() != selfSize) {
+ CGInterpolationQuality interpolationQuality = CGContextGetInterpolationQuality(context);
+ // When the image is scaled using high-quality interpolation, we create a temporary CGImage
+ // containing only the portion we want to display. We need to do this because high-quality
+ // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed
+ // into the destination rect. See <rdar://problem/6112909>.
+ shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped());
+ float xScale = srcRect.width() / destRect.width();
+ float yScale = srcRect.height() / destRect.height();
+ if (shouldUseSubimage) {
+ FloatRect subimageRect = srcRect;
+ float leftPadding = srcRect.x() - floorf(srcRect.x());
+ float topPadding = srcRect.y() - floorf(srcRect.y());
+
+ subimageRect.move(-leftPadding, -topPadding);
+ adjustedDestRect.move(-leftPadding / xScale, -topPadding / yScale);
+
+ subimageRect.setWidth(ceilf(subimageRect.width() + leftPadding));
+ adjustedDestRect.setWidth(subimageRect.width() / xScale);
+
+ subimageRect.setHeight(ceilf(subimageRect.height() + topPadding));
+ adjustedDestRect.setHeight(subimageRect.height() / yScale);
+
+ image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect));
+ if (currHeight < srcRect.bottom()) {
+ ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y);
+ adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale);
+ }
+ } else {
+ adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale));
+ adjustedDestRect.setSize(FloatSize(selfSize.width() / xScale, selfSize.height() / yScale));
+ }
+
+ CGContextClipToRect(context, destRect);
+ }
+
+ // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly.
+ if (!shouldUseSubimage && currHeight < selfSize.height())
+ adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height());
+
+ ctxt->setCompositeOperation(compositeOp);
+
+ // Flip the coords.
+ CGContextScaleCTM(context, 1, -1);
+ adjustedDestRect.setY(-adjustedDestRect.bottom());
+
+ // Adjust the color space.
+ image = imageWithColorSpace(image.get(), styleColorSpace);
+
+ // Draw the image.
+ CGContextDrawImage(context, adjustedDestRect, image.get());
+
+ ctxt->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+static void drawPatternCallback(void* info, CGContextRef context)
+{
+ CGImageRef image = (CGImageRef)info;
+ CGContextDrawImage(context, GraphicsContext(context).roundToDevicePixels(FloatRect(0, 0, CGImageGetWidth(image), CGImageGetHeight(image))), image);
+}
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ if (!nativeImageForCurrentFrame())
+ return;
+
+ ASSERT(patternTransform.isInvertible());
+ if (!patternTransform.isInvertible())
+ // Avoid a hang under CGContextDrawTiledImage on release builds.
+ return;
+
+ CGContextRef context = ctxt->platformContext();
+ ctxt->save();
+ CGContextClipToRect(context, destRect);
+ ctxt->setCompositeOperation(op);
+ CGContextTranslateCTM(context, destRect.x(), destRect.y() + destRect.height());
+ CGContextScaleCTM(context, 1, -1);
+
+ // Compute the scaled tile size.
+ float scaledTileHeight = tileRect.height() * narrowPrecisionToFloat(patternTransform.d());
+
+ // We have to adjust the phase to deal with the fact we're in Cartesian space now (with the bottom left corner of destRect being
+ // the origin).
+ float adjustedX = phase.x() - destRect.x() + tileRect.x() * narrowPrecisionToFloat(patternTransform.a()); // We translated the context so that destRect.x() is the origin, so subtract it out.
+ float adjustedY = destRect.height() - (phase.y() - destRect.y() + tileRect.y() * narrowPrecisionToFloat(patternTransform.d()) + scaledTileHeight);
+
+ CGImageRef tileImage = nativeImageForCurrentFrame();
+ float h = CGImageGetHeight(tileImage);
+
+ RetainPtr<CGImageRef> subImage;
+ if (tileRect.size() == size())
+ subImage = tileImage;
+ else {
+ // Copying a sub-image out of a partially-decoded image stops the decoding of the original image. It should never happen
+ // because sub-images are only used for border-image, which only renders when the image is fully decoded.
+ ASSERT(h == height());
+ subImage.adoptCF(CGImageCreateWithImageInRect(tileImage, tileRect));
+ }
+
+ // Adjust the color space.
+ subImage = imageWithColorSpace(subImage.get(), styleColorSpace);
+
+#ifndef BUILDING_ON_TIGER
+ // Leopard has an optimized call for the tiling of image patterns, but we can only use it if the image has been decoded enough that
+ // its buffer is the same size as the overall image. Because a partially decoded CGImageRef with a smaller width or height than the
+ // overall image buffer needs to tile with "gaps", we can't use the optimized tiling call in that case.
+ // FIXME: Could create WebKitSystemInterface SPI for CGCreatePatternWithImage2 and probably make Tiger tile faster as well.
+ // FIXME: We cannot use CGContextDrawTiledImage with scaled tiles on Leopard, because it suffers from rounding errors. Snow Leopard is ok.
+ float scaledTileWidth = tileRect.width() * narrowPrecisionToFloat(patternTransform.a());
+ float w = CGImageGetWidth(tileImage);
+#ifdef BUILDING_ON_LEOPARD
+ if (w == size().width() && h == size().height() && scaledTileWidth == tileRect.width() && scaledTileHeight == tileRect.height())
+#else
+ if (w == size().width() && h == size().height())
+#endif
+ CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage.get());
+ else {
+#endif
+
+ // On Leopard, this code now only runs for partially decoded images whose buffers do not yet match the overall size of the image.
+ // On Tiger this code runs all the time. This code is suboptimal because the pattern does not reference the image directly, and the
+ // pattern is destroyed before exiting the function. This means any decoding the pattern does doesn't end up cached anywhere, so we
+ // redecode every time we paint.
+ static const CGPatternCallbacks patternCallbacks = { 0, drawPatternCallback, NULL };
+ CGAffineTransform matrix = CGAffineTransformMake(narrowPrecisionToCGFloat(patternTransform.a()), 0, 0, narrowPrecisionToCGFloat(patternTransform.d()), adjustedX, adjustedY);
+ matrix = CGAffineTransformConcat(matrix, CGContextGetCTM(context));
+ // The top of a partially-decoded image is drawn at the bottom of the tile. Map it to the top.
+ matrix = CGAffineTransformTranslate(matrix, 0, size().height() - h);
+ RetainPtr<CGPatternRef> pattern(AdoptCF, CGPatternCreate(subImage.get(), CGRectMake(0, 0, tileRect.width(), tileRect.height()),
+ matrix, tileRect.width(), tileRect.height(),
+ kCGPatternTilingConstantSpacing, true, &patternCallbacks));
+ if (!pattern) {
+ ctxt->restore();
+ return;
+ }
+
+ RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0));
+
+ CGFloat alpha = 1;
+ RetainPtr<CGColorRef> color(AdoptCF, CGColorCreateWithPattern(patternSpace.get(), pattern.get(), &alpha));
+ CGContextSetFillColorSpace(context, patternSpace.get());
+
+ // FIXME: Really want a public API for this. It is just CGContextSetBaseCTM(context, CGAffineTransformIdentiy).
+ wkSetPatternBaseCTM(context, CGAffineTransformIdentity);
+ CGContextSetPatternPhase(context, CGSizeZero);
+
+ CGContextSetFillColorWithColor(context, color.get());
+ CGContextFillRect(context, CGContextGetClipBoundingBox(context));
+
+#ifndef BUILDING_ON_TIGER
+ }
+#endif
+
+ ctxt->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp
new file mode 100644
index 0000000..4ed8684
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ImageSource.h"
+
+#if PLATFORM(CG)
+#include "ImageSourceCG.h"
+
+#include "IntPoint.h"
+#include "IntSize.h"
+#include "MIMETypeRegistry.h"
+#include "SharedBuffer.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/UnusedParam.h>
+
+using namespace std;
+
+namespace WebCore {
+
+static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
+
+#if !PLATFORM(MAC)
+size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count)
+{
+ SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
+ size_t sourceSize = sharedBuffer->size();
+ if (position >= sourceSize)
+ return 0;
+
+ const char* source = sharedBuffer->data() + position;
+ size_t amount = min<size_t>(count, sourceSize - position);
+ memcpy(buffer, source, amount);
+ return amount;
+}
+
+void sharedBufferRelease(void* info)
+{
+ SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
+ sharedBuffer->deref();
+}
+#endif
+
+ImageSource::ImageSource(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
+ : m_decoder(0)
+ // FIXME: m_premultiplyAlpha is ignored in cg at the moment.
+ , m_alphaOption(alphaOption)
+ , m_gammaAndColorProfileOption(gammaAndColorProfileOption)
+{
+}
+
+ImageSource::~ImageSource()
+{
+ clear(true);
+}
+
+void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool allDataReceived)
+{
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ // Recent versions of ImageIO discard previously decoded image frames if the client
+ // application no longer holds references to them, so there's no need to throw away
+ // the decoder unless we're explicitly asked to destroy all of the frames.
+
+ if (!destroyAllFrames)
+ return;
+#else
+ // Older versions of ImageIO hold references to previously decoded image frames.
+ // There is no API to selectively release some of the frames it is holding, and
+ // if we don't release the frames we use too much memory on large images.
+ // Destroying the decoder is the only way to release previous frames.
+
+ UNUSED_PARAM(destroyAllFrames);
+#endif
+
+ if (m_decoder) {
+ CFRelease(m_decoder);
+ m_decoder = 0;
+ }
+ if (data)
+ setData(data, allDataReceived);
+}
+
+static CFDictionaryRef imageSourceOptions()
+{
+ static CFDictionaryRef options;
+
+ if (!options) {
+ const unsigned numOptions = 2;
+ const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
+ const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue };
+ options = CFDictionaryCreate(NULL, keys, values, numOptions,
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ }
+ return options;
+}
+
+bool ImageSource::initialized() const
+{
+ return m_decoder;
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+#if PLATFORM(MAC)
+ if (!m_decoder)
+ m_decoder = CGImageSourceCreateIncremental(0);
+ // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability
+ // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer.
+ RetainPtr<CFDataRef> cfData(AdoptCF, data->createCFData());
+ CGImageSourceUpdateData(m_decoder, cfData.get(), allDataReceived);
+#else
+ if (!m_decoder) {
+ m_decoder = CGImageSourceCreateIncremental(0);
+ } else if (allDataReceived) {
+#if !PLATFORM(WIN)
+ // 10.6 bug workaround: image sources with final=false fail to draw into PDF contexts, so re-create image source
+ // when data is complete. <rdar://problem/7874035> (<http://openradar.appspot.com/7874035>)
+ CFRelease(m_decoder);
+ m_decoder = CGImageSourceCreateIncremental(0);
+#endif
+ }
+ // Create a CGDataProvider to wrap the SharedBuffer.
+ data->ref();
+ // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer
+ // does not provide a way to lock down the byte pointer and guarantee that it won't move, which
+ // is a requirement for using the GetBytePointer callback.
+ CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, sharedBufferRelease };
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirect(data, data->size(), &providerCallbacks));
+ CGImageSourceUpdateDataProvider(m_decoder, dataProvider.get(), allDataReceived);
+#endif
+}
+
+String ImageSource::filenameExtension() const
+{
+ if (!m_decoder)
+ return String();
+ CFStringRef imageSourceType = CGImageSourceGetType(m_decoder);
+ return WebCore::preferredExtensionForImageSourceType(imageSourceType);
+}
+
+bool ImageSource::isSizeAvailable()
+{
+ bool result = false;
+ CGImageSourceStatus imageSourceStatus = CGImageSourceGetStatus(m_decoder);
+
+ // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus!
+ if (imageSourceStatus >= kCGImageStatusIncomplete) {
+ RetainPtr<CFDictionaryRef> image0Properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()));
+ if (image0Properties) {
+ CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelWidth);
+ CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelHeight);
+ result = widthNumber && heightNumber;
+ }
+ }
+
+ return result;
+}
+
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
+{
+ IntSize result;
+ RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()));
+ if (properties) {
+ int w = 0, h = 0;
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &w);
+ num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &h);
+ result = IntSize(w, h);
+ }
+ return result;
+}
+
+IntSize ImageSource::size() const
+{
+ return frameSizeAtIndex(0);
+}
+
+bool ImageSource::getHotSpot(IntPoint& hotSpot) const
+{
+ RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()));
+ if (!properties)
+ return false;
+
+ int x = -1, y = -1;
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotX"));
+ if (!num || !CFNumberGetValue(num, kCFNumberIntType, &x))
+ return false;
+
+ num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotY"));
+ if (!num || !CFNumberGetValue(num, kCFNumberIntType, &y))
+ return false;
+
+ if (x < 0 || y < 0)
+ return false;
+
+ hotSpot = IntPoint(x, y);
+ return true;
+}
+
+int ImageSource::repetitionCount()
+{
+ int result = cAnimationLoopOnce; // No property means loop once.
+ if (!initialized())
+ return result;
+
+ RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyProperties(m_decoder, imageSourceOptions()));
+ if (properties) {
+ CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary);
+ if (gifProperties) {
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount);
+ if (num) {
+ // A property with value 0 means loop forever.
+ CFNumberGetValue(num, kCFNumberIntType, &result);
+ if (!result)
+ result = cAnimationLoopInfinite;
+ }
+ } else
+ result = cAnimationNone; // Turns out we're not a GIF after all, so we don't animate.
+ }
+
+ return result;
+}
+
+size_t ImageSource::frameCount() const
+{
+ return m_decoder ? CGImageSourceGetCount(m_decoder) : 0;
+}
+
+CGImageRef ImageSource::createFrameAtIndex(size_t index)
+{
+ if (!initialized())
+ return 0;
+
+ RetainPtr<CGImageRef> image(AdoptCF, CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions()));
+ CFStringRef imageUTI = CGImageSourceGetType(m_decoder);
+ static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image");
+ if (!imageUTI || !CFEqual(imageUTI, xbmUTI))
+ return image.releaseRef();
+
+ // If it is an xbm image, mask out all the white areas to render them transparent.
+ const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255};
+ RetainPtr<CGImageRef> maskedImage(AdoptCF, CGImageCreateWithMaskingColors(image.get(), maskingColors));
+ if (!maskedImage)
+ return image.releaseRef();
+
+ return maskedImage.releaseRef();
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ ASSERT(frameCount());
+
+ // CGImageSourceGetStatusAtIndex claims that all frames of a multi-frame image are incomplete
+ // when we've not yet received the complete data for an image that is using an incremental data
+ // source (<rdar://problem/7679174>). We work around this by special-casing all frames except the
+ // last in an image and treating them as complete if they are present and reported as being
+ // incomplete. We do this on the assumption that loading new data can only modify the existing last
+ // frame or append new frames. The last frame is only treated as being complete if the image source
+ // reports it as such. This ensures that it is truly the last frame of the image rather than just
+ // the last that we currently have data for.
+
+ CGImageSourceStatus frameStatus = CGImageSourceGetStatusAtIndex(m_decoder, index);
+ if (index < frameCount() - 1)
+ return frameStatus >= kCGImageStatusIncomplete;
+
+ return frameStatus == kCGImageStatusComplete;
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ if (!initialized())
+ return 0;
+
+ float duration = 0;
+ RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()));
+ if (properties) {
+ CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary);
+ if (typeProperties) {
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime);
+ if (num)
+ CFNumberGetValue(num, kCFNumberFloatType, &duration);
+ }
+ }
+
+ // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
+ // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
+ // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
+ // for more information.
+ if (duration < 0.011f)
+ return 0.100f;
+ return duration;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t)
+{
+ if (!m_decoder)
+ return false;
+
+ CFStringRef imageType = CGImageSourceGetType(m_decoder);
+
+ // Return false if there is no image type or the image type is JPEG, because
+ // JPEG does not support alpha transparency.
+ if (!imageType || CFEqual(imageType, CFSTR("public.jpeg")))
+ return false;
+
+ // FIXME: Could return false for other non-transparent image formats.
+ // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary
+ // to determine whether or not a transparent color was defined.
+ return true;
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/ImageSourceCG.h b/Source/WebCore/platform/graphics/cg/ImageSourceCG.h
new file mode 100644
index 0000000..bff8162
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/ImageSourceCG.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 ImageSourceCG_h
+#define ImageSourceCG_h
+
+#include "ImageSource.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+String preferredExtensionForImageSourceType(const String& type);
+
+String MIMETypeForImageSourceType(const String& type);
+
+#if !PLATFORM(MAC)
+size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count);
+#endif
+
+}
+
+#endif // ImageSourceCG_h
diff --git a/Source/WebCore/platform/graphics/cg/ImageSourceCGMac.mm b/Source/WebCore/platform/graphics/cg/ImageSourceCGMac.mm
new file mode 100644
index 0000000..297e30a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/ImageSourceCGMac.mm
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
+ */
+
+#import "config.h"
+#import "ImageSourceCG.h"
+
+#import "PlatformString.h"
+#import "wtf/RetainPtr.h"
+
+namespace WebCore {
+
+String MIMETypeForImageSourceType(const String& uti)
+{
+ RetainPtr<CFStringRef> utiref(AdoptCF, uti.createCFString());
+ RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(utiref.get(), kUTTagClassMIMEType));
+ return mime.get();
+}
+
+String preferredExtensionForImageSourceType(const String& uti)
+{
+ RetainPtr<CFStringRef> type(AdoptCF, uti.createCFString());
+ RetainPtr<CFStringRef> extension(AdoptCF, UTTypeCopyPreferredTagWithClass(type.get(), kUTTagClassFilenameExtension));
+ return extension.get();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp b/Source/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp
new file mode 100644
index 0000000..ef69e5e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
+ */
+
+#include "config.h"
+#include "ImageSourceCG.h"
+
+#include "StdLibExtras.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+String MIMETypeForImageSourceType(const String& type)
+{
+ String mimeType;
+ // FIXME: This approach of taking a UTI like public.type and giving back
+ // a MIME type like image/type will work for common image UTIs like jpeg,
+ // png, tiff, gif but won't work for UTIs like: public.jpeg-2000,
+ // public.xbitmap-image, com.apple.quicktime-image, and others.
+ if (int dotLocation = type.reverseFind('.'))
+ mimeType = "image/" + type.substring(dotLocation + 1);
+ return mimeType;
+}
+
+String preferredExtensionForImageSourceType(const String& type)
+{
+ if (type.isEmpty())
+ return String();
+
+ typedef HashMap<String, String> StringMap;
+ DEFINE_STATIC_LOCAL(StringMap, UTIMap, ());
+ if (UTIMap.isEmpty()) {
+ UTIMap.add("public.html", "html");
+ UTIMap.add("public.jpeg", "jpeg");
+ UTIMap.add("public.jpeg-2000", "jp2");
+ UTIMap.add("public.plain-text", "txt");
+ UTIMap.add("public.png", "png");
+ UTIMap.add("public.tiff", "tiff");
+ UTIMap.add("public.xbitmap-image", "xbm");
+ UTIMap.add("public.xml", "xml");
+ UTIMap.add("com.adobe.illustrator.ai-image", "ai");
+ UTIMap.add("com.adobe.pdf", "pdf");
+ UTIMap.add("com.adobe.photoshop-image", "psd");
+ UTIMap.add("com.adobe.postscript", "ps");
+ UTIMap.add("com.apple.icns", "icns");
+ UTIMap.add("com.apple.macpaint-image", "pntg");
+ UTIMap.add("com.apple.pict", "pict");
+ UTIMap.add("com.apple.quicktime-image", "qtif");
+ UTIMap.add("com.apple.webarchive", "webarchive");
+ UTIMap.add("com.compuserve.gif", "gif");
+ UTIMap.add("com.ilm.openexr-image", "exr");
+ UTIMap.add("com.kodak.flashpix-image", "fpx");
+ UTIMap.add("com.microsoft.bmp", "bmp");
+ UTIMap.add("com.microsoft.ico", "ico");
+ UTIMap.add("com.netscape.javascript-source", "js");
+ UTIMap.add("com.sgi.sgi-image", "sgi");
+ UTIMap.add("com.truevision.tga-image", "tga");
+ }
+ return UTIMap.get(type);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cg/IntPointCG.cpp b/Source/WebCore/platform/graphics/cg/IntPointCG.cpp
new file mode 100644
index 0000000..95dbe5f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/IntPointCG.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const CGPoint& p) : m_x(static_cast<int>(p.x)), m_y(static_cast<int>(p.y))
+{
+}
+
+IntPoint::operator CGPoint() const
+{
+ return CGPointMake(m_x, m_y);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/IntRectCG.cpp b/Source/WebCore/platform/graphics/cg/IntRectCG.cpp
new file mode 100644
index 0000000..73fd63f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/IntRectCG.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+IntRect::operator CGRect() const
+{
+ return CGRectMake(x(), y(), width(), height());
+}
+
+IntRect enclosingIntRect(const CGRect& rect)
+{
+ int l = static_cast<int>(floorf(rect.origin.x));
+ int t = static_cast<int>(floorf(rect.origin.y));
+ int r = static_cast<int>(ceilf(CGRectGetMaxX(rect)));
+ int b = static_cast<int>(ceilf(CGRectGetMaxY(rect)));
+ return IntRect(l, t, r - l, b - t);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp b/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp
new file mode 100644
index 0000000..d8e8c83
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntSize.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+IntSize::IntSize(const CGSize& s) : m_width(static_cast<int>(s.width)), m_height(static_cast<int>(s.height))
+{
+}
+
+IntSize::operator CGSize() const
+{
+ return CGSizeMake(m_width, m_height);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp
new file mode 100644
index 0000000..8bf04f1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#define _USE_MATH_DEFINES 1
+#include "config.h"
+#include "PDFDocumentImage.h"
+
+#if PLATFORM(CG)
+
+#include "GraphicsContext.h"
+#include "ImageObserver.h"
+#include "SharedBuffer.h"
+#include <wtf/MathExtras.h>
+#include <wtf/RetainPtr.h>
+
+#if !PLATFORM(MAC)
+#include "ImageSourceCG.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+PDFDocumentImage::PDFDocumentImage()
+ : Image(0) // PDFs don't animate
+ , m_document(0)
+ , m_rotation(0.0f)
+ , m_currentPage(-1)
+{
+}
+
+PDFDocumentImage::~PDFDocumentImage()
+{
+ CGPDFDocumentRelease(m_document);
+}
+
+String PDFDocumentImage::filenameExtension() const
+{
+ return "pdf";
+}
+
+IntSize PDFDocumentImage::size() const
+{
+ const float sina = sinf(-m_rotation);
+ const float cosa = cosf(-m_rotation);
+ const float width = m_mediaBox.size().width();
+ const float height = m_mediaBox.size().height();
+ const float rotWidth = width * cosa - height * sina;
+ const float rotHeight = width * sina + height * cosa;
+
+ return IntSize((int)(fabsf(rotWidth) + 0.5f), (int)(fabsf(rotHeight) + 0.5f));
+}
+
+bool PDFDocumentImage::dataChanged(bool allDataReceived)
+{
+ if (allDataReceived && !m_document) {
+#if PLATFORM(MAC)
+ // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability
+ // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer.
+ RetainPtr<CFDataRef> data(AdoptCF, this->data()->createCFData());
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get()));
+#else
+ // Create a CGDataProvider to wrap the SharedBuffer.
+ // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer
+ // does not provide a way to lock down the byte pointer and guarantee that it won't move, which
+ // is a requirement for using the GetBytePointer callback.
+ CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, 0 };
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirect(this->data(), this->data()->size(), &providerCallbacks));
+#endif
+ m_document = CGPDFDocumentCreateWithProvider(dataProvider.get());
+ setCurrentPage(0);
+ }
+ return m_document; // return true if size is available
+}
+
+void PDFDocumentImage::adjustCTM(GraphicsContext* context) const
+{
+ // rotate the crop box and calculate bounding box
+ float sina = sinf(-m_rotation);
+ float cosa = cosf(-m_rotation);
+ float width = m_cropBox.width();
+ float height = m_cropBox.height();
+
+ // calculate rotated x and y edges of the corp box. if they're negative, it means part of the image has
+ // been rotated outside of the bounds and we need to shift over the image so it lies inside the bounds again
+ CGPoint rx = CGPointMake(width * cosa, width * sina);
+ CGPoint ry = CGPointMake(-height * sina, height * cosa);
+
+ // adjust so we are at the crop box origin
+ const CGFloat zero = 0;
+ CGContextTranslateCTM(context->platformContext(), floorf(-min(zero, min(rx.x, ry.x))), floorf(-min(zero, min(rx.y, ry.y))));
+
+ // rotate -ve to remove rotation
+ CGContextRotateCTM(context->platformContext(), -m_rotation);
+
+ // shift so we are completely within media box
+ CGContextTranslateCTM(context->platformContext(), m_mediaBox.x() - m_cropBox.x(), m_mediaBox.y() - m_cropBox.y());
+}
+
+void PDFDocumentImage::setCurrentPage(int page)
+{
+ if (!m_document)
+ return;
+
+ if (page == m_currentPage)
+ return;
+
+ if (!(page >= 0 && page < pageCount()))
+ return;
+
+ m_currentPage = page;
+
+ CGPDFPageRef cgPage = CGPDFDocumentGetPage(m_document, page + 1);
+
+ // get media box (guaranteed)
+ m_mediaBox = CGPDFPageGetBoxRect(cgPage, kCGPDFMediaBox);
+
+ // get crop box (not always there). if not, use media box
+ CGRect r = CGPDFPageGetBoxRect(cgPage, kCGPDFCropBox);
+ if (!CGRectIsEmpty(r))
+ m_cropBox = r;
+ else
+ m_cropBox = m_mediaBox;
+
+ // get page rotation angle
+ m_rotation = CGPDFPageGetRotationAngle(cgPage) * piFloat / 180.0f; // to radians
+}
+
+int PDFDocumentImage::pageCount() const
+{
+ return m_document ? CGPDFDocumentGetNumberOfPages(m_document) : 0;
+}
+
+void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator op)
+{
+ if (!m_document || m_currentPage == -1)
+ return;
+
+ context->save();
+
+ context->setCompositeOperation(op);
+
+ float hScale = dstRect.width() / srcRect.width();
+ float vScale = dstRect.height() / srcRect.height();
+
+ // Scale and translate so the document is rendered in the correct location,
+ // including accounting for the fact that a GraphicsContext is always flipped
+ // and doing appropriate flipping.
+ CGContextTranslateCTM(context->platformContext(), dstRect.x() - srcRect.x() * hScale, dstRect.y() - srcRect.y() * vScale);
+ CGContextScaleCTM(context->platformContext(), hScale, vScale);
+ CGContextScaleCTM(context->platformContext(), 1, -1);
+ CGContextTranslateCTM(context->platformContext(), 0, -srcRect.height());
+ CGContextClipToRect(context->platformContext(), CGRectIntegral(srcRect));
+
+ // Rotate translate image into position according to doc properties.
+ adjustCTM(context);
+
+ CGContextTranslateCTM(context->platformContext(), -m_mediaBox.x(), -m_mediaBox.y());
+ CGContextDrawPDFPage(context->platformContext(), CGPDFDocumentGetPage(m_document, m_currentPage + 1));
+
+ context->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h
new file mode 100644
index 0000000..790d620
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "Image.h"
+
+#include "FloatRect.h"
+#include "GraphicsTypes.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+ class GraphicsContext;
+
+ class PDFDocumentImage : public Image {
+ public:
+ static PassRefPtr<PDFDocumentImage> create()
+ {
+ return adoptRef(new PDFDocumentImage);
+ }
+
+ private:
+ virtual ~PDFDocumentImage();
+
+ virtual String filenameExtension() const;
+
+ virtual bool hasSingleSecurityOrigin() const { return true; }
+
+ virtual bool dataChanged(bool allDataReceived);
+
+ // FIXME: PDF Images are underreporting decoded sizes and will be unable
+ // to prune because these functions are not implemented yet.
+ virtual void destroyDecodedData(bool /*destroyAll*/ = true) { }
+ virtual unsigned decodedSize() const { return 0; }
+
+ virtual IntSize size() const;
+
+ PDFDocumentImage();
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
+
+ void setCurrentPage(int);
+ int pageCount() const;
+ void adjustCTM(GraphicsContext*) const;
+
+ CGPDFDocumentRef m_document;
+ FloatRect m_mediaBox;
+ FloatRect m_cropBox;
+ float m_rotation;
+ int m_currentPage;
+ };
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/PathCG.cpp b/Source/WebCore/platform/graphics/cg/PathCG.cpp
new file mode 100644
index 0000000..d6a1e6e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/PathCG.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * 2006, 2008 Rob Buis <buis@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Path.h"
+
+#if PLATFORM(CG)
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "PlatformString.h"
+#include "StrokeStyleApplier.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/MathExtras.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+static size_t putBytesNowhere(void*, const void*, size_t count)
+{
+ return count;
+}
+
+static CGContextRef createScratchContext()
+{
+ CGDataConsumerCallbacks callbacks = { putBytesNowhere, 0 };
+ RetainPtr<CGDataConsumerRef> consumer(AdoptCF, CGDataConsumerCreate(0, &callbacks));
+ CGContextRef context = CGPDFContextCreate(consumer.get(), 0, 0);
+
+ CGFloat black[4] = { 0, 0, 0, 1 };
+ CGContextSetFillColor(context, black);
+ CGContextSetStrokeColor(context, black);
+
+ return context;
+}
+
+static inline CGContextRef scratchContext()
+{
+ static CGContextRef context = createScratchContext();
+ return context;
+}
+
+Path::Path()
+ : m_path(CGPathCreateMutable())
+{
+}
+
+Path::~Path()
+{
+ CGPathRelease(m_path);
+}
+
+Path::Path(const Path& other)
+ : m_path(CGPathCreateMutableCopy(other.m_path))
+{
+}
+
+Path& Path::operator=(const Path& other)
+{
+ CGMutablePathRef path = CGPathCreateMutableCopy(other.m_path);
+ CGPathRelease(m_path);
+ m_path = path;
+ return *this;
+}
+
+static void copyClosingSubpathsApplierFunction(void* info, const CGPathElement* element)
+{
+ CGMutablePathRef path = static_cast<CGMutablePathRef>(info);
+ CGPoint* points = element->points;
+
+ switch (element->type) {
+ case kCGPathElementMoveToPoint:
+ if (!CGPathIsEmpty(path)) // to silence a warning when trying to close an empty path
+ CGPathCloseSubpath(path); // This is the only change from CGPathCreateMutableCopy
+ CGPathMoveToPoint(path, 0, points[0].x, points[0].y);
+ break;
+ case kCGPathElementAddLineToPoint:
+ CGPathAddLineToPoint(path, 0, points[0].x, points[0].y);
+ break;
+ case kCGPathElementAddQuadCurveToPoint:
+ CGPathAddQuadCurveToPoint(path, 0, points[0].x, points[0].y, points[1].x, points[1].y);
+ break;
+ case kCGPathElementAddCurveToPoint:
+ CGPathAddCurveToPoint(path, 0, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y);
+ break;
+ case kCGPathElementCloseSubpath:
+ CGPathCloseSubpath(path);
+ break;
+ }
+}
+
+static CGMutablePathRef copyCGPathClosingSubpaths(CGPathRef originalPath)
+{
+ CGMutablePathRef path = CGPathCreateMutable();
+ CGPathApply(originalPath, path, copyClosingSubpathsApplierFunction);
+ CGPathCloseSubpath(path);
+ return path;
+}
+
+bool Path::contains(const FloatPoint &point, WindRule rule) const
+{
+ if (!boundingRect().contains(point))
+ return false;
+
+ // CGPathContainsPoint returns false for non-closed paths, as a work-around, we copy and close the path first. Radar 4758998 asks for a better CG API to use
+ RetainPtr<CGMutablePathRef> path(AdoptCF, copyCGPathClosingSubpaths(m_path));
+ bool ret = CGPathContainsPoint(path.get(), 0, point, rule == RULE_EVENODD ? true : false);
+ return ret;
+}
+
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+
+ CGContextRef context = scratchContext();
+
+ CGContextSaveGState(context);
+ CGContextBeginPath(context);
+ CGContextAddPath(context, platformPath());
+
+ GraphicsContext gc(context);
+ applier->strokeStyle(&gc);
+
+ bool hitSuccess = CGContextPathContainsPoint(context, point, kCGPathStroke);
+ CGContextRestoreGState(context);
+
+ return hitSuccess;
+}
+
+void Path::translate(const FloatSize& size)
+{
+ CGAffineTransform translation = CGAffineTransformMake(1, 0, 0, 1, size.width(), size.height());
+ CGMutablePathRef newPath = CGPathCreateMutable();
+ CGPathAddPath(newPath, &translation, m_path);
+ CGPathRelease(m_path);
+ m_path = newPath;
+}
+
+FloatRect Path::boundingRect() const
+{
+ return CGPathGetBoundingBox(m_path);
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ CGContextRef context = scratchContext();
+
+ CGContextSaveGState(context);
+ CGContextBeginPath(context);
+ CGContextAddPath(context, platformPath());
+
+ if (applier) {
+ GraphicsContext graphicsContext(context);
+ applier->strokeStyle(&graphicsContext);
+ }
+
+ CGContextReplacePathWithStrokedPath(context);
+ CGRect box = CGContextIsPathEmpty(context) ? CGRectZero : CGContextGetPathBoundingBox(context);
+ CGContextRestoreGState(context);
+
+ return box;
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ CGPathMoveToPoint(m_path, 0, point.x(), point.y());
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ CGPathAddLineToPoint(m_path, 0, p.x(), p.y());
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
+{
+ CGPathAddQuadCurveToPoint(m_path, 0, cp.x(), cp.y(), p.x(), p.y());
+}
+
+void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
+{
+ CGPathAddCurveToPoint(m_path, 0, cp1.x(), cp1.y(), cp2.x(), cp2.y(), p.x(), p.y());
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ CGPathAddArcToPoint(m_path, 0, p1.x(), p1.y(), p2.x(), p2.y(), radius);
+}
+
+void Path::closeSubpath()
+{
+ CGPathCloseSubpath(m_path);
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool clockwise)
+{
+ // Workaround for <rdar://problem/5189233> CGPathAddArc hangs or crashes when passed inf as start or end angle
+ if (isfinite(sa) && isfinite(ea))
+ CGPathAddArc(m_path, 0, p.x(), p.y(), r, sa, ea, clockwise);
+}
+
+void Path::addRect(const FloatRect& r)
+{
+ CGPathAddRect(m_path, 0, r);
+}
+
+void Path::addEllipse(const FloatRect& r)
+{
+ CGPathAddEllipseInRect(m_path, 0, r);
+}
+
+void Path::clear()
+{
+ CGPathRelease(m_path);
+ m_path = CGPathCreateMutable();
+}
+
+bool Path::isEmpty() const
+{
+ return CGPathIsEmpty(m_path);
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
+
+FloatPoint Path::currentPoint() const
+{
+ return CGPathGetCurrentPoint(m_path);
+}
+
+// MARK: -
+// MARK: Path Management
+
+struct PathApplierInfo {
+ void* info;
+ PathApplierFunction function;
+};
+
+static void CGPathApplierToPathApplier(void *info, const CGPathElement *element)
+{
+ PathApplierInfo* pinfo = (PathApplierInfo*)info;
+ FloatPoint points[3];
+ PathElement pelement;
+ pelement.type = (PathElementType)element->type;
+ pelement.points = points;
+ CGPoint* cgPoints = element->points;
+ switch (element->type) {
+ case kCGPathElementMoveToPoint:
+ case kCGPathElementAddLineToPoint:
+ points[0] = cgPoints[0];
+ break;
+ case kCGPathElementAddQuadCurveToPoint:
+ points[0] = cgPoints[0];
+ points[1] = cgPoints[1];
+ break;
+ case kCGPathElementAddCurveToPoint:
+ points[0] = cgPoints[0];
+ points[1] = cgPoints[1];
+ points[2] = cgPoints[2];
+ break;
+ case kCGPathElementCloseSubpath:
+ break;
+ }
+ pinfo->function(pinfo->info, &pelement);
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ PathApplierInfo pinfo;
+ pinfo.info = info;
+ pinfo.function = function;
+ CGPathApply(m_path, &pinfo, CGPathApplierToPathApplier);
+}
+
+void Path::transform(const AffineTransform& transform)
+{
+ CGMutablePathRef path = CGPathCreateMutable();
+ CGAffineTransform transformCG = transform;
+ CGPathAddPath(path, &transformCG, m_path);
+ CGPathRelease(m_path);
+ m_path = path;
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/cg/PatternCG.cpp b/Source/WebCore/platform/graphics/cg/PatternCG.cpp
new file mode 100644
index 0000000..94f37b2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/PatternCG.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Pattern.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+static void patternCallback(void* info, CGContextRef context)
+{
+ CGImageRef platformImage = static_cast<Image*>(info)->getCGImageRef();
+ if (!platformImage)
+ return;
+
+ CGRect rect = GraphicsContext(context).roundToDevicePixels(
+ FloatRect(0, 0, CGImageGetWidth(platformImage), CGImageGetHeight(platformImage)));
+ CGContextDrawImage(context, rect, platformImage);
+}
+
+static void patternReleaseCallback(void* info)
+{
+ static_cast<Image*>(info)->deref();
+}
+
+CGPatternRef Pattern::createPlatformPattern(const AffineTransform& userSpaceTransformation) const
+{
+ IntRect tileRect = tileImage()->rect();
+
+ AffineTransform patternTransform = m_patternSpaceTransformation;
+ patternTransform.multiply(userSpaceTransformation);
+ patternTransform.scaleNonUniform(1, -1);
+ patternTransform.translate(0, -tileRect.height());
+
+ // If FLT_MAX should also be used for xStep or yStep, nothing is rendered. Using fractions of FLT_MAX also
+ // result in nothing being rendered.
+ // INT_MAX is almost correct, but there seems to be some number wrapping occurring making the fill
+ // pattern is not filled correctly.
+ // To make error of floating point less than 0.5, we use the half of the number of mantissa of float (1 << 22).
+ CGFloat xStep = m_repeatX ? tileRect.width() : (1 << 22);
+ CGFloat yStep = m_repeatY ? tileRect.height() : (1 << 22);
+
+ // The pattern will release the tile when it's done rendering in patternReleaseCallback
+ tileImage()->ref();
+
+ const CGPatternCallbacks patternCallbacks = { 0, patternCallback, patternReleaseCallback };
+ return CGPatternCreate(tileImage(), tileRect, patternTransform, xStep, yStep,
+ kCGPatternTilingConstantSpacing, TRUE, &patternCallbacks);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp b/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
new file mode 100644
index 0000000..ec40836
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+#include "TransformationMatrix.h"
+
+#if PLATFORM(CG)
+
+#include <CoreGraphics/CGAffineTransform.h>
+#include "FloatConversion.h"
+
+namespace WebCore {
+
+TransformationMatrix::TransformationMatrix(const CGAffineTransform& t)
+{
+ setA(t.a);
+ setB(t.b);
+ setC(t.c);
+ setD(t.d);
+ setE(t.tx);
+ setF(t.ty);
+}
+
+TransformationMatrix::operator CGAffineTransform() const
+{
+ return CGAffineTransformMake(narrowPrecisionToCGFloat(a()),
+ narrowPrecisionToCGFloat(b()),
+ narrowPrecisionToCGFloat(c()),
+ narrowPrecisionToCGFloat(d()),
+ narrowPrecisionToCGFloat(e()),
+ narrowPrecisionToCGFloat(f()));
+}
+
+AffineTransform::operator CGAffineTransform() const
+{
+ return CGAffineTransformMake(narrowPrecisionToCGFloat(a()),
+ narrowPrecisionToCGFloat(b()),
+ narrowPrecisionToCGFloat(c()),
+ narrowPrecisionToCGFloat(d()),
+ narrowPrecisionToCGFloat(e()),
+ narrowPrecisionToCGFloat(f()));
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp
new file mode 100644
index 0000000..ad961aa
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Canvas2DLayerChromium.h"
+
+#include "DrawingBuffer.h"
+#include "GraphicsContext3D.h"
+
+namespace WebCore {
+
+PassRefPtr<Canvas2DLayerChromium> Canvas2DLayerChromium::create(DrawingBuffer* drawingBuffer, GraphicsLayerChromium* owner)
+{
+ return adoptRef(new Canvas2DLayerChromium(drawingBuffer, owner));
+}
+
+Canvas2DLayerChromium::Canvas2DLayerChromium(DrawingBuffer* drawingBuffer, GraphicsLayerChromium* owner)
+ : CanvasLayerChromium(owner)
+ , m_drawingBuffer(drawingBuffer)
+{
+}
+
+Canvas2DLayerChromium::~Canvas2DLayerChromium()
+{
+ if (m_textureId)
+ layerRendererContext()->deleteTexture(m_textureId);
+}
+
+void Canvas2DLayerChromium::updateContentsIfDirty()
+{
+ if (!m_contentsDirty || !m_drawingBuffer)
+ return;
+ if (m_textureChanged) { // We have to generate a new backing texture.
+ GraphicsContext3D* context = layerRendererContext();
+ if (m_textureId)
+ context->deleteTexture(m_textureId);
+ m_textureId = context->createTexture();
+ context->activeTexture(GraphicsContext3D::TEXTURE0);
+ context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId);
+ IntSize size = m_drawingBuffer->size();
+ context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, size.width(), size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE);
+ // Set the min-mag filters to linear and wrap modes to GraphicsContext3D::CLAMP_TO_EDGE
+ // to get around NPOT texture limitations of GLES.
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
+ m_textureChanged = false;
+ // FIXME: The finish() here is required because we have to make sure that the texture created in this
+ // context (the compositor context) is actually created by the service side before the child context
+ // attempts to use it (in publishToPlatformLayer). finish() is currently the only call with strong
+ // enough semantics to promise this, but is actually much stronger. Ideally we'd do something like
+ // inserting a fence here and waiting for it before trying to publish.
+ context->finish();
+ }
+ // Update the contents of the texture used by the compositor.
+ if (m_contentsDirty) {
+ m_drawingBuffer->publishToPlatformLayer();
+ m_contentsDirty = false;
+ }
+}
+
+void Canvas2DLayerChromium::setTextureChanged()
+{
+ m_textureChanged = true;
+}
+
+unsigned Canvas2DLayerChromium::textureId() const
+{
+ return m_textureId;
+}
+
+void Canvas2DLayerChromium::setDrawingBuffer(DrawingBuffer* drawingBuffer)
+{
+ if (drawingBuffer != m_drawingBuffer) {
+ m_drawingBuffer = drawingBuffer;
+ m_textureChanged = true;
+ }
+}
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h
new file mode 100644
index 0000000..44ef050
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 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 Canvas2DLayerChromium_h
+#define Canvas2DLayerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "CanvasLayerChromium.h"
+
+namespace WebCore {
+
+class DrawingBuffer;
+
+// A layer containing an accelerated 2d canvas
+class Canvas2DLayerChromium : public CanvasLayerChromium {
+public:
+ static PassRefPtr<Canvas2DLayerChromium> create(DrawingBuffer*, GraphicsLayerChromium* owner);
+ virtual ~Canvas2DLayerChromium();
+ virtual bool drawsContent() { return true; }
+ virtual void updateContentsIfDirty();
+
+ void setTextureChanged();
+ unsigned textureId() const;
+ void setDrawingBuffer(DrawingBuffer*);
+
+private:
+ explicit Canvas2DLayerChromium(DrawingBuffer*, GraphicsLayerChromium* owner);
+ DrawingBuffer* m_drawingBuffer;
+
+ static unsigned m_shaderProgramId;
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp
new file mode 100644
index 0000000..4aef25b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "CanvasLayerChromium.h"
+
+#include "GraphicsContext3D.h"
+#include "LayerRendererChromium.h"
+
+namespace WebCore {
+
+unsigned CanvasLayerChromium::m_shaderProgramId = 0;
+
+CanvasLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context)
+ : m_context(context)
+ , m_canvasShaderProgram(0)
+ , m_shaderSamplerLocation(-1)
+ , m_shaderMatrixLocation(-1)
+ , m_shaderAlphaLocation(-1)
+ , m_initialized(false)
+{
+ char vertexShaderString[] =
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "uniform mat4 matrix; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = matrix * a_position; \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+
+ // Canvas layers need to be flipped vertically and their colors shouldn't be
+ // swizzled.
+ char fragmentShaderString[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "uniform float alpha; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 texColor = texture2D(s_texture, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n"
+ " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n"
+ "} \n";
+
+ m_canvasShaderProgram = createShaderProgram(m_context, vertexShaderString, fragmentShaderString);
+ if (!m_canvasShaderProgram) {
+ LOG_ERROR("CanvasLayerChromium: Failed to create shader program");
+ return;
+ }
+
+ m_shaderSamplerLocation = m_context->getUniformLocation(m_canvasShaderProgram, "s_texture");
+ m_shaderMatrixLocation = m_context->getUniformLocation(m_canvasShaderProgram, "matrix");
+ m_shaderAlphaLocation = m_context->getUniformLocation(m_canvasShaderProgram, "alpha");
+ ASSERT(m_shaderSamplerLocation != -1);
+ ASSERT(m_shaderMatrixLocation != -1);
+ ASSERT(m_shaderAlphaLocation != -1);
+
+ m_initialized = true;
+}
+
+CanvasLayerChromium::SharedValues::~SharedValues()
+{
+ if (m_canvasShaderProgram)
+ GLC(m_context, m_context->deleteProgram(m_canvasShaderProgram));
+}
+
+CanvasLayerChromium::CanvasLayerChromium(GraphicsLayerChromium* owner)
+ : LayerChromium(owner)
+ , m_textureChanged(true)
+ , m_textureId(0)
+{
+}
+
+CanvasLayerChromium::~CanvasLayerChromium()
+{
+}
+
+void CanvasLayerChromium::draw()
+{
+ ASSERT(layerRenderer());
+ const CanvasLayerChromium::SharedValues* sv = layerRenderer()->canvasLayerSharedValues();
+ ASSERT(sv && sv->initialized());
+ GraphicsContext3D* context = layerRendererContext();
+ GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0));
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId));
+ layerRenderer()->useShader(sv->canvasShaderProgram());
+ GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0));
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(),
+ bounds().width(), bounds().height(), drawOpacity(),
+ sv->shaderMatrixLocation(), sv->shaderAlphaLocation());
+
+}
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h
new file mode 100644
index 0000000..6520b55
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 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 CanvasLayerChromium_h
+#define CanvasLayerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "LayerChromium.h"
+
+namespace WebCore {
+
+// Base class for WebGL and accelerated 2d canvases.
+class CanvasLayerChromium : public LayerChromium {
+public:
+ virtual ~CanvasLayerChromium();
+
+ virtual void draw();
+
+ class SharedValues {
+ public:
+ explicit SharedValues(GraphicsContext3D*);
+ ~SharedValues();
+
+ unsigned canvasShaderProgram() const { return m_canvasShaderProgram; }
+ int shaderSamplerLocation() const { return m_shaderSamplerLocation; }
+ int shaderMatrixLocation() const { return m_shaderMatrixLocation; }
+ int shaderAlphaLocation() const { return m_shaderAlphaLocation; }
+ bool initialized() const { return m_initialized; }
+
+ private:
+ GraphicsContext3D* m_context;
+ unsigned m_canvasShaderProgram;
+ int m_shaderSamplerLocation;
+ int m_shaderMatrixLocation;
+ int m_shaderAlphaLocation;
+ bool m_initialized;
+ };
+
+protected:
+ explicit CanvasLayerChromium(GraphicsLayerChromium* owner);
+ bool m_textureChanged;
+ unsigned m_textureId;
+
+private:
+ static unsigned m_shaderProgramId;
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // CanvasLayerChromium_h
diff --git a/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.cpp b/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.cpp
new file mode 100644
index 0000000..b5eda93
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.cpp
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+#include "ComplexTextControllerLinux.h"
+
+#include "Font.h"
+
+#include <unicode/normlzr.h>
+
+namespace WebCore {
+
+// Harfbuzz uses 26.6 fixed point values for pixel offsets. However, we don't
+// handle subpixel positioning so this function is used to truncate Harfbuzz
+// values to a number of pixels.
+static int truncateFixedPointToInteger(HB_Fixed value)
+{
+ return value >> 6;
+}
+
+ComplexTextController::ComplexTextController(const TextRun& run, unsigned startingX, const Font* font)
+ : m_font(font)
+ , m_startingX(startingX)
+ , m_offsetX(m_startingX)
+ , m_run(getNormalizedTextRun(run, m_normalizedRun, m_normalizedBuffer))
+ , m_iterateBackwards(m_run.rtl())
+ , m_wordSpacingAdjustment(0)
+ , m_padding(0)
+ , m_padPerWordBreak(0)
+ , m_padError(0)
+ , m_letterSpacing(0)
+{
+ // Do not use |run| inside this constructor. Use |m_run| instead.
+
+ memset(&m_item, 0, sizeof(m_item));
+ // We cannot know, ahead of time, how many glyphs a given script run
+ // will produce. We take a guess that script runs will not produce more
+ // than twice as many glyphs as there are code points plus a bit of
+ // padding and fallback if we find that we are wrong.
+ createGlyphArrays((m_run.length() + 2) * 2);
+
+ m_item.log_clusters = new unsigned short[m_run.length()];
+
+ m_item.face = 0;
+ m_item.font = allocHarfbuzzFont();
+
+ m_item.item.bidiLevel = m_run.rtl();
+
+ m_item.string = m_run.characters();
+ m_item.stringLength = m_run.length();
+
+ reset();
+}
+
+ComplexTextController::~ComplexTextController()
+{
+ fastFree(m_item.font);
+ deleteGlyphArrays();
+ delete[] m_item.log_clusters;
+}
+
+bool ComplexTextController::isWordBreak(unsigned index)
+{
+ return index && isCodepointSpace(m_item.string[index]) && !isCodepointSpace(m_item.string[index - 1]);
+}
+
+int ComplexTextController::determineWordBreakSpacing(unsigned logClustersIndex)
+{
+ int wordBreakSpacing = 0;
+ // The first half of the conjunction works around the case where
+ // output glyphs aren't associated with any codepoints by the
+ // clusters log.
+ if (logClustersIndex < m_item.item.length
+ && isWordBreak(m_item.item.pos + logClustersIndex)) {
+ wordBreakSpacing = m_wordSpacingAdjustment;
+
+ if (m_padding > 0) {
+ int toPad = roundf(m_padPerWordBreak + m_padError);
+ m_padError += m_padPerWordBreak - toPad;
+
+ if (m_padding < toPad)
+ toPad = m_padding;
+ m_padding -= toPad;
+ wordBreakSpacing += toPad;
+ }
+ }
+ return wordBreakSpacing;
+}
+
+// setPadding sets a number of pixels to be distributed across the TextRun.
+// WebKit uses this to justify text.
+void ComplexTextController::setPadding(int padding)
+{
+ m_padding = padding;
+ if (!m_padding)
+ return;
+
+ // If we have padding to distribute, then we try to give an equal
+ // amount to each space. The last space gets the smaller amount, if
+ // any.
+ unsigned numWordBreaks = 0;
+
+ for (unsigned i = 0; i < m_item.stringLength; i++) {
+ if (isWordBreak(i))
+ numWordBreaks++;
+ }
+
+ if (numWordBreaks)
+ m_padPerWordBreak = m_padding / numWordBreaks;
+ else
+ m_padPerWordBreak = 0;
+}
+
+void ComplexTextController::reset()
+{
+ if (m_iterateBackwards)
+ m_indexOfNextScriptRun = m_run.length() - 1;
+ else
+ m_indexOfNextScriptRun = 0;
+ m_offsetX = m_startingX;
+}
+
+void ComplexTextController::setBackwardsIteration(bool isBackwards)
+{
+ m_iterateBackwards = isBackwards;
+ reset();
+}
+
+// Advance to the next script run, returning false when the end of the
+// TextRun has been reached.
+bool ComplexTextController::nextScriptRun()
+{
+ if (m_iterateBackwards) {
+ // In right-to-left mode we need to render the shaped glyph backwards and
+ // also render the script runs themselves backwards. So given a TextRun:
+ // AAAAAAACTTTTTTT (A = Arabic, C = Common, T = Thai)
+ // we render:
+ // TTTTTTCAAAAAAA
+ // (and the glyphs in each A, C and T section are backwards too)
+ if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
+ return false;
+ m_currentFontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false).fontData;
+ } else {
+ if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
+ return false;
+
+ // It is actually wrong to consider script runs at all in this code.
+ // Other WebKit code (e.g. Mac) segments complex text just by finding
+ // the longest span of text covered by a single font.
+ // But we currently need to call hb_utf16_script_run_next anyway to fill
+ // in the harfbuzz data structures to e.g. pick the correct script's shaper.
+ // So we allow that to run first, then do a second pass over the range it
+ // found and take the largest subregion that stays within a single font.
+ m_currentFontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false).fontData;
+ unsigned endOfRun;
+ for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) {
+ const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false).fontData;
+ if (nextFontData != m_currentFontData)
+ break;
+ }
+ m_item.item.length = endOfRun;
+ m_indexOfNextScriptRun = m_item.item.pos + endOfRun;
+ }
+
+ setupFontForScriptRun();
+ shapeGlyphs();
+ setGlyphXPositions(rtl());
+
+ return true;
+}
+
+float ComplexTextController::widthOfFullRun()
+{
+ float widthSum = 0;
+ while (nextScriptRun())
+ widthSum += width();
+
+ return widthSum;
+}
+
+void ComplexTextController::setupFontForScriptRun()
+{
+ const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false).fontData;
+ const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData();
+ m_item.face = platformData.harfbuzzFace();
+ void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData);
+ m_item.font->userData = opaquePlatformData;
+}
+
+HB_FontRec* ComplexTextController::allocHarfbuzzFont()
+{
+ HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec)));
+ memset(font, 0, sizeof(HB_FontRec));
+ font->klass = &harfbuzzSkiaClass;
+ font->userData = 0;
+ // The values which harfbuzzSkiaClass returns are already scaled to
+ // pixel units, so we just set all these to one to disable further
+ // scaling.
+ font->x_ppem = 1;
+ font->y_ppem = 1;
+ font->x_scale = 1;
+ font->y_scale = 1;
+
+ return font;
+}
+
+void ComplexTextController::deleteGlyphArrays()
+{
+ delete[] m_item.glyphs;
+ delete[] m_item.attributes;
+ delete[] m_item.advances;
+ delete[] m_item.offsets;
+ delete[] m_glyphs16;
+ delete[] m_xPositions;
+}
+
+void ComplexTextController::createGlyphArrays(int size)
+{
+ m_item.glyphs = new HB_Glyph[size];
+ m_item.attributes = new HB_GlyphAttributes[size];
+ m_item.advances = new HB_Fixed[size];
+ m_item.offsets = new HB_FixedPoint[size];
+
+ m_glyphs16 = new uint16_t[size];
+ m_xPositions = new SkScalar[size];
+
+ m_item.num_glyphs = size;
+ m_glyphsArrayCapacity = size; // Save the GlyphArrays size.
+ resetGlyphArrays();
+}
+
+void ComplexTextController::resetGlyphArrays()
+{
+ int size = m_item.num_glyphs;
+ // All the types here don't have pointers. It is safe to reset to
+ // zero unless Harfbuzz breaks the compatibility in the future.
+ memset(m_item.glyphs, 0, size * sizeof(HB_Glyph));
+ memset(m_item.attributes, 0, size * sizeof(HB_GlyphAttributes));
+ memset(m_item.advances, 0, size * sizeof(HB_Fixed));
+ memset(m_item.offsets, 0, size * sizeof(HB_FixedPoint));
+ memset(m_glyphs16, 0, size * sizeof(uint16_t));
+ memset(m_xPositions, 0, size * sizeof(SkScalar));
+}
+
+void ComplexTextController::shapeGlyphs()
+{
+ // HB_ShapeItem() resets m_item.num_glyphs. If the previous call to
+ // HB_ShapeItem() used less space than was available, the capacity of
+ // the array may be larger than the current value of m_item.num_glyphs.
+ // So, we need to reset the num_glyphs to the capacity of the array.
+ m_item.num_glyphs = m_glyphsArrayCapacity;
+ resetGlyphArrays();
+ while (!HB_ShapeItem(&m_item)) {
+ // We overflowed our arrays. Resize and retry.
+ // HB_ShapeItem fills in m_item.num_glyphs with the needed size.
+ deleteGlyphArrays();
+ // The |+ 1| here is a workaround for a bug in Harfbuzz: the Khmer
+ // shaper (at least) can fail because of insufficient glyph buffers
+ // and request 0 additional glyphs: throwing us into an infinite
+ // loop.
+ createGlyphArrays(m_item.num_glyphs + 1);
+ }
+}
+
+void ComplexTextController::setGlyphXPositions(bool isRTL)
+{
+ double position = 0;
+ // logClustersIndex indexes logClusters for the first (or last when
+ // RTL) codepoint of the current glyph. Each time we advance a glyph,
+ // we skip over all the codepoints that contributed to the current
+ // glyph.
+ int logClustersIndex = 0;
+
+ if (isRTL) {
+ logClustersIndex = m_item.num_glyphs - 1;
+
+ // Glyphs are stored in logical order, but for layout purposes we
+ // always go left to right.
+ for (int i = m_item.num_glyphs - 1; i >= 0; --i) {
+ if (!m_currentFontData->isZeroWidthSpaceGlyph(m_glyphs16[i])) {
+ // Whitespace must be laid out in logical order, so when inserting
+ // spaces in RTL (but iterating in LTR order) we must insert spaces
+ // _before_ the next glyph.
+ if (static_cast<unsigned>(i + 1) >= m_item.num_glyphs || m_item.attributes[i + 1].clusterStart)
+ position += m_letterSpacing;
+
+ position += determineWordBreakSpacing(logClustersIndex);
+ }
+
+ m_glyphs16[i] = m_item.glyphs[i];
+ double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
+ m_xPositions[i] = m_offsetX + position + offsetX;
+
+ while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i)
+ logClustersIndex--;
+
+ if (!m_currentFontData->isZeroWidthSpaceGlyph(m_glyphs16[i]))
+ position += truncateFixedPointToInteger(m_item.advances[i]);
+ }
+ } else {
+ for (size_t i = 0; i < m_item.num_glyphs; ++i) {
+ m_glyphs16[i] = m_item.glyphs[i];
+ double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
+ m_xPositions[i] = m_offsetX + position + offsetX;
+
+ if (m_currentFontData->isZeroWidthSpaceGlyph(m_glyphs16[i]))
+ continue;
+
+ double advance = truncateFixedPointToInteger(m_item.advances[i]);
+
+ advance += determineWordBreakSpacing(logClustersIndex);
+
+ if (m_item.attributes[i].clusterStart)
+ advance += m_letterSpacing;
+
+ while (static_cast<unsigned>(logClustersIndex) < m_item.item.length && logClusters()[logClustersIndex] == i)
+ logClustersIndex++;
+
+ position += advance;
+ }
+ }
+ m_pixelWidth = std::max(position, 0.0);
+ m_offsetX += m_pixelWidth;
+}
+
+void ComplexTextController::normalizeSpacesAndMirrorChars(const UChar* source, bool rtl, UChar* destination, int length)
+{
+ int position = 0;
+ bool error = false;
+ // Iterate characters in source and mirror character if needed.
+ while (position < length) {
+ UChar32 character;
+ int nextPosition = position;
+ U16_NEXT(source, nextPosition, length, character);
+ if (Font::treatAsSpace(character))
+ character = ' ';
+ else if (Font::treatAsZeroWidthSpace(character))
+ character = zeroWidthSpace;
+ else if (rtl)
+ character = u_charMirror(character);
+ U16_APPEND(destination, position, length, character, error);
+ ASSERT(!error);
+ position = nextPosition;
+ }
+}
+
+const TextRun& ComplexTextController::getNormalizedTextRun(const TextRun& originalRun, OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer)
+{
+ // Normalize the text run in three ways:
+ // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
+ // (U+0300..) are used in the run. This conversion is necessary since most OpenType
+ // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
+ // their GSUB tables.
+ //
+ // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since
+ // the API returns FALSE (= not normalized) for complex runs that don't require NFC
+ // normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
+ // Harfbuzz will do the same thing for us using the GSUB table.
+ // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
+ // for characters like '\n' otherwise.
+ // 3) Convert mirrored characters such as parenthesis for rtl text.
+
+ // Convert to NFC form if the text has diacritical marks.
+ icu::UnicodeString normalizedString;
+ UErrorCode error = U_ZERO_ERROR;
+
+ for (int16_t i = 0; i < originalRun.length(); ++i) {
+ UChar ch = originalRun[i];
+ if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
+ icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(),
+ originalRun.length()), UNORM_NFC, 0 /* no options */,
+ normalizedString, error);
+ if (U_FAILURE(error))
+ return originalRun;
+ break;
+ }
+ }
+
+ // Normalize space and mirror parenthesis for rtl text.
+ int normalizedBufferLength;
+ const UChar* sourceText;
+ if (normalizedString.isEmpty()) {
+ normalizedBufferLength = originalRun.length();
+ sourceText = originalRun.characters();
+ } else {
+ normalizedBufferLength = normalizedString.length();
+ sourceText = normalizedString.getBuffer();
+ }
+
+ normalizedBuffer.set(new UChar[normalizedBufferLength + 1]);
+
+ normalizeSpacesAndMirrorChars(sourceText, originalRun.rtl(), normalizedBuffer.get(), normalizedBufferLength);
+
+ normalizedRun.set(new TextRun(originalRun));
+ normalizedRun->setText(normalizedBuffer.get(), normalizedBufferLength);
+ return *normalizedRun;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.h b/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.h
new file mode 100644
index 0000000..4ebbd89
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 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 ComplexTextControllerLinux_h
+#define ComplexTextControllerLinux_h
+
+#include "HarfbuzzSkia.h"
+#include "SkScalar.h"
+#include "TextRun.h"
+
+#include <unicode/uchar.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class Font;
+class FontPlatformData;
+class SimpleFontData;
+
+// ComplexTextController walks a TextRun and presents each script run in sequence. A
+// TextRun is a sequence of code-points with the same embedding level (i.e. they
+// are all left-to-right or right-to-left). A script run is a subsequence where
+// all the characters have the same script (e.g. Arabic, Thai etc). Shaping is
+// only ever done with script runs since the shapers only know how to deal with
+// a single script.
+//
+// After creating it, the script runs are either iterated backwards or forwards.
+// It defaults to backwards for RTL and forwards otherwise (which matches the
+// presentation order), however you can set it with |setBackwardsIteration|.
+//
+// Once you have setup the object, call |nextScriptRun| to get the first script
+// run. This will return false when the iteration is complete. At any time you
+// can call |reset| to start over again.
+class ComplexTextController {
+public:
+ ComplexTextController(const TextRun&, unsigned, const Font*);
+ ~ComplexTextController();
+
+ bool isWordBreak(unsigned);
+ int determineWordBreakSpacing(unsigned);
+ // setPadding sets a number of pixels to be distributed across the TextRun.
+ // WebKit uses this to justify text.
+ void setPadding(int);
+ void reset();
+ void setBackwardsIteration(bool);
+ // Advance to the next script run, returning false when the end of the
+ // TextRun has been reached.
+ bool nextScriptRun();
+ float widthOfFullRun();
+
+ // setWordSpacingAdjustment sets a delta (in pixels) which is applied at
+ // each word break in the TextRun.
+ void setWordSpacingAdjustment(int wordSpacingAdjustment) { m_wordSpacingAdjustment = wordSpacingAdjustment; }
+
+ // setLetterSpacingAdjustment sets an additional number of pixels that is
+ // added to the advance after each output cluster. This matches the behaviour
+ // of WidthIterator::advance.
+ void setLetterSpacingAdjustment(int letterSpacingAdjustment) { m_letterSpacing = letterSpacingAdjustment; }
+ int letterSpacing() const { return m_letterSpacing; }
+
+ // Set the x offset for the next script run. This affects the values in
+ // |xPositions|
+ void setXOffsetToZero() { m_offsetX = 0; }
+ bool rtl() const { return m_run.rtl(); }
+ const uint16_t* glyphs() const { return m_glyphs16; }
+
+ // Return the length of the array returned by |glyphs|
+ const unsigned length() const { return m_item.num_glyphs; }
+
+ // Return the x offset for each of the glyphs. Note that this is translated
+ // by the current x offset and that the x offset is updated for each script
+ // run.
+ const SkScalar* xPositions() const { return m_xPositions; }
+
+ // Get the advances (widths) for each glyph.
+ const HB_Fixed* advances() const { return m_item.advances; }
+
+ // Return the width (in px) of the current script run.
+ const unsigned width() const { return m_pixelWidth; }
+
+ // Return the cluster log for the current script run. For example:
+ // script run: f i a n c é (fi gets ligatured)
+ // log clutrs: 0 0 1 2 3 4
+ // So, for each input code point, the log tells you which output glyph was
+ // generated for it.
+ const unsigned short* logClusters() const { return m_item.log_clusters; }
+
+ // return the number of code points in the current script run
+ const unsigned numCodePoints() const { return m_numCodePoints; }
+
+ const FontPlatformData* fontPlatformDataForScriptRun() { return reinterpret_cast<FontPlatformData*>(m_item.font->userData); }
+
+private:
+ void setupFontForScriptRun();
+ HB_FontRec* allocHarfbuzzFont();
+ void deleteGlyphArrays();
+ void createGlyphArrays(int);
+ void resetGlyphArrays();
+ void shapeGlyphs();
+ void setGlyphXPositions(bool);
+
+ static void normalizeSpacesAndMirrorChars(const UChar* source, bool rtl, UChar* destination, int length);
+ static const TextRun& getNormalizedTextRun(const TextRun& originalRun, OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer);
+
+ // This matches the logic in RenderBlock::findNextLineBreak
+ static bool isCodepointSpace(HB_UChar16 c) { return c == ' ' || c == '\t'; }
+
+ const Font* const m_font;
+ const SimpleFontData* m_currentFontData;
+ HB_ShaperItem m_item;
+ uint16_t* m_glyphs16; // A vector of 16-bit glyph ids.
+ SkScalar* m_xPositions; // A vector of x positions for each glyph.
+ ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|.
+ const unsigned m_startingX; // Offset in pixels of the first script run.
+ unsigned m_offsetX; // Offset in pixels to the start of the next script run.
+ unsigned m_pixelWidth; // Width (in px) of the current script run.
+ unsigned m_numCodePoints; // Code points in current script run.
+ unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays.
+
+ OwnPtr<TextRun> m_normalizedRun;
+ OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run.
+ const TextRun& m_run;
+ bool m_iterateBackwards;
+ int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break.
+ float m_padding; // pixels to be distributed over the line at word breaks.
+ float m_padPerWordBreak; // pixels to be added to each word break.
+ float m_padError; // |m_padPerWordBreak| might have a fractional component.
+ // Since we only add a whole number of padding pixels at
+ // each word break we accumulate error. This is the
+ // number of pixels that we are behind so far.
+ int m_letterSpacing; // pixels to be added after each glyph.
+};
+
+} // namespace WebCore
+
+#endif // ComplexTextControllerLinux_h
diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
new file mode 100644
index 0000000..d00faf8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "ContentLayerChromium.h"
+
+#include "GraphicsContext3D.h"
+#include "LayerRendererChromium.h"
+#include "LayerTexture.h"
+#include "RenderLayerBacking.h"
+
+#if PLATFORM(SKIA)
+#include "NativeImageSkia.h"
+#include "PlatformContextSkia.h"
+#include "SkColorPriv.h"
+#include "skia/ext/platform_canvas.h"
+#elif PLATFORM(CG)
+#include <CoreGraphics/CGBitmapContext.h>
+#endif
+
+namespace WebCore {
+
+ContentLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context)
+ : m_context(context)
+ , m_contentShaderProgram(0)
+ , m_shaderSamplerLocation(-1)
+ , m_shaderMatrixLocation(-1)
+ , m_shaderAlphaLocation(-1)
+ , m_initialized(false)
+{
+ // Shaders for drawing the layer contents.
+ char vertexShaderString[] =
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "uniform mat4 matrix; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = matrix * a_position; \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+
+#if PLATFORM(SKIA)
+ // Color is in RGBA order.
+ char rgbaFragmentShaderString[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "uniform float alpha; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 texColor = texture2D(s_texture, v_texCoord); \n"
+ " gl_FragColor = texColor * alpha; \n"
+ "} \n";
+#endif
+
+ // Color is in BGRA order.
+ char bgraFragmentShaderString[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "uniform float alpha; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 texColor = texture2D(s_texture, v_texCoord); \n"
+ " gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha; \n"
+ "} \n";
+
+#if PLATFORM(SKIA)
+ // Assuming the packing is either Skia default RGBA or Chromium default BGRA.
+ char* fragmentShaderString = SK_B32_SHIFT ? rgbaFragmentShaderString : bgraFragmentShaderString;
+#else
+ char* fragmentShaderString = bgraFragmentShaderString;
+#endif
+ m_contentShaderProgram = createShaderProgram(m_context, vertexShaderString, fragmentShaderString);
+ if (!m_contentShaderProgram) {
+ LOG_ERROR("ContentLayerChromium: Failed to create shader program");
+ return;
+ }
+
+ m_shaderSamplerLocation = m_context->getUniformLocation(m_contentShaderProgram, "s_texture");
+ m_shaderMatrixLocation = m_context->getUniformLocation(m_contentShaderProgram, "matrix");
+ m_shaderAlphaLocation = m_context->getUniformLocation(m_contentShaderProgram, "alpha");
+ ASSERT(m_shaderSamplerLocation != -1);
+ ASSERT(m_shaderMatrixLocation != -1);
+ ASSERT(m_shaderAlphaLocation != -1);
+
+ m_initialized = true;
+}
+
+ContentLayerChromium::SharedValues::~SharedValues()
+{
+ if (m_contentShaderProgram)
+ GLC(m_context, m_context->deleteProgram(m_contentShaderProgram));
+}
+
+
+PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChromium* owner)
+{
+ return adoptRef(new ContentLayerChromium(owner));
+}
+
+ContentLayerChromium::ContentLayerChromium(GraphicsLayerChromium* owner)
+ : LayerChromium(owner)
+ , m_contentsTexture(0)
+ , m_skipsDraw(false)
+{
+}
+
+ContentLayerChromium::~ContentLayerChromium()
+{
+ cleanupResources();
+}
+
+void ContentLayerChromium::cleanupResources()
+{
+ LayerChromium::cleanupResources();
+ m_contentsTexture.clear();
+}
+
+bool ContentLayerChromium::requiresClippedUpdateRect() const
+{
+ // To avoid allocating excessively large textures, switch into "large layer mode" if
+ // one of the layer's dimensions is larger than 2000 pixels or the size of
+ // surface it's rendering into. This is a temporary measure until layer tiling is implemented.
+ static const int maxLayerSize = 2000;
+ return (m_bounds.width() > max(maxLayerSize, m_targetRenderSurface->contentRect().width())
+ || m_bounds.height() > max(maxLayerSize, m_targetRenderSurface->contentRect().height())
+ || !layerRenderer()->checkTextureSize(m_bounds));
+}
+
+void ContentLayerChromium::updateContentsIfDirty()
+{
+ RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client());
+ if (!backing || backing->paintingGoesToWindow())
+ return;
+
+ ASSERT(drawsContent());
+
+ ASSERT(layerRenderer());
+
+ void* pixels = 0;
+ IntRect dirtyRect;
+ IntRect updateRect;
+ IntSize requiredTextureSize;
+ IntSize bitmapSize;
+ IntRect boundsRect(IntPoint(0, 0), m_bounds);
+
+ // FIXME: Remove this test when tiled layers are implemented.
+ if (requiresClippedUpdateRect()) {
+ // A layer with 3D transforms could require an arbitrarily large number
+ // of texels to be repainted, so ignore these layers until tiling is
+ // implemented.
+ if (!drawTransform().isIdentityOrTranslation()) {
+ m_skipsDraw = true;
+ return;
+ }
+
+ // Calculate the region of this layer that is currently visible.
+ const IntRect clipRect = m_targetRenderSurface->contentRect();
+
+ TransformationMatrix layerOriginTransform = drawTransform();
+ layerOriginTransform.translate3d(-0.5 * m_bounds.width(), -0.5 * m_bounds.height(), 0);
+
+ // For now we apply the large layer treatment only for layers that are either untransformed
+ // or are purely translated. Their matrix is expected to be invertible.
+ ASSERT(layerOriginTransform.isInvertible());
+
+ TransformationMatrix targetToLayerMatrix = layerOriginTransform.inverse();
+ IntRect visibleRectInLayerCoords = targetToLayerMatrix.mapRect(clipRect);
+ visibleRectInLayerCoords.intersect(IntRect(0, 0, m_bounds.width(), m_bounds.height()));
+
+ // For normal layers, the center of the texture corresponds with the center of the layer.
+ // In large layers the center of the texture is the center of the visible region so we have
+ // to keep track of the offset in order to render correctly.
+ IntRect visibleRectInSurfaceCoords = layerOriginTransform.mapRect(visibleRectInLayerCoords);
+ m_layerCenterInSurfaceCoords = FloatRect(visibleRectInSurfaceCoords).center();
+
+ // If this is still too large to render, then skip the layer completely.
+ if (!layerRenderer()->checkTextureSize(visibleRectInLayerCoords.size())) {
+ m_skipsDraw = true;
+ return;
+ }
+
+ // If the visible portion of the layer is different from the last upload, or if our backing
+ // texture has been evicted, then the whole layer is considered dirty.
+ if (visibleRectInLayerCoords != m_visibleRectInLayerCoords || !m_contentsTexture || !m_contentsTexture->isValid(requiredTextureSize, GraphicsContext3D::RGBA))
+ m_dirtyRect = boundsRect;
+ m_visibleRectInLayerCoords = visibleRectInLayerCoords;
+
+ // Calculate the portion of the dirty rectangle that is visible. m_dirtyRect is in layer space.
+ IntRect visibleDirtyRectInLayerSpace = enclosingIntRect(m_dirtyRect);
+ visibleDirtyRectInLayerSpace.intersect(visibleRectInLayerCoords);
+
+ // What the rectangles mean:
+ // dirtyRect: The region of this layer that will be updated.
+ // updateRect: The region of the layer's texture that will be uploaded into.
+ // requiredTextureSize: is the required size of this layer's texture.
+ dirtyRect = visibleDirtyRectInLayerSpace;
+ updateRect = dirtyRect;
+ IntSize visibleRectOffsetInLayerCoords(visibleRectInLayerCoords.x(), visibleRectInLayerCoords.y());
+ updateRect.move(-visibleRectOffsetInLayerCoords);
+ requiredTextureSize = visibleRectInLayerCoords.size();
+ } else {
+ dirtyRect = IntRect(m_dirtyRect);
+ requiredTextureSize = m_bounds;
+ // If the texture needs to be reallocated then we must redraw the entire
+ // contents of the layer.
+ if (!m_contentsTexture || !m_contentsTexture->isValid(requiredTextureSize, GraphicsContext3D::RGBA))
+ dirtyRect = boundsRect;
+ else {
+ // Clip the dirtyRect to the size of the layer to avoid drawing
+ // outside the bounds of the backing texture.
+ dirtyRect.intersect(boundsRect);
+ }
+ updateRect = dirtyRect;
+ }
+
+ if (dirtyRect.isEmpty())
+ return;
+
+#if PLATFORM(SKIA)
+ const SkBitmap* skiaBitmap = 0;
+ OwnPtr<skia::PlatformCanvas> canvas;
+ OwnPtr<PlatformContextSkia> skiaContext;
+ OwnPtr<GraphicsContext> graphicsContext;
+
+ canvas.set(new skia::PlatformCanvas(dirtyRect.width(), dirtyRect.height(), false));
+ skiaContext.set(new PlatformContextSkia(canvas.get()));
+
+ // This is needed to get text to show up correctly.
+ // FIXME: Does this take us down a very slow text rendering path?
+ skiaContext->setDrawingToImageBuffer(true);
+
+ graphicsContext.set(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(skiaContext.get())));
+
+ // Bring the canvas into the coordinate system of the paint rect.
+ canvas->translate(static_cast<SkScalar>(-dirtyRect.x()), static_cast<SkScalar>(-dirtyRect.y()));
+
+ m_owner->paintGraphicsLayerContents(*graphicsContext, dirtyRect);
+ const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false);
+ skiaBitmap = &bitmap;
+ ASSERT(skiaBitmap);
+
+ SkAutoLockPixels lock(*skiaBitmap);
+ SkBitmap::Config skiaConfig = skiaBitmap->config();
+ // FIXME: do we need to support more image configurations?
+ if (skiaConfig == SkBitmap::kARGB_8888_Config) {
+ pixels = skiaBitmap->getPixels();
+ bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height());
+ }
+#elif PLATFORM(CG)
+ Vector<uint8_t> tempVector;
+ int rowBytes = 4 * dirtyRect.width();
+ tempVector.resize(rowBytes * dirtyRect.height());
+ memset(tempVector.data(), 0, tempVector.size());
+ RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ RetainPtr<CGContextRef> contextCG(AdoptCF, CGBitmapContextCreate(tempVector.data(),
+ dirtyRect.width(), dirtyRect.height(), 8, rowBytes,
+ colorSpace.get(),
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+ CGContextTranslateCTM(contextCG.get(), 0, dirtyRect.height());
+ CGContextScaleCTM(contextCG.get(), 1, -1);
+
+ GraphicsContext graphicsContext(contextCG.get());
+
+ // Translate the graphics context into the coordinate system of the dirty rect.
+ graphicsContext.translate(-dirtyRect.x(), -dirtyRect.y());
+
+ m_owner->paintGraphicsLayerContents(graphicsContext, dirtyRect);
+
+ pixels = tempVector.data();
+ bitmapSize = dirtyRect.size();
+#else
+#error "Need to implement for your platform."
+#endif
+
+ if (pixels)
+ updateTextureRect(pixels, requiredTextureSize, updateRect);
+}
+
+void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& requiredTextureSize, const IntRect& updateRect)
+{
+ if (!pixels)
+ return;
+
+ GraphicsContext3D* context = layerRendererContext();
+ if (!m_contentsTexture)
+ m_contentsTexture = LayerTexture::create(context, layerRenderer()->textureManager());
+
+ if (!m_contentsTexture->reserve(requiredTextureSize, GraphicsContext3D::RGBA)) {
+ m_skipsDraw = true;
+ return;
+ }
+
+ m_contentsTexture->bindTexture();
+
+ GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels));
+
+ m_dirtyRect.setSize(FloatSize());
+ // Large layers always stay dirty, because they need to update when the content rect changes.
+ m_contentsDirty = requiresClippedUpdateRect();
+}
+
+void ContentLayerChromium::draw()
+{
+ if (m_skipsDraw)
+ return;
+
+ ASSERT(layerRenderer());
+
+ const ContentLayerChromium::SharedValues* sv = layerRenderer()->contentLayerSharedValues();
+ ASSERT(sv && sv->initialized());
+ GraphicsContext3D* context = layerRendererContext();
+ GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0));
+ m_contentsTexture->bindTexture();
+ layerRenderer()->useShader(sv->contentShaderProgram());
+ GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0));
+
+ if (requiresClippedUpdateRect()) {
+ float m43 = drawTransform().m43();
+ TransformationMatrix transform;
+ transform.translate3d(m_layerCenterInSurfaceCoords.x(), m_layerCenterInSurfaceCoords.y(), m43);
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(),
+ transform, m_visibleRectInLayerCoords.width(),
+ m_visibleRectInLayerCoords.height(), drawOpacity(),
+ sv->shaderMatrixLocation(), sv->shaderAlphaLocation());
+ } else {
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(),
+ drawTransform(), m_bounds.width(), m_bounds.height(),
+ drawOpacity(), sv->shaderMatrixLocation(),
+ sv->shaderAlphaLocation());
+ }
+ m_contentsTexture->unreserve();
+}
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h
new file mode 100644
index 0000000..dc1630b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 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 ContentLayerChromium_h
+#define ContentLayerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "LayerChromium.h"
+#include "TextureManager.h"
+
+namespace WebCore {
+
+class LayerTexture;
+
+// A Layer that requires a GraphicsContext to render its contents.
+class ContentLayerChromium : public LayerChromium {
+ friend class LayerRendererChromium;
+public:
+ static PassRefPtr<ContentLayerChromium> create(GraphicsLayerChromium* owner = 0);
+
+ virtual ~ContentLayerChromium();
+
+ virtual void updateContentsIfDirty();
+ virtual void draw();
+ virtual bool drawsContent() { return m_owner && m_owner->drawsContent(); }
+
+ // Stores values that are shared between instances of this class that are
+ // associated with the same LayerRendererChromium (and hence the same GL
+ // context).
+ class SharedValues {
+ public:
+ explicit SharedValues(GraphicsContext3D*);
+ ~SharedValues();
+
+ unsigned contentShaderProgram() const { return m_contentShaderProgram; }
+ int shaderSamplerLocation() const { return m_shaderSamplerLocation; }
+ int shaderMatrixLocation() const { return m_shaderMatrixLocation; }
+ int shaderAlphaLocation() const { return m_shaderAlphaLocation; }
+ int initialized() const { return m_initialized; }
+
+ private:
+ GraphicsContext3D* m_context;
+ unsigned m_contentShaderProgram;
+ int m_shaderSamplerLocation;
+ int m_shaderMatrixLocation;
+ int m_shaderAlphaLocation;
+ int m_initialized;
+ };
+
+protected:
+ explicit ContentLayerChromium(GraphicsLayerChromium* owner);
+
+ void updateTextureRect(void* pixels, const IntSize& requiredTextureSize, const IntRect& updateRect);
+
+ virtual void cleanupResources();
+ bool requiresClippedUpdateRect() const;
+
+ OwnPtr<LayerTexture> m_contentsTexture;
+ bool m_skipsDraw;
+
+private:
+
+ IntRect m_visibleRectInLayerCoords;
+ FloatPoint m_layerCenterInSurfaceCoords;
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.h b/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.h
new file mode 100644
index 0000000..e1fb740
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 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 CrossProcessFontLoading_h
+#define CrossProcessFontLoading_h
+
+#import <wtf/RefCounted.h>
+#import <wtf/RetainPtr.h>
+
+typedef struct CGFont* CGFontRef;
+typedef UInt32 ATSFontContainerRef;
+typedef UInt32 ATSFontRef;
+
+namespace WebCore {
+
+// MemoryActivatedFont encapsulates a font loaded from another process and
+// activated from memory.
+//
+// Responsibilities:
+// * Holder for the CGFontRef & ATSFontRef belonging to the activated font.
+// * Responsible for unloading the font container when done.
+//
+// Memory Management:
+// The class is reference counted, with each instance of FontPlatformData that
+// uses this class holding a reference to it.
+// Entries are kept track of internally in a hash to allow quick lookup
+// of existing instances for reuse:
+// - fontCacheBySrcFontContainerRef() - key is the ATSFontContainerRef
+// corresponding to the *original in-process NSFont* whose loading was blocked
+// by the sandbox.
+// This is needed to allow lookup of a pre-existing MemoryActivatedFont when
+// creating a new FontPlatformData object.
+//
+// Assumptions:
+// This code assumes that an ATSFontRef is a unique identifier tied to an
+// activated font. i.e. After we activate a font, its ATSFontRef doesn't
+// change.
+// It also assumes that the ATSFoncontainerRef for two in-memory NSFonts that
+// correspond to the same on-disk font file are always the same and don't change
+// with time.
+//
+// Flushing caches:
+// When the system notifies us of a system font cache flush, all FontDataCache
+// objects are destroyed. This should in turn dereference all
+// MemoryActivatedFonts and thus unload all in-memory fonts.
+class MemoryActivatedFont : public RefCounted<MemoryActivatedFont> {
+public:
+ // Use to create a new object, see docs on constructor below.
+ static PassRefPtr<MemoryActivatedFont> create(ATSFontContainerRef srcFontContainerRef, ATSFontContainerRef container);
+ ~MemoryActivatedFont();
+
+ // Get cached CGFontRef corresponding to the in-memory font.
+ CGFontRef cgFont() { return m_cgFont.get(); }
+
+ // Get cached ATSFontRef corresponding to the in-memory font.
+ ATSFontRef atsFontRef() { return m_atsFontRef; }
+
+private:
+ // srcFontRef - ATSFontRef belonging to the NSFont object that failed to
+ // load in-process.
+ // container - a font container corresponding to an identical font that
+ // we loaded cross-process.
+ MemoryActivatedFont(ATSFontContainerRef srcFontContainerRef, ATSFontContainerRef container);
+
+ ATSFontContainerRef m_fontContainer;
+ WTF::RetainPtr<CGFontRef> m_cgFont;
+ ATSFontRef m_atsFontRef;
+ ATSFontContainerRef m_srcFontContainerRef;
+};
+
+} // namespace WebCore
+
+#endif // CrossProcessFontLoading_h
diff --git a/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.mm b/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.mm
new file mode 100644
index 0000000..72e3369
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.mm
@@ -0,0 +1,210 @@
+/*
+ * This file is part of the internal font implementation.
+ *
+ * Copyright (c) 2010 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+// This file provides additional functionality to the Mac FontPlatformData class
+// defined in WebCore/platform/cocoa/FontPlatformDataCocoa.mm .
+// Because we want to support loading fonts between processes in the face of
+// font loading being blocked by the sandbox, we need a mechnasim to both
+// do the loading of in-memory fonts and keep track of them.
+
+#import "config.h"
+#import "CrossProcessFontLoading.h"
+
+#import "../graphics/cocoa/FontPlatformData.h"
+#import "ChromiumBridge.h"
+#import <AppKit/NSFont.h>
+#import <wtf/HashMap.h>
+
+namespace WebCore {
+
+namespace {
+
+typedef HashMap<ATSFontContainerRef, MemoryActivatedFont*> FontContainerRefMemoryFontHash;
+
+// On 10.5, font loading is not blocked by the sandbox and thus there is no
+// need for the cross-process font loading mechanim.
+// On system versions >=10.6 cross-process font loading is required.
+bool OutOfProcessFontLoadingEnabled()
+{
+ static SInt32 systemVersion = 0;
+ if (!systemVersion) {
+ if (Gestalt(gestaltSystemVersion, &systemVersion) != noErr)
+ return false;
+ }
+
+ return systemVersion >= 0x1060;
+}
+
+FontContainerRefMemoryFontHash& fontCacheBySrcFontContainerRef()
+{
+ DEFINE_STATIC_LOCAL(FontContainerRefMemoryFontHash, srcFontRefCache, ());
+ return srcFontRefCache;
+}
+
+ATSFontContainerRef fontContainerRefFromNSFont(NSFont* srcFont)
+{
+ ATSFontRef fontRef = CTFontGetPlatformFont(toCTFontRef(srcFont), 0);
+ if (!fontRef)
+ return kATSFontContainerRefUnspecified;
+ ATSFontContainerRef fontContainer = kATSFontContainerRefUnspecified;
+ if (ATSFontGetContainer(fontRef, 0, &fontContainer) != noErr)
+ return kATSFontContainerRefUnspecified;
+ return fontContainer;
+}
+
+// The only way we can tell that an in-process font has failed to load
+// is if CTFontCopyGraphicsFont() returns the LastResort font.
+bool isLastResortFont(CGFontRef cgFont)
+{
+ NSString* fontName = (NSString*)CGFontCopyPostScriptName(cgFont);
+ return [fontName isEqualToString:@"LastResort"];
+}
+
+// Given an in-process font which has failed to load, return a
+// MemoryActivatedFont* corresponding to an in-memory representation of the
+// same font loaded from the browser process.
+// On failure this function returns a PassRefPtr pointing to 0.
+PassRefPtr<MemoryActivatedFont> loadFontFromBrowserProcess(NSFont* nsFont)
+{
+ ATSFontContainerRef container;
+ // Send cross-process request to load font.
+ if (!ChromiumBridge::loadFont(nsFont, &container))
+ return 0;
+
+ ATSFontContainerRef srcFontContainerRef = fontContainerRefFromNSFont(nsFont);
+ if (!srcFontContainerRef) {
+ ATSFontDeactivate(container, 0, kATSOptionFlagsDefault);
+ return 0;
+ }
+
+ PassRefPtr<MemoryActivatedFont> font = adoptRef(fontCacheBySrcFontContainerRef().get(srcFontContainerRef));
+ if (font.get())
+ return font;
+
+ return MemoryActivatedFont::create(srcFontContainerRef, container);
+}
+
+} // namespace
+
+PassRefPtr<MemoryActivatedFont> MemoryActivatedFont::create(ATSFontContainerRef srcFontContainerRef, ATSFontContainerRef container)
+{
+ MemoryActivatedFont* font = new MemoryActivatedFont(srcFontContainerRef, container);
+ if (!font->cgFont()) // Object construction failed.
+ {
+ delete font;
+ return 0;
+ }
+ return adoptRef(font);
+}
+
+MemoryActivatedFont::MemoryActivatedFont(ATSFontContainerRef srcFontContainerRef, ATSFontContainerRef container)
+ : m_fontContainer(container)
+ , m_atsFontRef(kATSFontRefUnspecified)
+ , m_srcFontContainerRef(srcFontContainerRef)
+{
+ if (!container)
+ return;
+
+ // Count the number of fonts in the container.
+ ItemCount fontCount = 0;
+ OSStatus err = ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 0, 0, &fontCount);
+ if (err != noErr || fontCount < 1)
+ return;
+
+ // For now always assume that we want the first font in the container.
+ ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 1, &m_atsFontRef, 0);
+
+ if (!m_atsFontRef)
+ return;
+
+ // Cache CGFont representation of the font.
+ m_cgFont.adoptCF(CGFontCreateWithPlatformFont(&m_atsFontRef));
+
+ if (!m_cgFont.get())
+ return;
+
+ // Add ourselves to cache.
+ fontCacheBySrcFontContainerRef().add(m_srcFontContainerRef, this);
+}
+
+// Destructor - Unload font container from memory and remove ourselves
+// from cache.
+MemoryActivatedFont::~MemoryActivatedFont()
+{
+ if (m_cgFont.get()) {
+ // First remove ourselves from the caches.
+ ASSERT(fontCacheBySrcFontContainerRef().contains(m_srcFontContainerRef));
+
+ fontCacheBySrcFontContainerRef().remove(m_srcFontContainerRef);
+
+ // Make sure the CGFont is destroyed before its font container.
+ m_cgFont.releaseRef();
+ }
+
+ if (m_fontContainer != kATSFontContainerRefUnspecified)
+ ATSFontDeactivate(m_fontContainer, 0, kATSOptionFlagsDefault);
+}
+
+// Given an NSFont, try to load a representation of that font into the cgFont
+// parameter. If loading is blocked by the sandbox, the font may be loaded
+// cross-process.
+// If sandbox loading also fails, a fallback font is loaded.
+//
+// Considerations:
+// * cgFont must be CFRelease()ed by the caller when done.
+//
+// Parameters:
+// * nsFont - The font we wish to load.
+// * fontSize - point size of the font we wish to load.
+// * outNSFont - The font that was actually loaded, may be different from nsFont
+// if a fallback font was used.
+// * cgFont - on output this contains the CGFontRef corresponding to the NSFont
+// that was picked in the end. The caller is responsible for calling
+// CFRelease() on this parameter when done with it.
+// * fontID - on output, the ID corresponding to nsFont.
+void FontPlatformData::loadFont(NSFont* nsFont, float fontSize, NSFont*& outNSFont, CGFontRef& cgFont)
+{
+ outNSFont = nsFont;
+ cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0);
+ if (OutOfProcessFontLoadingEnabled() && outNSFont && cgFont && isLastResortFont(cgFont)) {
+ // Release old CGFontRef since it points at the LastResort font which we don't want.
+ CFRelease(cgFont);
+ cgFont = 0;
+
+ // Font loading was blocked by the Sandbox.
+ m_inMemoryFont = loadFontFromBrowserProcess(outNSFont);
+ if (m_inMemoryFont.get()) {
+ cgFont = m_inMemoryFont->cgFont();
+
+ // Need to add an extra retain so output semantics of this function
+ // are consistent.
+ CFRetain(cgFont);
+ } else {
+ // If we still can't load the font, then return Times,
+ // rather than the LastResort font.
+ outNSFont = [NSFont fontWithName:@"Times" size:fontSize];
+ cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0);
+ }
+ }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp
new file mode 100644
index 0000000..507c227
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+
+#include "DrawingBuffer.h"
+
+#include "Extensions3DChromium.h"
+#include "GraphicsContext3D.h"
+#include "SharedGraphicsContext3D.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "Canvas2DLayerChromium.h"
+#endif
+
+namespace WebCore {
+
+struct DrawingBufferInternal {
+ unsigned offscreenColorTexture;
+#if USE(ACCELERATED_COMPOSITING)
+ RefPtr<Canvas2DLayerChromium> platformLayer;
+#endif
+};
+
+static unsigned generateColorTexture(GraphicsContext3D* context, const IntSize& size)
+{
+ unsigned offscreenColorTexture = context->createTexture();
+ if (!offscreenColorTexture)
+ return 0;
+
+ context->bindTexture(GraphicsContext3D::TEXTURE_2D, offscreenColorTexture);
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST);
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST);
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
+ context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, size.width(), size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE);
+ context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, offscreenColorTexture, 0);
+
+ return offscreenColorTexture;
+}
+
+
+DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, const IntSize& size)
+ : m_context(context)
+ , m_size(size)
+ , m_fbo(0)
+ , m_colorBuffer(0)
+ , m_depthStencilBuffer(0)
+ , m_multisampleFBO(0)
+ , m_multisampleColorBuffer(0)
+ , m_multisampleDepthStencilBuffer(0)
+ , m_internal(new DrawingBufferInternal)
+{
+ if (!m_context->getExtensions()->supports("GL_CHROMIUM_copy_texture_to_parent_texture")) {
+ m_context.clear();
+ return;
+ }
+ m_fbo = context->createFramebuffer();
+ context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
+ m_colorBuffer = generateColorTexture(context, size);
+}
+
+DrawingBuffer::~DrawingBuffer()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_internal->platformLayer)
+ m_internal->platformLayer->setDrawingBuffer(0);
+#endif
+
+ if (!m_context)
+ return;
+
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
+ m_context->deleteTexture(m_colorBuffer);
+
+ clear();
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+void DrawingBuffer::publishToPlatformLayer()
+{
+ if (!m_context)
+ return;
+
+ if (m_callback)
+ m_callback->willPublish();
+ unsigned parentTexture = m_internal->platformLayer->textureId();
+ // FIXME: We do the copy in the canvas' (child) context so that it executes in the correct order relative to
+ // other commands in the child context. This ensures that the parent texture always contains a complete
+ // frame and not some intermediate result. However, there is no synchronization to ensure that this copy
+ // happens before the compositor draws. This means we might draw stale frames sometimes. Ideally this
+ // would insert a fence into the child command stream that the compositor could wait for.
+ m_context->makeContextCurrent();
+ static_cast<Extensions3DChromium*>(m_context->getExtensions())->copyTextureToParentTextureCHROMIUM(m_colorBuffer, parentTexture);
+ m_context->flush();
+}
+#endif
+
+void DrawingBuffer::didReset()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_internal->platformLayer)
+ m_internal->platformLayer->setTextureChanged();
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* DrawingBuffer::platformLayer()
+{
+ if (!m_internal->platformLayer)
+ m_internal->platformLayer = Canvas2DLayerChromium::create(this, 0);
+ return m_internal->platformLayer.get();
+}
+#endif
+
+Platform3DObject DrawingBuffer::platformColorBuffer() const
+{
+ return m_colorBuffer;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h b/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h
new file mode 100644
index 0000000..d120424
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 Extensions3DChromium_h
+#define Extensions3DChromium_h
+
+#include "Extensions3D.h"
+
+namespace WebCore {
+
+class GraphicsContext3DInternal;
+
+class Extensions3DChromium : public Extensions3D {
+public:
+ virtual ~Extensions3DChromium();
+
+ // Supported extensions:
+ // GL_CHROMIUM_resource_safe : indicating that textures/renderbuffers are always initialized before read/write.
+ // GL_CHROMIUM_strict_attribs : indicating a GL error is generated for out-of-bounds buffer accesses.
+
+ // Extensions3D methods.
+ virtual bool supports(const String&);
+ virtual void ensureEnabled(const String&);
+ virtual int getGraphicsResetStatusARB();
+ virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter) { }
+ virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height) { }
+
+ enum {
+ // GL_CHROMIUM_map_sub (enums inherited from GL_ARB_vertex_buffer_object)
+ READ_ONLY = 0x88B8,
+ WRITE_ONLY = 0x88B9
+ };
+
+ // GL_CHROMIUM_map_sub
+ void* mapBufferSubDataCHROMIUM(unsigned target, int offset, int size, unsigned access);
+ void unmapBufferSubDataCHROMIUM(const void*);
+ void* mapTexSubImage2DCHROMIUM(unsigned target, int level, int xoffset, int yoffset, int width, int height, unsigned format, unsigned type, unsigned access);
+ void unmapTexSubImage2DCHROMIUM(const void*);
+
+ // GL_CHROMIUM_copy_texture_to_parent_texture
+ void copyTextureToParentTextureCHROMIUM(unsigned texture, unsigned parentTexture);
+
+private:
+ // Instances of this class are strictly owned by the GraphicsContext3D implementation and do not
+ // need to be instantiated by any other code.
+ friend class GraphicsContext3DInternal;
+ explicit Extensions3DChromium(GraphicsContext3DInternal*);
+
+ // Weak pointer back to GraphicsContext3DInternal
+ GraphicsContext3DInternal* m_internal;
+};
+
+} // namespace WebCore
+
+#endif // Extensions3DChromium_h
diff --git a/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
new file mode 100644
index 0000000..2c79815
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Inc.
+ * Copyright (c) 2006, 2007, 2008, 2009 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.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "ChromiumBridge.h"
+#include "Font.h"
+#include "FontUtilsChromiumWin.h"
+#include "HashMap.h"
+#include "HashSet.h"
+#include "SimpleFontData.h"
+#include <unicode/uniset.h>
+#include <wtf/text/StringHash.h>
+
+#include <windows.h>
+#include <objidl.h>
+#include <mlang.h>
+
+using std::min;
+
+namespace WebCore
+{
+
+// FIXME: consider adding to WebKit String class
+static bool charactersAreAllASCII(const String& s)
+{
+ return WTF::charactersAreAllASCII(s.characters(), s.length());
+}
+
+// When asked for a CJK font with a native name under a non-CJK locale or
+// asked for a CJK font with a Romanized name under a CJK locale,
+// |GetTextFace| (after |CreateFont*|) returns a 'bogus' value (e.g. Arial).
+// This is not consistent with what MSDN says !!
+// Therefore, before we call |CreateFont*|, we have to map a Romanized name to
+// the corresponding native name under a CJK locale and vice versa
+// under a non-CJK locale.
+// See the corresponding gecko bugs at
+// https://bugzilla.mozilla.org/show_bug.cgi?id=373952
+// https://bugzilla.mozilla.org/show_bug.cgi?id=231426
+static bool LookupAltName(const String& name, String& altName)
+{
+ struct FontCodepage {
+ WCHAR* name;
+ int codePage;
+ };
+
+ struct NamePair {
+ WCHAR* name;
+ FontCodepage altNameCodepage;
+ };
+
+ const int japaneseCodepage = 932;
+ const int simplifiedChineseCodepage = 936;
+ const int koreanCodepage = 949;
+ const int traditionalChineseCodepage = 950;
+
+ // FIXME(jungshik) : This list probably covers 99% of cases.
+ // To cover the remaining 1% and cut down the file size,
+ // consider accessing 'NAME' table of a truetype font
+ // using |GetFontData| and caching the mapping.
+ // In the table below, the ASCII keys are all lower-cased for
+ // case-insensitive matching.
+ static const NamePair namePairs[] = {
+ // MS Pゴシック, MS PGothic
+ {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", {L"MS PGothic", japaneseCodepage}},
+ {L"ms pgothic", {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", japaneseCodepage}},
+ // MS P明朝, MS PMincho
+ {L"\xFF2D\xFF33 \xFF30\x660E\x671D", {L"MS PMincho", japaneseCodepage}},
+ {L"ms pmincho", {L"\xFF2D\xFF33 \xFF30\x660E\x671D", japaneseCodepage}},
+ // MSゴシック, MS Gothic
+ {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", {L"MS Gothic", japaneseCodepage}},
+ {L"ms gothic", {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", japaneseCodepage}},
+ // MS 明朝, MS Mincho
+ {L"\xFF2D\xFF33 \x660E\x671D", {L"MS Mincho", japaneseCodepage}},
+ {L"ms mincho", {L"\xFF2D\xFF33 \x660E\x671D", japaneseCodepage}},
+ // メイリオ, Meiryo
+ {L"\x30E1\x30A4\x30EA\x30AA", {L"Meiryo", japaneseCodepage}},
+ {L"meiryo", {L"\x30E1\x30A4\x30EA\x30AA", japaneseCodepage}},
+ // 바탕, Batang
+ {L"\xBC14\xD0D5", {L"Batang", koreanCodepage}},
+ {L"batang", {L"\xBC14\xD0D5", koreanCodepage}},
+ // 바탕체, Batangche
+ {L"\xBC14\xD0D5\xCCB4", {L"Batangche", koreanCodepage}},
+ {L"batangche", {L"\xBC14\xD0D5\xCCB4", koreanCodepage}},
+ // 굴림, Gulim
+ {L"\xAD74\xB9BC", {L"Gulim", koreanCodepage}},
+ {L"gulim", {L"\xAD74\xB9BC", koreanCodepage}},
+ // 굴림체, Gulimche
+ {L"\xAD74\xB9BC\xCCB4", {L"Gulimche", koreanCodepage}},
+ {L"gulimche", {L"\xAD74\xB9BC\xCCB4", koreanCodepage}},
+ // 돋움, Dotum
+ {L"\xB3CB\xC6C0", {L"Dotum", koreanCodepage}},
+ {L"dotum", {L"\xB3CB\xC6C0", koreanCodepage}},
+ // 돋움체, Dotumche
+ {L"\xB3CB\xC6C0\xCCB4", {L"Dotumche", koreanCodepage}},
+ {L"dotumche", {L"\xB3CB\xC6C0\xCCB4", koreanCodepage}},
+ // 궁서, Gungsuh
+ {L"\xAD81\xC11C", {L"Gungsuh", koreanCodepage}},
+ {L"gungsuh", {L"\xAD81\xC11C", koreanCodepage}},
+ // 궁서체, Gungsuhche
+ {L"\xAD81\xC11C\xCCB4", {L"Gungsuhche", koreanCodepage}},
+ {L"gungsuhche", {L"\xAD81\xC11C\xCCB4", koreanCodepage}},
+ // 맑은 고딕, Malgun Gothic
+ {L"\xB9D1\xC740 \xACE0\xB515", {L"Malgun Gothic", koreanCodepage}},
+ {L"malgun gothic", {L"\xB9D1\xC740 \xACE0\xB515", koreanCodepage}},
+ // 宋体, SimSun
+ {L"\x5B8B\x4F53", {L"SimSun", simplifiedChineseCodepage}},
+ {L"simsun", {L"\x5B8B\x4F53", simplifiedChineseCodepage}},
+ // 宋体-ExtB, SimSun-ExtB
+ {L"\x5B8B\x4F53-ExtB", {L"SimSun-ExtB", simplifiedChineseCodepage}},
+ {L"simsun-extb", {L"\x5B8B\x4F53-extb", simplifiedChineseCodepage}},
+ // 黑体, SimHei
+ {L"\x9ED1\x4F53", {L"SimHei", simplifiedChineseCodepage}},
+ {L"simhei", {L"\x9ED1\x4F53", simplifiedChineseCodepage}},
+ // 新宋体, NSimSun
+ {L"\x65B0\x5B8B\x4F53", {L"NSimSun", simplifiedChineseCodepage}},
+ {L"nsimsun", {L"\x65B0\x5B8B\x4F53", simplifiedChineseCodepage}},
+ // 微软雅黑, Microsoft Yahei
+ {L"\x5FAE\x8F6F\x96C5\x9ED1", {L"Microsoft Yahei", simplifiedChineseCodepage}},
+ {L"microsoft yahei", {L"\x5FAE\x8F6F\x96C5\x9ED1", simplifiedChineseCodepage}},
+ // 仿宋, FangSong
+ {L"\x4EFF\x5B8B", {L"FangSong", simplifiedChineseCodepage}},
+ {L"fangsong", {L"\x4EFF\x5B8B", simplifiedChineseCodepage}},
+ // 楷体, KaiTi
+ {L"\x6977\x4F53", {L"KaiTi", simplifiedChineseCodepage}},
+ {L"kaiti", {L"\x6977\x4F53", simplifiedChineseCodepage}},
+ // 仿宋_GB2312, FangSong_GB2312
+ {L"\x4EFF\x5B8B_GB2312", {L"FangSong_GB2312", simplifiedChineseCodepage}},
+ {L"fangsong_gb2312", {L"\x4EFF\x5B8B_gb2312", simplifiedChineseCodepage}},
+ // 楷体_GB2312, KaiTi_GB2312
+ {L"\x6977\x4F53", {L"KaiTi_GB2312", simplifiedChineseCodepage}},
+ {L"kaiti_gb2312", {L"\x6977\x4F53_gb2312", simplifiedChineseCodepage}},
+ // 新細明體, PMingLiu
+ {L"\x65B0\x7D30\x660E\x9AD4", {L"PMingLiu", traditionalChineseCodepage}},
+ {L"pmingliu", {L"\x65B0\x7D30\x660E\x9AD4", traditionalChineseCodepage}},
+ // 新細明體-ExtB, PMingLiu-ExtB
+ {L"\x65B0\x7D30\x660E\x9AD4-ExtB", {L"PMingLiu-ExtB", traditionalChineseCodepage}},
+ {L"pmingliu-extb", {L"\x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCodepage}},
+ // 細明體, MingLiu
+ {L"\x7D30\x660E\x9AD4", {L"MingLiu", traditionalChineseCodepage}},
+ {L"mingliu", {L"\x7D30\x660E\x9AD4", traditionalChineseCodepage}},
+ // 細明體-ExtB, MingLiu-ExtB
+ {L"\x7D30\x660E\x9AD4-ExtB", {L"MingLiu-ExtB", traditionalChineseCodepage}},
+ {L"mingliu-extb", {L"x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCodepage}},
+ // 微軟正黑體, Microsoft JhengHei
+ {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", {L"Microsoft JhengHei", traditionalChineseCodepage}},
+ {L"microsoft jhengHei", {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", traditionalChineseCodepage}},
+ // 標楷體, DFKai-SB
+ {L"\x6A19\x6977\x9AD4", {L"DFKai-SB", traditionalChineseCodepage}},
+ {L"dfkai-sb", {L"\x6A19\x6977\x9AD4", traditionalChineseCodepage}},
+ // WenQuanYi Zen Hei
+ {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", {L"WenQuanYi Zen Hei", traditionalChineseCodepage}},
+ {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", traditionalChineseCodepage}},
+ // WenQuanYi Zen Hei
+ {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", {L"WenQuanYi Zen Hei", simplifiedChineseCodepage}},
+ {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", simplifiedChineseCodepage}},
+ // AR PL ShanHeiSun Uni,
+ {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069",
+ {L"AR PL ShanHeiSun Uni", traditionalChineseCodepage}},
+ {L"ar pl shanheisun uni",
+ {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", traditionalChineseCodepage}},
+ // AR PL ShanHeiSun Uni,
+ {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069",
+ {L"AR PL ShanHeiSun Uni", simplifiedChineseCodepage}},
+ {L"ar pl shanheisun uni",
+ {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", simplifiedChineseCodepage}},
+ // AR PL ZenKai Uni
+ // Traditional Chinese and Simplified Chinese names are
+ // identical.
+ {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", traditionalChineseCodepage}},
+ {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", traditionalChineseCodepage}},
+ {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", simplifiedChineseCodepage}},
+ {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", simplifiedChineseCodepage}},
+ };
+
+ typedef HashMap<String, const FontCodepage*> NameMap;
+ static NameMap* fontNameMap = 0;
+
+ if (!fontNameMap) {
+ fontNameMap = new NameMap;
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(namePairs); ++i)
+ fontNameMap->set(String(namePairs[i].name), &(namePairs[i].altNameCodepage));
+ }
+
+ bool isAscii = false;
+ String n;
+ // use |lower| only for ASCII names
+ // For non-ASCII names, we don't want to invoke an expensive
+ // and unnecessary |lower|.
+ if (charactersAreAllASCII(name)) {
+ isAscii = true;
+ n = name.lower();
+ } else
+ n = name;
+
+ NameMap::iterator iter = fontNameMap->find(n);
+ if (iter == fontNameMap->end())
+ return false;
+
+ static int systemCp = ::GetACP();
+ int fontCp = iter->second->codePage;
+
+ if ((isAscii && systemCp == fontCp) || (!isAscii && systemCp != fontCp)) {
+ altName = String(iter->second->name);
+ return true;
+ }
+
+ return false;
+}
+
+static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winfont, String* winName)
+{
+ int len = min(static_cast<int>(family.length()), LF_FACESIZE - 1);
+ memcpy(winfont->lfFaceName, family.characters(), len * sizeof(WORD));
+ winfont->lfFaceName[len] = '\0';
+
+ HFONT hfont = CreateFontIndirect(winfont);
+ if (!hfont)
+ return 0;
+
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont));
+ WCHAR name[LF_FACESIZE];
+ unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name);
+ if (resultLength > 0)
+ resultLength--; // ignore the null terminator
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+ *winName = String(name, resultLength);
+ return hfont;
+}
+
+// This maps font family names to their repertoires of supported Unicode
+// characters. Because it's family names rather than font faces we use
+// as keys, there might be edge cases where one face of a font family
+// has a different repertoire from another face of the same family.
+typedef HashMap<const wchar_t*, icu::UnicodeSet*> FontCmapCache;
+
+static bool fontContainsCharacter(const FontPlatformData* fontData,
+ const wchar_t* family, UChar32 character)
+{
+ // FIXME: For non-BMP characters, GetFontUnicodeRanges is of
+ // no use. We have to read directly from the cmap table of a font.
+ // Return true for now.
+ if (character > 0xFFFF)
+ return true;
+
+ // This cache is just leaked on shutdown.
+ static FontCmapCache* fontCmapCache = 0;
+ if (!fontCmapCache)
+ fontCmapCache = new FontCmapCache;
+
+ HashMap<const wchar_t*, icu::UnicodeSet*>::iterator it = fontCmapCache->find(family);
+ if (it != fontCmapCache->end())
+ return it->second->contains(character);
+
+ HFONT hfont = fontData->hfont();
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(hdc, hfont));
+ int count = GetFontUnicodeRanges(hdc, 0);
+ if (count == 0 && ChromiumBridge::ensureFontLoaded(hfont))
+ count = GetFontUnicodeRanges(hdc, 0);
+ if (count == 0) {
+ LOG_ERROR("Unable to get the font unicode range after second attempt");
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ return true;
+ }
+
+ static Vector<char, 512> glyphsetBuffer;
+ glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0));
+ GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data());
+ // In addition, refering to the OS/2 table and converting the codepage list
+ // to the coverage map might be faster.
+ count = GetFontUnicodeRanges(hdc, glyphset);
+ ASSERT(count > 0);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ // FIXME: consider doing either of the following two:
+ // 1) port back ICU 4.0's faster look-up code for UnicodeSet
+ // 2) port Mozilla's CompressedCharMap or gfxSparseBitset
+ unsigned i = 0;
+ icu::UnicodeSet* cmap = new icu::UnicodeSet;
+ while (i < glyphset->cRanges) {
+ WCHAR start = glyphset->ranges[i].wcLow;
+ cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1);
+ i++;
+ }
+ cmap->freeze();
+ // We don't lowercase |family| because all of them are under our control
+ // and they're already lowercased.
+ fontCmapCache->set(family, cmap);
+ return cmap->contains(character);
+}
+
+// Tries the given font and save it |outFontFamilyName| if it succeeds.
+static SimpleFontData* fontDataFromDescriptionAndLogFont(FontCache* fontCache, const FontDescription& fontDescription, const LOGFONT& font, wchar_t* outFontFamilyName)
+{
+ SimpleFontData* fontData = fontCache->getCachedFontData(fontDescription, font.lfFaceName);
+ if (fontData)
+ memcpy(outFontFamilyName, font.lfFaceName, sizeof(font.lfFaceName));
+ return fontData;
+}
+
+static LONG toGDIFontWeight(FontWeight fontWeight)
+{
+ static LONG gdiFontWeights[] = {
+ FW_THIN, // FontWeight100
+ FW_EXTRALIGHT, // FontWeight200
+ FW_LIGHT, // FontWeight300
+ FW_NORMAL, // FontWeight400
+ FW_MEDIUM, // FontWeight500
+ FW_SEMIBOLD, // FontWeight600
+ FW_BOLD, // FontWeight700
+ FW_EXTRABOLD, // FontWeight800
+ FW_HEAVY // FontWeight900
+ };
+ return gdiFontWeights[fontWeight];
+}
+
+static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont)
+{
+ // The size here looks unusual. The negative number is intentional.
+ // Unlike WebKit trunk, we don't multiply the size by 32. That seems to be
+ // some kind of artifact of their CG backend, or something.
+ winfont->lfHeight = -fontDescription.computedPixelSize();
+ winfont->lfWidth = 0;
+ winfont->lfEscapement = 0;
+ winfont->lfOrientation = 0;
+ winfont->lfUnderline = false;
+ winfont->lfStrikeOut = false;
+ winfont->lfCharSet = DEFAULT_CHARSET;
+ winfont->lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ winfont->lfQuality = ChromiumBridge::layoutTestMode() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY; // Honor user's desktop settings.
+ winfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ winfont->lfItalic = fontDescription.italic();
+ winfont->lfWeight = toGDIFontWeight(fontDescription.weight());
+}
+
+struct TraitsInFamilyProcData {
+ TraitsInFamilyProcData(const AtomicString& familyName)
+ : m_familyName(familyName)
+ {
+ }
+
+ const AtomicString& m_familyName;
+ HashSet<unsigned> m_traitsMasks;
+};
+
+static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam);
+
+ unsigned traitsMask = 0;
+ traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask;
+ traitsMask |= FontVariantNormalMask;
+ LONG weight = logFont->lfWeight;
+ traitsMask |= weight == FW_THIN ? FontWeight100Mask :
+ weight == FW_EXTRALIGHT ? FontWeight200Mask :
+ weight == FW_LIGHT ? FontWeight300Mask :
+ weight == FW_NORMAL ? FontWeight400Mask :
+ weight == FW_MEDIUM ? FontWeight500Mask :
+ weight == FW_SEMIBOLD ? FontWeight600Mask :
+ weight == FW_BOLD ? FontWeight700Mask :
+ weight == FW_EXTRABOLD ? FontWeight800Mask :
+ FontWeight900Mask;
+ procData->m_traitsMasks.add(traitsMask);
+ return 1;
+}
+
+void FontCache::platformInit()
+{
+ // Not needed on Windows.
+}
+
+// Given the desired base font, this will create a SimpleFontData for a specific
+// font that can be used to render the given range of characters.
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ // FIXME: Consider passing fontDescription.dominantScript()
+ // to GetFallbackFamily here.
+ FontDescription fontDescription = font.fontDescription();
+ UChar32 c;
+ UScriptCode script;
+ const wchar_t* family = getFallbackFamily(characters, length,
+ fontDescription.genericFamily(), &c, &script);
+ FontPlatformData* data = 0;
+ if (family)
+ data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)), false);
+
+ // Last resort font list : PanUnicode. CJK fonts have a pretty
+ // large repertoire. Eventually, we need to scan all the fonts
+ // on the system to have a Firefox-like coverage.
+ // Make sure that all of them are lowercased.
+ const static wchar_t* const cjkFonts[] = {
+ L"arial unicode ms",
+ L"ms pgothic",
+ L"simsun",
+ L"gulim",
+ L"pmingliu",
+ L"wenquanyi zen hei", // partial CJK Ext. A coverage but more
+ // widely known to Chinese users.
+ L"ar pl shanheisun uni",
+ L"ar pl zenkai uni",
+ L"han nom a", // Complete CJK Ext. A coverage
+ L"code2000", // Complete CJK Ext. A coverage
+ // CJK Ext. B fonts are not listed here because it's of no use
+ // with our current non-BMP character handling because we use
+ // Uniscribe for it and that code path does not go through here.
+ };
+
+ const static wchar_t* const commonFonts[] = {
+ L"tahoma",
+ L"arial unicode ms",
+ L"lucida sans unicode",
+ L"microsoft sans serif",
+ L"palatino linotype",
+ // Six fonts below (and code2000 at the end) are not from MS, but
+ // once installed, cover a very wide range of characters.
+ L"dejavu serif",
+ L"dejavu sasns",
+ L"freeserif",
+ L"freesans",
+ L"gentium",
+ L"gentiumalt",
+ L"ms pgothic",
+ L"simsun",
+ L"gulim",
+ L"pmingliu",
+ L"code2000",
+ };
+
+ const wchar_t* const* panUniFonts = 0;
+ int numFonts = 0;
+ if (script == USCRIPT_HAN) {
+ panUniFonts = cjkFonts;
+ numFonts = WTF_ARRAY_LENGTH(cjkFonts);
+ } else {
+ panUniFonts = commonFonts;
+ numFonts = WTF_ARRAY_LENGTH(commonFonts);
+ }
+ // Font returned from GetFallbackFamily may not cover |characters|
+ // because it's based on script to font mapping. This problem is
+ // critical enough for non-Latin scripts (especially Han) to
+ // warrant an additional (real coverage) check with fontCotainsCharacter.
+ int i;
+ for (i = 0; (!data || !fontContainsCharacter(data, family, c)) && i < numFonts; ++i) {
+ family = panUniFonts[i];
+ data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)));
+ }
+ // When i-th font (0-base) in |panUniFonts| contains a character and
+ // we get out of the loop, |i| will be |i + 1|. That is, if only the
+ // last font in the array covers the character, |i| will be numFonts.
+ // So, we have to use '<=" rather than '<' to see if we found a font
+ // covering the character.
+ if (i <= numFonts)
+ return getCachedFontData(data);
+
+ return 0;
+
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& description)
+{
+ FontDescription::GenericFamilyType generic = description.genericFamily();
+
+ // FIXME: Would be even better to somehow get the user's default font here.
+ // For now we'll pick the default that the user would get without changing
+ // any prefs.
+ static AtomicString timesStr("Times New Roman");
+ static AtomicString courierStr("Courier New");
+ static AtomicString arialStr("Arial");
+
+ AtomicString& fontStr = timesStr;
+ if (generic == FontDescription::SansSerifFamily)
+ fontStr = arialStr;
+ else if (generic == FontDescription::MonospaceFamily)
+ fontStr = courierStr;
+
+ SimpleFontData* simpleFont = getCachedFontData(description, fontStr);
+ if (simpleFont)
+ return simpleFont;
+
+ // Fall back to system fonts as Win Safari does because this function must
+ // return a valid font. Once we find a valid system font, we save its name
+ // to a static variable and use it to prevent trying system fonts again.
+ static wchar_t fallbackFontName[LF_FACESIZE] = {0};
+ if (fallbackFontName[0])
+ return getCachedFontData(description, fallbackFontName);
+
+ // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available.
+ if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))) {
+ LOGFONT defaultGUILogFont;
+ GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont);
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, defaultGUILogFont, fallbackFontName))
+ return simpleFont;
+ }
+
+ // Fall back to Non-client metrics fonts.
+ NONCLIENTMETRICS nonClientMetrics = {0};
+ nonClientMetrics.cbSize = sizeof(nonClientMetrics);
+ if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) {
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfMessageFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfMenuFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfStatusFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfCaptionFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfSmCaptionFont, fallbackFontName))
+ return simpleFont;
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ HDC hdc = GetDC(0);
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ TraitsInFamilyProcData procData(familyName);
+ EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
+ copyToVector(procData.m_traitsMasks, traitsMasks);
+
+ ReleaseDC(0, hdc);
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ LOGFONT winfont = {0};
+ FillLogFont(fontDescription, &winfont);
+
+ // Windows will always give us a valid pointer here, even if the face name
+ // is non-existent. We have to double-check and see if the family name was
+ // really used.
+ String winName;
+ HFONT hfont = createFontIndirectAndGetWinName(family, &winfont, &winName);
+ if (!hfont)
+ return 0;
+
+ // FIXME: Do we need to use predefined fonts "guaranteed" to exist
+ // when we're running in layout-test mode?
+ if (!equalIgnoringCase(family, winName)) {
+ // For CJK fonts with both English and native names,
+ // GetTextFace returns a native name under the font's "locale"
+ // and an English name under other locales regardless of
+ // lfFaceName field of LOGFONT. As a result, we need to check
+ // if a font has an alternate name. If there is, we need to
+ // compare it with what's requested in the first place.
+ String altName;
+ if (!LookupAltName(family, altName) ||
+ !equalIgnoringCase(altName, winName)) {
+ DeleteObject(hfont);
+ return 0;
+ }
+ }
+
+ return new FontPlatformData(hfont,
+ fontDescription.computedPixelSize());
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
new file mode 100644
index 0000000..bd33927
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 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.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "ChromiumBridge.h"
+#include "Font.h"
+#include "FontDescription.h"
+#include "FontPlatformData.h"
+#include "Logging.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font,
+ const UChar* characters,
+ int length)
+{
+ String family = ChromiumBridge::getFontFamilyForCharacters(characters, length);
+ if (family.isEmpty())
+ return 0;
+
+ AtomicString atomicFamily(family);
+ return getCachedFontData(getCachedFontPlatformData(font.fontDescription(), atomicFamily, false));
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& description)
+{
+ static const AtomicString sansStr("Sans");
+ static const AtomicString serifStr("Serif");
+ static const AtomicString monospaceStr("Monospace");
+
+ FontPlatformData* fontPlatformData = 0;
+ switch (description.genericFamily()) {
+ case FontDescription::SerifFamily:
+ fontPlatformData = getCachedFontPlatformData(description, serifStr);
+ break;
+ case FontDescription::MonospaceFamily:
+ fontPlatformData = getCachedFontPlatformData(description, monospaceStr);
+ break;
+ case FontDescription::SansSerifFamily:
+ default:
+ fontPlatformData = getCachedFontPlatformData(description, sansStr);
+ break;
+ }
+
+ ASSERT(fontPlatformData);
+ return getCachedFontData(fontPlatformData);
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName,
+ Vector<unsigned>& traitsMasks)
+{
+ notImplemented();
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription,
+ const AtomicString& family)
+{
+ const char* name = 0;
+ CString s;
+
+ // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into
+ // the fallback name (like "monospace") that fontconfig understands.
+ if (!family.length() || family.startsWith("-webkit-")) {
+ static const struct {
+ FontDescription::GenericFamilyType mType;
+ const char* mName;
+ } fontDescriptions[] = {
+ { FontDescription::SerifFamily, "serif" },
+ { FontDescription::SansSerifFamily, "sans-serif" },
+ { FontDescription::MonospaceFamily, "monospace" },
+ { FontDescription::CursiveFamily, "cursive" },
+ { FontDescription::FantasyFamily, "fantasy" }
+ };
+
+ FontDescription::GenericFamilyType type = fontDescription.genericFamily();
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(fontDescriptions); i++) {
+ if (type == fontDescriptions[i].mType) {
+ name = fontDescriptions[i].mName;
+ break;
+ }
+ }
+ if (!name)
+ name = "";
+ } else {
+ // convert the name to utf8
+ s = family.string().utf8();
+ name = s.data();
+ }
+
+ int style = SkTypeface::kNormal;
+ if (fontDescription.weight() >= FontWeightBold)
+ style |= SkTypeface::kBold;
+ if (fontDescription.italic())
+ style |= SkTypeface::kItalic;
+
+ SkTypeface* tf = SkTypeface::CreateFromName(name, static_cast<SkTypeface::Style>(style));
+ if (!tf)
+ return 0;
+
+ FontPlatformData* result =
+ new FontPlatformData(tf,
+ name,
+ fontDescription.computedSize(),
+ (style & SkTypeface::kBold) && !tf->isBold(),
+ (style & SkTypeface::kItalic) && !tf->isItalic(),
+ fontDescription.orientation());
+ tf->unref();
+ return result;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
new file mode 100644
index 0000000..1a00833
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Inc.
+ * Copyright (c) 2006, 2007, 2008, 2009, 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "ChromiumBridge.h"
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "NotImplemented.h"
+#include "PlatformContextSkia.h"
+#include "SimpleFontData.h"
+#include "SkiaFontWin.h"
+#include "SkiaUtils.h"
+#include "TransparencyWin.h"
+#include "UniscribeHelperTextRun.h"
+
+#include "skia/ext/platform_canvas_win.h"
+#include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency.
+
+#include <windows.h>
+
+namespace WebCore {
+
+namespace {
+
+bool canvasHasMultipleLayers(const SkCanvas* canvas)
+{
+ SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false);
+ iter.next(); // There is always at least one layer.
+ return !iter.done(); // There is > 1 layer if the the iterator can stil advance.
+}
+
+class TransparencyAwareFontPainter {
+public:
+ TransparencyAwareFontPainter(GraphicsContext*, const FloatPoint&);
+ ~TransparencyAwareFontPainter();
+
+protected:
+ // Called by our subclass' constructor to initialize GDI if necessary. This
+ // is a separate function so it can be called after the subclass finishes
+ // construction (it calls virtual functions).
+ void init();
+
+ virtual IntRect estimateTextBounds() = 0;
+
+ // Use the context from the transparency helper when drawing with GDI. It
+ // may point to a temporary one.
+ GraphicsContext* m_graphicsContext;
+ PlatformGraphicsContext* m_platformContext;
+
+ FloatPoint m_point;
+
+ // Set when Windows can handle the type of drawing we're doing.
+ bool m_useGDI;
+
+ // These members are valid only when m_useGDI is set.
+ HDC m_hdc;
+ TransparencyWin m_transparency;
+
+private:
+ // Call when we're using GDI mode to initialize the TransparencyWin to help
+ // us draw GDI text.
+ void initializeForGDI();
+
+ bool m_createdTransparencyLayer; // We created a layer to give the font some alpha.
+};
+
+TransparencyAwareFontPainter::TransparencyAwareFontPainter(GraphicsContext* context,
+ const FloatPoint& point)
+ : m_graphicsContext(context)
+ , m_platformContext(context->platformContext())
+ , m_point(point)
+ , m_useGDI(windowsCanHandleTextDrawing(context))
+ , m_hdc(0)
+ , m_createdTransparencyLayer(false)
+{
+}
+
+void TransparencyAwareFontPainter::init()
+{
+ if (m_useGDI)
+ initializeForGDI();
+}
+
+void TransparencyAwareFontPainter::initializeForGDI()
+{
+ m_graphicsContext->save();
+ SkColor color = m_platformContext->effectiveFillColor();
+ // Used only when m_createdTransparencyLayer is true.
+ float layerAlpha = 0.0f;
+ if (SkColorGetA(color) != 0xFF) {
+ // When the font has some transparency, apply it by creating a new
+ // transparency layer with that opacity applied. We'll actually create
+ // a new transparency layer after we calculate the bounding box.
+ m_createdTransparencyLayer = true;
+ layerAlpha = SkColorGetA(color) / 255.0f;
+ // The color should be opaque now.
+ color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
+ }
+
+ TransparencyWin::LayerMode layerMode;
+ IntRect layerRect;
+ if (m_platformContext->isDrawingToImageBuffer()) {
+ // Assume if we're drawing to an image buffer that the background
+ // is not opaque and we have to undo ClearType. We may want to
+ // enhance this to actually check, since it will often be opaque
+ // and we could do ClearType in that case.
+ layerMode = TransparencyWin::TextComposite;
+ layerRect = estimateTextBounds();
+ m_graphicsContext->clip(layerRect);
+ if (m_createdTransparencyLayer)
+ m_graphicsContext->beginTransparencyLayer(layerAlpha);
+
+ // The transparency helper requires that we draw text in black in
+ // this mode and it will apply the color.
+ m_transparency.setTextCompositeColor(color);
+ color = SkColorSetRGB(0, 0, 0);
+ } else if (m_createdTransparencyLayer || canvasHasMultipleLayers(m_platformContext->canvas())) {
+ // When we're drawing a web page, we know the background is opaque,
+ // but if we're drawing to a layer, we still need extra work.
+ layerMode = TransparencyWin::OpaqueCompositeLayer;
+ layerRect = estimateTextBounds();
+ m_graphicsContext->clip(layerRect);
+ if (m_createdTransparencyLayer)
+ m_graphicsContext->beginTransparencyLayer(layerAlpha);
+ } else {
+ // Common case of drawing onto the bottom layer of a web page: we
+ // know everything is opaque so don't need to do anything special.
+ layerMode = TransparencyWin::NoLayer;
+ }
+
+ // Bug 26088 - init() might fail if layerRect is invalid. Given this, we
+ // need to be careful to check for null pointers everywhere after this call
+ m_transparency.init(m_graphicsContext, layerMode,
+ TransparencyWin::KeepTransform, layerRect);
+
+ // Set up the DC, using the one from the transparency helper.
+ if (m_transparency.platformContext()) {
+ m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint();
+ SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
+ SetBkMode(m_hdc, TRANSPARENT);
+ }
+}
+
+TransparencyAwareFontPainter::~TransparencyAwareFontPainter()
+{
+ if (!m_useGDI || !m_graphicsContext || !m_platformContext)
+ return; // Nothing to do.
+ m_transparency.composite();
+ if (m_createdTransparencyLayer)
+ m_graphicsContext->endTransparencyLayer();
+ m_graphicsContext->restore();
+ m_platformContext->canvas()->endPlatformPaint();
+}
+
+// Specialization for simple GlyphBuffer painting.
+class TransparencyAwareGlyphPainter : public TransparencyAwareFontPainter {
+ public:
+ TransparencyAwareGlyphPainter(GraphicsContext*,
+ const SimpleFontData*,
+ const GlyphBuffer&,
+ int from, int numGlyphs,
+ const FloatPoint&);
+ ~TransparencyAwareGlyphPainter();
+
+ // Draws the partial string of glyphs, starting at |startAdvance| to the
+ // left of m_point. We express it this way so that if we're using the Skia
+ // drawing path we can use floating-point positioning, even though we have
+ // to use integer positioning in the GDI path.
+ bool drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances, int startAdvance) const;
+
+ private:
+ virtual IntRect estimateTextBounds();
+
+ const SimpleFontData* m_font;
+ const GlyphBuffer& m_glyphBuffer;
+ int m_from;
+ int m_numGlyphs;
+
+ // When m_useGdi is set, this stores the previous HFONT selected into the
+ // m_hdc so we can restore it.
+ HGDIOBJ m_oldFont; // For restoring the DC to its original state.
+};
+
+TransparencyAwareGlyphPainter::TransparencyAwareGlyphPainter(
+ GraphicsContext* context,
+ const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs,
+ const FloatPoint& point)
+ : TransparencyAwareFontPainter(context, point)
+ , m_font(font)
+ , m_glyphBuffer(glyphBuffer)
+ , m_from(from)
+ , m_numGlyphs(numGlyphs)
+ , m_oldFont(0)
+{
+ init();
+
+ if (m_hdc)
+ m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
+}
+
+TransparencyAwareGlyphPainter::~TransparencyAwareGlyphPainter()
+{
+ if (m_useGDI && m_hdc)
+ ::SelectObject(m_hdc, m_oldFont);
+}
+
+
+// Estimates the bounding box of the given text. This is copied from
+// FontCGWin.cpp, it is possible, but a lot more work, to get the precide
+// bounds.
+IntRect TransparencyAwareGlyphPainter::estimateTextBounds()
+{
+ int totalWidth = 0;
+ for (int i = 0; i < m_numGlyphs; i++)
+ totalWidth += lroundf(m_glyphBuffer.advanceAt(m_from + i));
+
+ return IntRect(m_point.x() - (m_font->ascent() + m_font->descent()) / 2,
+ m_point.y() - m_font->ascent() - m_font->lineGap(),
+ totalWidth + m_font->ascent() + m_font->descent(),
+ m_font->lineSpacing());
+}
+
+bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ int startAdvance) const
+{
+ if (!m_useGDI) {
+ SkPoint origin = m_point;
+ origin.fX += startAdvance;
+ return paintSkiaText(m_graphicsContext, m_font->platformData().hfont(),
+ numGlyphs, glyphs, advances, 0, &origin);
+ }
+
+ if (!m_graphicsContext || !m_hdc)
+ return true;
+
+ // Windows' origin is the top-left of the bounding box, so we have
+ // to subtract off the font ascent to get it.
+ int x = lroundf(m_point.x() + startAdvance);
+ int y = lroundf(m_point.y() - m_font->ascent());
+
+ // If there is a non-blur shadow and both the fill color and shadow color
+ // are opaque, handle without skia.
+ FloatSize shadowOffset;
+ float shadowBlur;
+ Color shadowColor;
+ ColorSpace shadowColorSpace;
+ if (m_graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace)) {
+ // If there is a shadow and this code is reached, windowsCanHandleDrawTextShadow()
+ // will have already returned true during the ctor initiatization of m_useGDI
+ ASSERT(shadowColor.alpha() == 255);
+ ASSERT(m_graphicsContext->fillColor().alpha() == 255);
+ ASSERT(shadowBlur == 0);
+ COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue()));
+ COLORREF savedTextColor = GetTextColor(m_hdc);
+ SetTextColor(m_hdc, textColor);
+ ExtTextOut(m_hdc, x + shadowOffset.width(), y + shadowOffset.height(), ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
+ SetTextColor(m_hdc, savedTextColor);
+ }
+
+ return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
+}
+
+class TransparencyAwareUniscribePainter : public TransparencyAwareFontPainter {
+ public:
+ TransparencyAwareUniscribePainter(GraphicsContext*,
+ const Font*,
+ const TextRun&,
+ int from, int to,
+ const FloatPoint&);
+ ~TransparencyAwareUniscribePainter();
+
+ // Uniscibe will draw directly into our buffer, so we need to expose our DC.
+ HDC hdc() const { return m_hdc; }
+
+ private:
+ virtual IntRect estimateTextBounds();
+
+ const Font* m_font;
+ const TextRun& m_run;
+ int m_from;
+ int m_to;
+};
+
+TransparencyAwareUniscribePainter::TransparencyAwareUniscribePainter(
+ GraphicsContext* context,
+ const Font* font,
+ const TextRun& run,
+ int from, int to,
+ const FloatPoint& point)
+ : TransparencyAwareFontPainter(context, point)
+ , m_font(font)
+ , m_run(run)
+ , m_from(from)
+ , m_to(to)
+{
+ init();
+}
+
+TransparencyAwareUniscribePainter::~TransparencyAwareUniscribePainter()
+{
+}
+
+IntRect TransparencyAwareUniscribePainter::estimateTextBounds()
+{
+ // This case really really sucks. There is no convenient way to estimate
+ // the bounding box. So we run Uniscribe twice. If we find this happens a
+ // lot, the way to fix it is to make the extra layer after the
+ // UniscribeHelper has measured the text.
+ IntPoint intPoint(lroundf(m_point.x()),
+ lroundf(m_point.y()));
+
+ UniscribeHelperTextRun state(m_run, *m_font);
+ int left = lroundf(m_point.x()) + state.characterToX(m_from);
+ int right = lroundf(m_point.x()) + state.characterToX(m_to);
+
+ // Adjust for RTL script since we just want to know the text bounds.
+ if (left > right)
+ std::swap(left, right);
+
+ // This algorithm for estimating how much extra space we need (the text may
+ // go outside the selection rect) is based roughly on
+ // TransparencyAwareGlyphPainter::estimateTextBounds above.
+ return IntRect(left - (m_font->ascent() + m_font->descent()) / 2,
+ m_point.y() - m_font->ascent() - m_font->lineGap(),
+ (right - left) + m_font->ascent() + m_font->descent(),
+ m_font->lineSpacing());
+}
+
+} // namespace
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext,
+ const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer,
+ int from,
+ int numGlyphs,
+ const FloatPoint& point) const
+{
+ graphicsContext->platformContext()->prepareForSoftwareDraw();
+
+ SkColor color = graphicsContext->platformContext()->effectiveFillColor();
+ unsigned char alpha = SkColorGetA(color);
+ // Skip 100% transparent text; no need to draw anything.
+ if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
+ return;
+
+ TransparencyAwareGlyphPainter painter(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
+
+ // We draw the glyphs in chunks to avoid having to do a heap allocation for
+ // the arrays of characters and advances. Since ExtTextOut is the
+ // lowest-level text output function on Windows, there should be little
+ // penalty for splitting up the text. On the other hand, the buffer cannot
+ // be bigger than 4094 or the function will fail.
+ const int kMaxBufferLength = 256;
+ Vector<WORD, kMaxBufferLength> glyphs;
+ Vector<int, kMaxBufferLength> advances;
+ int glyphIndex = 0; // The starting glyph of the current chunk.
+ int curAdvance = 0; // How far from the left the current chunk is.
+ while (glyphIndex < numGlyphs) {
+ // How many chars will be in this chunk?
+ int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
+ glyphs.resize(curLen);
+ advances.resize(curLen);
+
+ int curWidth = 0;
+ for (int i = 0; i < curLen; ++i, ++glyphIndex) {
+ glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
+ advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex));
+
+ // Bug 26088 - very large positive or negative runs can fail to
+ // render so we clamp the size here. In the specs, negative
+ // letter-spacing is implementation-defined, so this should be
+ // fine, and it matches Safari's implementation. The call actually
+ // seems to crash if kMaxNegativeRun is set to somewhere around
+ // -32830, so we give ourselves a little breathing room.
+ const int maxNegativeRun = -32768;
+ const int maxPositiveRun = 32768;
+ if ((curWidth + advances[i] < maxNegativeRun) || (curWidth + advances[i] > maxPositiveRun))
+ advances[i] = 0;
+ curWidth += advances[i];
+ }
+
+ // Actually draw the glyphs (with retry on failure).
+ bool success = false;
+ for (int executions = 0; executions < 2; ++executions) {
+ success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], curAdvance);
+ if (!success && executions == 0) {
+ // Ask the browser to load the font for us and retry.
+ ChromiumBridge::ensureFontLoaded(font->platformData().hfont());
+ continue;
+ }
+ break;
+ }
+
+ if (!success)
+ LOG_ERROR("Unable to draw the glyphs after second attempt");
+
+ curAdvance += curWidth;
+ }
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run,
+ const FloatPoint& point,
+ int h,
+ int from,
+ int to) const
+{
+ UniscribeHelperTextRun state(run, *this);
+ float left = static_cast<float>(point.x() + state.characterToX(from));
+ float right = static_cast<float>(point.x() + state.characterToX(to));
+
+ // If the text is RTL, left will actually be after right.
+ if (left < right)
+ return FloatRect(left, point.y(),
+ right - left, static_cast<float>(h));
+
+ return FloatRect(right, point.y(),
+ left - right, static_cast<float>(h));
+}
+
+void Font::drawComplexText(GraphicsContext* graphicsContext,
+ const TextRun& run,
+ const FloatPoint& point,
+ int from,
+ int to) const
+{
+ PlatformGraphicsContext* context = graphicsContext->platformContext();
+ UniscribeHelperTextRun state(run, *this);
+
+ SkColor color = graphicsContext->platformContext()->effectiveFillColor();
+ unsigned char alpha = SkColorGetA(color);
+ // Skip 100% transparent text; no need to draw anything.
+ if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
+ return;
+
+ TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point);
+
+ HDC hdc = painter.hdc();
+ if (windowsCanHandleTextDrawing(graphicsContext) && !hdc)
+ return;
+
+ // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
+ // Enforce non-transparent color.
+ color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
+ if (hdc) {
+ SetTextColor(hdc, skia::SkColorToCOLORREF(color));
+ SetBkMode(hdc, TRANSPARENT);
+ }
+
+ // If there is a non-blur shadow and both the fill color and shadow color
+ // are opaque, handle without skia.
+ FloatSize shadowOffset;
+ float shadowBlur;
+ Color shadowColor;
+ ColorSpace shadowColorSpace;
+ if (graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace) && windowsCanHandleDrawTextShadow(graphicsContext)) {
+ COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue()));
+ COLORREF savedTextColor = GetTextColor(hdc);
+ SetTextColor(hdc, textColor);
+ state.draw(graphicsContext, hdc, static_cast<int>(point.x()) + shadowOffset.width(),
+ static_cast<int>(point.y() - ascent()) + shadowOffset.height(), from, to);
+ SetTextColor(hdc, savedTextColor);
+ }
+
+ // Uniscribe counts the coordinates from the upper left, while WebKit uses
+ // the baseline, so we have to subtract off the ascent.
+ state.draw(graphicsContext, hdc, static_cast<int>(point.x()),
+ static_cast<int>(point.y() - ascent()), from, to);
+
+ context->canvas()->endPlatformPaint();
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
+{
+ UniscribeHelperTextRun state(run, *this);
+ return static_cast<float>(state.width());
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
+ bool includePartialGlyphs) const
+{
+ // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
+ // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
+ int x = static_cast<int>(xFloat);
+
+ // Mac code ignores includePartialGlyphs, and they don't know what it's
+ // supposed to do, so we just ignore it as well.
+ UniscribeHelperTextRun state(run, *this);
+ int charIndex = state.xToCharacter(x);
+
+ // XToCharacter will return -1 if the position is before the first
+ // character (we get called like this sometimes).
+ if (charIndex < 0)
+ charIndex = 0;
+ return charIndex;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/FontLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontLinux.cpp
new file mode 100644
index 0000000..b256e70
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2007, 2008, 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "ComplexTextControllerLinux.h"
+#include "FloatRect.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "HarfbuzzSkia.h"
+#include "NotImplemented.h"
+#include "PlatformContextSkia.h"
+#include "SimpleFontData.h"
+
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkTemplates.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+static bool isCanvasMultiLayered(SkCanvas* canvas)
+{
+ SkCanvas::LayerIter layerIterator(canvas, false);
+ layerIterator.next();
+ return !layerIterator.done();
+}
+
+static void adjustTextRenderMode(SkPaint* paint, PlatformContextSkia* skiaContext)
+{
+ // Our layers only have a single alpha channel. This means that subpixel
+ // rendered text cannot be compositied correctly when the layer is
+ // collapsed. Therefore, subpixel text is disabled when we are drawing
+ // onto a layer or when the compositor is being used.
+ if (isCanvasMultiLayered(skiaContext->canvas()) || skiaContext->isDrawingToImageBuffer())
+ paint->setLCDRenderText(false);
+}
+
+void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
+ const FloatPoint& point) const {
+ SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
+
+ const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
+ SkScalar x = SkFloatToScalar(point.x());
+ SkScalar y = SkFloatToScalar(point.y());
+
+ // FIXME: text rendering speed:
+ // Android has code in their WebCore fork to special case when the
+ // GlyphBuffer has no advances other than the defaults. In that case the
+ // text drawing can proceed faster. However, it's unclear when those
+ // patches may be upstreamed to WebKit so we always use the slower path
+ // here.
+ const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
+ SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs);
+ SkPoint* pos = storage.get();
+ SkPoint* vPosBegin = storage2.get();
+ SkPoint* vPosEnd = storage3.get();
+
+ bool isVertical = font->orientation() == Vertical;
+ for (int i = 0; i < numGlyphs; i++) {
+ SkScalar myWidth = SkFloatToScalar(adv[i].width());
+ pos[i].set(x, y);
+ if (isVertical) {
+ vPosBegin[i].set(x + myWidth, y);
+ vPosEnd[i].set(x + myWidth, y - myWidth);
+ }
+ x += myWidth;
+ y += SkFloatToScalar(adv[i].height());
+ }
+
+ gc->platformContext()->prepareForSoftwareDraw();
+
+ SkCanvas* canvas = gc->platformContext()->canvas();
+ TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode();
+
+ // We draw text up to two times (once for fill, once for stroke).
+ if (textMode & TextModeFill) {
+ SkPaint paint;
+ gc->platformContext()->setupPaintForFilling(&paint);
+ font->platformData().setupPaint(&paint);
+ adjustTextRenderMode(&paint, gc->platformContext());
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setColor(gc->fillColor().rgb());
+
+ if (isVertical) {
+ SkPath path;
+ for (int i = 0; i < numGlyphs; ++i) {
+ path.reset();
+ path.moveTo(vPosBegin[i]);
+ path.lineTo(vPosEnd[i]);
+ canvas->drawTextOnPath(glyphs + i, 2, path, 0, paint);
+ }
+ } else
+ canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+ }
+
+ if ((textMode & TextModeStroke)
+ && gc->platformContext()->getStrokeStyle() != NoStroke
+ && gc->platformContext()->getStrokeThickness() > 0) {
+
+ SkPaint paint;
+ gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
+ font->platformData().setupPaint(&paint);
+ adjustTextRenderMode(&paint, gc->platformContext());
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setColor(gc->strokeColor().rgb());
+
+ if (textMode & TextModeFill) {
+ // If we also filled, we don't want to draw shadows twice.
+ // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
+ SkSafeUnref(paint.setLooper(0));
+ }
+
+ if (isVertical) {
+ SkPath path;
+ for (int i = 0; i < numGlyphs; ++i) {
+ path.reset();
+ path.moveTo(vPosBegin[i]);
+ path.lineTo(vPosEnd[i]);
+ canvas->drawTextOnPath(glyphs + i, 2, path, 0, paint);
+ }
+ } else
+ canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+ }
+}
+
+// Harfbuzz uses 26.6 fixed point values for pixel offsets. However, we don't
+// handle subpixel positioning so this function is used to truncate Harfbuzz
+// values to a number of pixels.
+static int truncateFixedPointToInteger(HB_Fixed value)
+{
+ return value >> 6;
+}
+
+static void setupForTextPainting(SkPaint* paint, SkColor color)
+{
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint->setColor(color);
+}
+
+void Font::drawComplexText(GraphicsContext* gc, const TextRun& run,
+ const FloatPoint& point, int from, int to) const
+{
+ if (!run.length())
+ return;
+
+ SkCanvas* canvas = gc->platformContext()->canvas();
+ TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode();
+ bool fill = textMode & TextModeFill;
+ bool stroke = (textMode & TextModeStroke)
+ && gc->platformContext()->getStrokeStyle() != NoStroke
+ && gc->platformContext()->getStrokeThickness() > 0;
+
+ if (!fill && !stroke)
+ return;
+
+ SkPaint strokePaint, fillPaint;
+ if (fill) {
+ gc->platformContext()->setupPaintForFilling(&fillPaint);
+ setupForTextPainting(&fillPaint, gc->fillColor().rgb());
+ }
+ if (stroke) {
+ gc->platformContext()->setupPaintForStroking(&strokePaint, 0, 0);
+ setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
+ }
+
+ ComplexTextController controller(run, point.x(), this);
+ controller.setWordSpacingAdjustment(wordSpacing());
+ controller.setLetterSpacingAdjustment(letterSpacing());
+ controller.setPadding(run.padding());
+
+ while (controller.nextScriptRun()) {
+ if (fill) {
+ controller.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
+ adjustTextRenderMode(&fillPaint, gc->platformContext());
+ canvas->drawPosTextH(controller.glyphs(), controller.length() << 1, controller.xPositions(), point.y(), fillPaint);
+ }
+
+ if (stroke) {
+ controller.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
+ adjustTextRenderMode(&strokePaint, gc->platformContext());
+ canvas->drawPosTextH(controller.glyphs(), controller.length() << 1, controller.xPositions(), point.y(), strokePaint);
+ }
+ }
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
+{
+ ComplexTextController controller(run, 0, this);
+ controller.setWordSpacingAdjustment(wordSpacing());
+ controller.setLetterSpacingAdjustment(letterSpacing());
+ return controller.widthOfFullRun();
+}
+
+static int glyphIndexForXPositionInScriptRun(const ComplexTextController& controller, int x)
+{
+ const HB_Fixed* advances = controller.advances();
+ int letterSpacing = controller.letterSpacing();
+ int glyphIndex;
+ if (controller.rtl()) {
+ for (glyphIndex = controller.length() - 1; glyphIndex >= 0; --glyphIndex) {
+ // When iterating LTR over RTL text, we must include the whitespace
+ // _before_ the glyph, so no + 1 here.
+ if (x < (static_cast<int>(controller.length()) - glyphIndex) * letterSpacing + truncateFixedPointToInteger(advances[glyphIndex]))
+ break;
+ x -= truncateFixedPointToInteger(advances[glyphIndex]);
+ }
+ } else {
+ for (glyphIndex = 0; static_cast<unsigned>(glyphIndex) < controller.length(); ++glyphIndex) {
+ if (x < (glyphIndex * letterSpacing + truncateFixedPointToInteger(advances[glyphIndex])))
+ break;
+ x -= truncateFixedPointToInteger(advances[glyphIndex]);
+ }
+ }
+
+ return glyphIndex;
+}
+
+// Return the code point index for the given |x| offset into the text run.
+int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
+ bool includePartialGlyphs) const
+{
+ // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
+ // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
+ int x = static_cast<int>(xFloat);
+
+ // (Mac code ignores includePartialGlyphs, and they don't know what it's
+ // supposed to do, so we just ignore it as well.)
+ ComplexTextController controller(run, 0, this);
+ controller.setWordSpacingAdjustment(wordSpacing());
+ controller.setLetterSpacingAdjustment(letterSpacing());
+
+ // If this is RTL text, the first glyph from the left is actually the last
+ // code point. So we need to know how many code points there are total in
+ // order to subtract. This is different from the length of the TextRun
+ // because UTF-16 surrogate pairs are a single code point, but 32-bits long.
+ // In LTR we leave this as 0 so that we get the correct value for
+ // |basePosition|, below.
+ unsigned totalCodePoints = 0;
+ if (controller.rtl()) {
+ ssize_t offset = 0;
+ while (offset < run.length()) {
+ utf16_to_code_point(run.characters(), run.length(), &offset);
+ totalCodePoints++;
+ }
+ }
+
+ unsigned basePosition = totalCodePoints;
+
+ // For RTL:
+ // code-point order: abcd efg hijkl
+ // on screen: lkjih gfe dcba
+ // ^ ^
+ // | |
+ // basePosition--| |
+ // totalCodePoints----|
+ // Since basePosition is currently the total number of code-points, the
+ // first thing we do is decrement it so that it's pointing to the start of
+ // the current script-run.
+ //
+ // For LTR, basePosition is zero so it already points to the start of the
+ // first script run.
+ while (controller.nextScriptRun()) {
+ if (controller.rtl())
+ basePosition -= controller.numCodePoints();
+
+ if (x >= 0 && static_cast<unsigned>(x) < controller.width()) {
+ // The x value in question is within this script run. We consider
+ // each glyph in presentation order and stop when we find the one
+ // covering this position.
+ const int glyphIndex = glyphIndexForXPositionInScriptRun(controller, x);
+
+ // Now that we have a glyph index, we have to turn that into a
+ // code-point index. Because of ligatures, several code-points may
+ // have gone into a single glyph. We iterate over the clusters log
+ // and find the first code-point which contributed to the glyph.
+
+ // Some shapers (i.e. Khmer) will produce cluster logs which report
+ // that /no/ code points contributed to certain glyphs. Because of
+ // this, we take any code point which contributed to the glyph in
+ // question, or any subsequent glyph. If we run off the end, then
+ // we take the last code point.
+ const unsigned short* log = controller.logClusters();
+ for (unsigned j = 0; j < controller.numCodePoints(); ++j) {
+ if (log[j] >= glyphIndex)
+ return basePosition + j;
+ }
+
+ return basePosition + controller.numCodePoints() - 1;
+ }
+
+ x -= controller.width();
+
+ if (!controller.rtl())
+ basePosition += controller.numCodePoints();
+ }
+
+ return basePosition;
+}
+
+// Return the rectangle for selecting the given range of code-points in the TextRun.
+FloatRect Font::selectionRectForComplexText(const TextRun& run,
+ const FloatPoint& point, int height,
+ int from, int to) const
+{
+ int fromX = -1, toX = -1, fromAdvance = -1, toAdvance = -1;
+ ComplexTextController controller(run, 0, this);
+ controller.setWordSpacingAdjustment(wordSpacing());
+ controller.setLetterSpacingAdjustment(letterSpacing());
+
+ // Base will point to the x offset for the current script run. Note that, in
+ // the LTR case, width will be 0.
+ int base = controller.rtl() ? controller.widthOfFullRun() : 0;
+ const int leftEdge = base;
+
+ // We want to enumerate the script runs in code point order in the following
+ // code. This call also resets |controller|.
+ controller.setBackwardsIteration(false);
+
+ while (controller.nextScriptRun() && (fromX == -1 || toX == -1)) {
+ // ComplexTextController will helpfully accululate the x offsets for different
+ // script runs for us. For this code, however, we always want the x offsets
+ // to start from zero so we call this before each script run.
+ controller.setXOffsetToZero();
+
+ if (controller.rtl())
+ base -= controller.width();
+
+ if (fromX == -1 && from >= 0 && static_cast<unsigned>(from) < controller.numCodePoints()) {
+ // |from| is within this script run. So we index the clusters log to
+ // find which glyph this code-point contributed to and find its x
+ // position.
+ int glyph = controller.logClusters()[from];
+ fromX = base + controller.xPositions()[glyph];
+ fromAdvance = controller.advances()[glyph];
+ } else
+ from -= controller.numCodePoints();
+
+ if (toX == -1 && to >= 0 && static_cast<unsigned>(to) < controller.numCodePoints()) {
+ int glyph = controller.logClusters()[to];
+ toX = base + controller.xPositions()[glyph];
+ toAdvance = controller.advances()[glyph];
+ } else
+ to -= controller.numCodePoints();
+
+ if (!controller.rtl())
+ base += controller.width();
+ }
+
+ // The position in question might be just after the text.
+ const int rightEdge = base;
+ if (fromX == -1 && !from)
+ fromX = leftEdge;
+ else if (controller.rtl())
+ fromX += truncateFixedPointToInteger(fromAdvance);
+
+ if (toX == -1 && !to)
+ toX = rightEdge;
+
+ ASSERT(fromX != -1 && toX != -1);
+
+ if (fromX < toX)
+ return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
+
+ return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformData.h b/Source/WebCore/platform/graphics/chromium/FontPlatformData.h
new file mode 100644
index 0000000..d8ce3e2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontPlatformData.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2007, 2008, 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 FontPlatformData_h
+#define FontPlatformData_h
+
+#if OS(WINDOWS)
+#include "FontPlatformDataChromiumWin.h"
+#elif OS(LINUX) || OS(FREEBSD)
+#include "FontPlatformDataLinux.h"
+#endif
+
+#endif // FontPlatformData_h
diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
new file mode 100644
index 0000000..d6c83ec
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Inc.
+ * Copyright (c) 2006, 2007, 2008, 2009, 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.
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include <windows.h>
+#include <objidl.h>
+#include <mlang.h>
+
+#include "ChromiumBridge.h"
+#include "SkiaFontWin.h"
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_font(hashTableDeletedFontValue())
+ , m_size(-1)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+FontPlatformData::FontPlatformData()
+ : m_font(0)
+ , m_size(0)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+FontPlatformData::FontPlatformData(HFONT font, float size)
+ : m_font(RefCountedHFONT::create(font))
+ , m_size(size)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+ : m_font(0)
+ , m_size(size)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& data)
+ : m_font(data.m_font)
+ , m_size(data.m_size)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data)
+{
+ if (this != &data) {
+ m_font = data.m_font;
+ m_size = data.m_size;
+
+ // The following fields will get re-computed if necessary.
+ ScriptFreeCache(&m_scriptCache);
+ m_scriptCache = 0;
+
+ delete m_scriptFontProperties;
+ m_scriptFontProperties = 0;
+ }
+ return *this;
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ ScriptFreeCache(&m_scriptCache);
+ m_scriptCache = 0;
+
+ delete m_scriptFontProperties;
+ m_scriptFontProperties = 0;
+}
+
+FontPlatformData::RefCountedHFONT::~RefCountedHFONT()
+{
+ if (m_hfont != reinterpret_cast<HFONT>(-1)) {
+ SkiaWinOutlineCache::removePathsForFont(m_hfont);
+ DeleteObject(m_hfont);
+ }
+}
+
+FontPlatformData::RefCountedHFONT* FontPlatformData::hashTableDeletedFontValue()
+{
+ static RefPtr<RefCountedHFONT> deletedValue =
+ RefCountedHFONT::create(reinterpret_cast<HFONT>(-1));
+ return deletedValue.get();
+}
+
+SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
+{
+ if (!m_scriptFontProperties) {
+ m_scriptFontProperties = new SCRIPT_FONTPROPERTIES;
+ memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES));
+ m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
+ HRESULT result = ScriptGetFontProperties(0, scriptCache(),
+ m_scriptFontProperties);
+ if (result == E_PENDING) {
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, hfont());
+ HRESULT hr = ScriptGetFontProperties(dc, scriptCache(),
+ m_scriptFontProperties);
+ if (S_OK != hr) {
+ if (ChromiumBridge::ensureFontLoaded(hfont())) {
+ // FIXME: Handle gracefully the error if this call also fails.
+ hr = ScriptGetFontProperties(dc, scriptCache(),
+ m_scriptFontProperties);
+ if (S_OK != hr) {
+ LOG_ERROR("Unable to get the font properties after second attempt");
+ }
+ }
+ }
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+ }
+ }
+ return m_scriptFontProperties;
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h b/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
new file mode 100644
index 0000000..b6ebb2e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Inc.
+ * Copyright (c) 2006, 2007, 2008, 2009, 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 FontPlatformDataChromiumWin_h
+#define FontPlatformDataChromiumWin_h
+
+#include "config.h"
+
+#include "FontOrientation.h"
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/StringImpl.h>
+
+#include <usp10.h>
+
+typedef struct HFONT__ *HFONT;
+
+namespace WebCore {
+
+class FontDescription;
+
+class FontPlatformData {
+public:
+ // Used for deleted values in the font cache's hash tables. The hash table
+ // will create us with this structure, and it will compare other values
+ // to this "Deleted" one. It expects the Deleted one to be differentiable
+ // from the NULL one (created with the empty constructor), so we can't just
+ // set everything to NULL.
+ FontPlatformData(WTF::HashTableDeletedValueType);
+ FontPlatformData();
+ FontPlatformData(HFONT, float size);
+ FontPlatformData(float size, bool bold, bool oblique);
+ FontPlatformData(const FontPlatformData&);
+
+ FontPlatformData& operator=(const FontPlatformData&);
+
+ bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); }
+
+ ~FontPlatformData();
+
+ HFONT hfont() const { return m_font ? m_font->hfont() : 0; }
+ float size() const { return m_size; }
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+ unsigned hash() const
+ {
+ return m_font ? m_font->hash() : NULL;
+ }
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ return m_font == other.m_font && m_size == other.m_size;
+ }
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+ SCRIPT_FONTPROPERTIES* scriptFontProperties() const;
+ SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; }
+
+private:
+ // We refcount the internal HFONT so that FontPlatformData can be
+ // efficiently copied. WebKit depends on being able to copy it, and we
+ // don't really want to re-create the HFONT.
+ class RefCountedHFONT : public RefCounted<RefCountedHFONT> {
+ public:
+ static PassRefPtr<RefCountedHFONT> create(HFONT hfont)
+ {
+ return adoptRef(new RefCountedHFONT(hfont));
+ }
+
+ ~RefCountedHFONT();
+
+ HFONT hfont() const { return m_hfont; }
+ unsigned hash() const
+ {
+ return WTF::StringHasher::createBlobHash<sizeof(HFONT)>(&m_hfont);
+ }
+
+ bool operator==(const RefCountedHFONT& other) const
+ {
+ return m_hfont == other.m_hfont;
+ }
+
+ private:
+ // The create() function assumes there is already a refcount of one
+ // so it can do adoptRef.
+ RefCountedHFONT(HFONT hfont) : m_hfont(hfont)
+ {
+ }
+
+ HFONT m_hfont;
+ };
+
+ static RefCountedHFONT* hashTableDeletedFontValue();
+
+ RefPtr<RefCountedHFONT> m_font;
+ float m_size; // Point size of the font in pixels.
+
+ mutable SCRIPT_CACHE m_scriptCache;
+ mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties;
+};
+
+} // WebCore
+
+#endif // FontPlatformDataChromiumWin_h
diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
new file mode 100644
index 0000000..42942cc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 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.
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "ChromiumBridge.h"
+#include "HarfbuzzSkia.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+
+#include <wtf/text/StringImpl.h>
+
+namespace WebCore {
+
+static SkPaint::Hinting skiaHinting = SkPaint::kNormal_Hinting;
+static bool isSkiaAntiAlias = true;
+static bool isSkiaSubpixelGlyphs = false;
+
+void FontPlatformData::setHinting(SkPaint::Hinting hinting)
+{
+ skiaHinting = hinting;
+}
+
+void FontPlatformData::setAntiAlias(bool isAntiAlias)
+{
+ isSkiaAntiAlias = isAntiAlias;
+}
+
+void FontPlatformData::setSubpixelGlyphs(bool isSubpixelGlyphs)
+{
+ isSkiaSubpixelGlyphs = isSubpixelGlyphs;
+}
+
+FontPlatformData::RefCountedHarfbuzzFace::~RefCountedHarfbuzzFace()
+{
+ HB_FreeFace(m_harfbuzzFace);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& src)
+ : m_typeface(src.m_typeface)
+ , m_family(src.m_family)
+ , m_textSize(src.m_textSize)
+ , m_fakeBold(src.m_fakeBold)
+ , m_fakeItalic(src.m_fakeItalic)
+ , m_orientation(src.m_orientation)
+ , m_style(src.m_style)
+ , m_harfbuzzFace(src.m_harfbuzzFace)
+{
+ SkSafeRef(m_typeface);
+}
+
+FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation)
+ : m_typeface(tf)
+ , m_family(family)
+ , m_textSize(textSize)
+ , m_fakeBold(fakeBold)
+ , m_fakeItalic(fakeItalic)
+ , m_orientation(orientation)
+{
+ SkSafeRef(m_typeface);
+ querySystemForRenderStyle();
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
+ : m_typeface(src.m_typeface)
+ , m_family(src.m_family)
+ , m_textSize(textSize)
+ , m_fakeBold(src.m_fakeBold)
+ , m_fakeItalic(src.m_fakeItalic)
+ , m_harfbuzzFace(src.m_harfbuzzFace)
+{
+ SkSafeRef(m_typeface);
+ querySystemForRenderStyle();
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ SkSafeUnref(m_typeface);
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src)
+{
+ SkRefCnt_SafeAssign(m_typeface, src.m_typeface);
+
+ m_family = src.m_family;
+ m_textSize = src.m_textSize;
+ m_fakeBold = src.m_fakeBold;
+ m_fakeItalic = src.m_fakeItalic;
+ m_harfbuzzFace = src.m_harfbuzzFace;
+ m_orientation = src.m_orientation;
+ m_style = src.m_style;
+
+ return *this;
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+void FontPlatformData::setupPaint(SkPaint* paint) const
+{
+ const float ts = m_textSize >= 0 ? m_textSize : 12;
+
+ paint->setAntiAlias(m_style.useAntiAlias == FontRenderStyle::NoPreference ? isSkiaAntiAlias : m_style.useAntiAlias);
+ switch (m_style.useHinting) {
+ case FontRenderStyle::NoPreference:
+ paint->setHinting(skiaHinting);
+ break;
+ case 0:
+ paint->setHinting(SkPaint::kNo_Hinting);
+ break;
+ default:
+ paint->setHinting(static_cast<SkPaint::Hinting>(m_style.hintStyle));
+ break;
+ }
+
+ paint->setEmbeddedBitmapText(m_style.useBitmaps);
+ paint->setTextSize(SkFloatToScalar(ts));
+ paint->setTypeface(m_typeface);
+ paint->setFakeBoldText(m_fakeBold);
+ paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);
+ paint->setAutohinted(m_style.useAutoHint);
+
+ if (m_style.useAntiAlias == 1 || (m_style.useAntiAlias == FontRenderStyle::NoPreference && isSkiaAntiAlias))
+ paint->setLCDRenderText(m_style.useSubpixel == FontRenderStyle::NoPreference ? isSkiaSubpixelGlyphs : m_style.useSubpixel);
+}
+
+SkFontID FontPlatformData::uniqueID() const
+{
+ return m_typeface->uniqueID();
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& a) const
+{
+ // If either of the typeface pointers are invalid (either NULL or the
+ // special deleted value) then we test for pointer equality. Otherwise, we
+ // call SkTypeface::Equal on the valid pointers.
+ bool typefacesEqual;
+ if (m_typeface == hashTableDeletedFontValue()
+ || a.m_typeface == hashTableDeletedFontValue()
+ || !m_typeface
+ || !a.m_typeface)
+ typefacesEqual = m_typeface == a.m_typeface;
+ else
+ typefacesEqual = SkTypeface::Equal(m_typeface, a.m_typeface);
+
+ return typefacesEqual
+ && m_textSize == a.m_textSize
+ && m_fakeBold == a.m_fakeBold
+ && m_fakeItalic == a.m_fakeItalic
+ && m_orientation == a.m_orientation
+ && m_style == a.m_style;
+}
+
+unsigned FontPlatformData::hash() const
+{
+ unsigned h = SkTypeface::UniqueID(m_typeface);
+ h ^= 0x01010101 * ((static_cast<int>(m_orientation) << 2) | (static_cast<int>(m_fakeBold) << 1) | static_cast<int>(m_fakeItalic));
+
+ // This memcpy is to avoid a reinterpret_cast that breaks strict-aliasing
+ // rules. Memcpy is generally optimized enough so that performance doesn't
+ // matter here.
+ uint32_t textSizeBytes;
+ memcpy(&textSizeBytes, &m_textSize, sizeof(uint32_t));
+ h ^= textSizeBytes;
+
+ return h;
+}
+
+bool FontPlatformData::isFixedPitch() const
+{
+ notImplemented();
+ return false;
+}
+
+HB_FaceRec_* FontPlatformData::harfbuzzFace() const
+{
+ if (!m_harfbuzzFace)
+ m_harfbuzzFace = RefCountedHarfbuzzFace::create(HB_NewFace(const_cast<FontPlatformData*>(this), harfbuzzSkiaGetTable));
+
+ return m_harfbuzzFace->face();
+}
+
+void FontPlatformData::querySystemForRenderStyle()
+{
+ if (!m_family.length()) {
+ // We don't have a family for this. Probably because it's a webfont. We
+ // set all the values to 'no preference' and take the defaults passed
+ // in from XSETTINGS.
+ m_style.useBitmaps = FontRenderStyle::NoPreference;
+ m_style.useAutoHint = FontRenderStyle::NoPreference;
+ m_style.useHinting = FontRenderStyle::NoPreference;
+ m_style.useAntiAlias = FontRenderStyle::NoPreference;
+ m_style.useSubpixel = FontRenderStyle::NoPreference;
+ return;
+ }
+
+ ChromiumBridge::getRenderStyleForStrike(m_family.data(), (((int)m_textSize) << 2) | (m_typeface->style() & 3), &m_style);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
new file mode 100644
index 0000000..43771d7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 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 FontPlatformDataLinux_h
+#define FontPlatformDataLinux_h
+
+#include "FontOrientation.h"
+#include "FontRenderStyle.h"
+#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringImpl.h>
+#include <SkPaint.h>
+
+class SkTypeface;
+typedef uint32_t SkFontID;
+
+struct HB_FaceRec_;
+
+namespace WebCore {
+
+class FontDescription;
+
+// -----------------------------------------------------------------------------
+// FontPlatformData is the handle which WebKit has on a specific face. A face
+// is the tuple of (font, size, ...etc). Here we are just wrapping a Skia
+// SkTypeface pointer and dealing with the reference counting etc.
+// -----------------------------------------------------------------------------
+class FontPlatformData {
+public:
+ // Used for deleted values in the font cache's hash tables. The hash table
+ // will create us with this structure, and it will compare other values
+ // to this "Deleted" one. It expects the Deleted one to be differentiable
+ // from the NULL one (created with the empty constructor), so we can't just
+ // set everything to NULL.
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_typeface(hashTableDeletedFontValue())
+ , m_textSize(0)
+ , m_fakeBold(false)
+ , m_fakeItalic(false)
+ { }
+
+ FontPlatformData()
+ : m_typeface(0)
+ , m_textSize(0)
+ , m_fakeBold(false)
+ , m_fakeItalic(false)
+ , m_orientation(Horizontal)
+ { }
+
+ FontPlatformData(float textSize, bool fakeBold, bool fakeItalic)
+ : m_typeface(0)
+ , m_textSize(textSize)
+ , m_fakeBold(fakeBold)
+ , m_fakeItalic(fakeItalic)
+ , m_orientation(Horizontal)
+ { }
+
+ FontPlatformData(const FontPlatformData&);
+ FontPlatformData(SkTypeface*, const char* name, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation = Horizontal);
+ FontPlatformData(const FontPlatformData& src, float textSize);
+ ~FontPlatformData();
+
+ // -------------------------------------------------------------------------
+ // Return true iff this font is monospaced (i.e. every glyph has an equal x
+ // advance)
+ // -------------------------------------------------------------------------
+ bool isFixedPitch() const;
+
+ // -------------------------------------------------------------------------
+ // Setup a Skia painting context to use this font.
+ // -------------------------------------------------------------------------
+ void setupPaint(SkPaint*) const;
+
+ // -------------------------------------------------------------------------
+ // Return Skia's unique id for this font. This encodes both the style and
+ // the font's file name so refers to a single face.
+ // -------------------------------------------------------------------------
+ SkFontID uniqueID() const;
+
+ unsigned hash() const;
+ float size() const { return m_textSize; }
+
+ FontOrientation orientation() const { return m_orientation; }
+
+ bool operator==(const FontPlatformData&) const;
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool isHashTableDeletedValue() const { return m_typeface == hashTableDeletedFontValue(); }
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+ HB_FaceRec_* harfbuzzFace() const;
+
+ // -------------------------------------------------------------------------
+ // Global font preferences...
+
+ static void setHinting(SkPaint::Hinting);
+ static void setAntiAlias(bool on);
+ static void setSubpixelGlyphs(bool on);
+
+private:
+ class RefCountedHarfbuzzFace : public RefCounted<RefCountedHarfbuzzFace> {
+ public:
+ static PassRefPtr<RefCountedHarfbuzzFace> create(HB_FaceRec_* harfbuzzFace)
+ {
+ return adoptRef(new RefCountedHarfbuzzFace(harfbuzzFace));
+ }
+
+ ~RefCountedHarfbuzzFace();
+
+ HB_FaceRec_* face() const { return m_harfbuzzFace; }
+
+ private:
+ RefCountedHarfbuzzFace(HB_FaceRec_* harfbuzzFace) : m_harfbuzzFace(harfbuzzFace)
+ {
+ }
+
+ HB_FaceRec_* m_harfbuzzFace;
+ };
+
+ void querySystemForRenderStyle();
+
+ // FIXME: Could SkAutoUnref be used here?
+ SkTypeface* m_typeface;
+ CString m_family;
+ float m_textSize;
+ bool m_fakeBold;
+ bool m_fakeItalic;
+ FontOrientation m_orientation;
+ FontRenderStyle m_style;
+ mutable RefPtr<RefCountedHarfbuzzFace> m_harfbuzzFace;
+
+ SkTypeface* hashTableDeletedFontValue() const { return reinterpret_cast<SkTypeface*>(-1); }
+};
+
+} // namespace WebCore
+
+#endif // ifdef FontPlatformData_h
diff --git a/Source/WebCore/platform/graphics/chromium/FontRenderStyle.h b/Source/WebCore/platform/graphics/chromium/FontRenderStyle.h
new file mode 100644
index 0000000..6e2ae54
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontRenderStyle.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 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 FontRenderStyle_h
+#define FontRenderStyle_h
+
+namespace WebCore {
+
+// FontRenderStyle describes the user's preferences for rendering a font at a
+// given size.
+struct FontRenderStyle {
+ enum {
+ NoPreference = 2,
+ };
+
+ FontRenderStyle()
+ : useBitmaps(0),
+ useAutoHint(0),
+ useHinting(0),
+ hintStyle(0),
+ useAntiAlias(0),
+ useSubpixel(0) { }
+
+ bool operator==(const FontRenderStyle& a) const
+ {
+ return useBitmaps == a.useBitmaps
+ && useAutoHint == a.useAutoHint
+ && useHinting == a.useHinting
+ && hintStyle == a.hintStyle
+ && useAntiAlias == a.useAntiAlias
+ && useSubpixel == a.useSubpixel;
+ }
+
+ // Each of the use* members below can take one of three values:
+ // 0: off
+ // 1: on
+ // NoPreference: no preference expressed
+ char useBitmaps; // use embedded bitmap strike if possible
+ char useAutoHint; // use 'auto' hinting (FreeType specific)
+ char useHinting; // hint glyphs to the pixel grid
+ char hintStyle; // level of hinting, 0..3
+ char useAntiAlias; // antialias glyph shapes
+ char useSubpixel; // use subpixel antialias
+};
+
+}
+
+#endif // FontRenderStyle_h
diff --git a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp
new file mode 100644
index 0000000..bea0572
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 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.
+ */
+
+#include "config.h"
+#include "FontUtilsChromiumWin.h"
+
+#include <limits>
+
+#include "PlatformString.h"
+#include "UniscribeHelper.h"
+#include <unicode/locid.h>
+#include <unicode/uchar.h>
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+namespace {
+
+bool isFontPresent(const UChar* fontName)
+{
+ HFONT hfont = CreateFont(12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ fontName);
+ if (!hfont)
+ return false;
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont));
+ WCHAR actualFontName[LF_FACESIZE];
+ GetTextFace(dc, LF_FACESIZE, actualFontName);
+ actualFontName[LF_FACESIZE - 1] = 0;
+ SelectObject(dc, oldFont);
+ DeleteObject(hfont);
+ ReleaseDC(0, dc);
+ // We don't have to worry about East Asian fonts with locale-dependent
+ // names here for now.
+ return !wcscmp(fontName, actualFontName);
+}
+
+// A simple mapping from UScriptCode to family name. This is a sparse array,
+// which works well since the range of UScriptCode values is small.
+typedef const UChar* ScriptToFontMap[USCRIPT_CODE_LIMIT];
+
+void initializeScriptFontMap(ScriptToFontMap& scriptFontMap)
+{
+ struct FontMap {
+ UScriptCode script;
+ const UChar* family;
+ };
+
+ static const FontMap fontMap[] = {
+ {USCRIPT_LATIN, L"times new roman"},
+ {USCRIPT_GREEK, L"times new roman"},
+ {USCRIPT_CYRILLIC, L"times new roman"},
+ // FIXME: Consider trying new Vista fonts before XP fonts for CJK.
+ // Some Vista users do want to use Vista cleartype CJK fonts. If we
+ // did, the results of tests with CJK characters would have to be
+ // regenerated for Vista.
+ {USCRIPT_SIMPLIFIED_HAN, L"simsun"},
+ {USCRIPT_TRADITIONAL_HAN, L"pmingliu"},
+ {USCRIPT_HIRAGANA, L"ms pgothic"},
+ {USCRIPT_KATAKANA, L"ms pgothic"},
+ {USCRIPT_KATAKANA_OR_HIRAGANA, L"ms pgothic"},
+ {USCRIPT_HANGUL, L"gulim"},
+ {USCRIPT_THAI, L"tahoma"},
+ {USCRIPT_HEBREW, L"david"},
+ {USCRIPT_ARABIC, L"tahoma"},
+ {USCRIPT_DEVANAGARI, L"mangal"},
+ {USCRIPT_BENGALI, L"vrinda"},
+ {USCRIPT_GURMUKHI, L"raavi"},
+ {USCRIPT_GUJARATI, L"shruti"},
+ {USCRIPT_TAMIL, L"latha"},
+ {USCRIPT_TELUGU, L"gautami"},
+ {USCRIPT_KANNADA, L"tunga"},
+ {USCRIPT_GEORGIAN, L"sylfaen"},
+ {USCRIPT_ARMENIAN, L"sylfaen"},
+ {USCRIPT_THAANA, L"mv boli"},
+ {USCRIPT_CANADIAN_ABORIGINAL, L"euphemia"},
+ {USCRIPT_CHEROKEE, L"plantagenet cherokee"},
+ {USCRIPT_MONGOLIAN, L"mongolian balti"},
+ // For USCRIPT_COMMON, we map blocks to scripts when
+ // that makes sense.
+ };
+
+ struct ScriptToFontFamilies {
+ UScriptCode script;
+ const UChar** families;
+ };
+
+ // Kartika on Vista or earlier lacks the support for Chillu
+ // letters added to Unicode 5.1.
+ // Try AnjaliOldLipi (a very widely used Malaylalam font with the full
+ // Unicode 5.x support) before falling back to Kartika.
+ static const UChar* malayalamFonts[] = {L"AnjaliOldLipi", L"Lohit Malayalam", L"Kartika", L"Rachana", 0};
+ // Try Khmer OS before Vista fonts because 'Khmer OS' goes along better
+ // with Latin and looks better/larger for the same size.
+ static const UChar* khmerFonts[] = {L"Khmer OS", L"MoolBoran", L"DaunPenh", L"Code2000", 0};
+ // For the following 6 scripts, two or fonts are listed. The fonts in
+ // the 1st slot are not available on Windows XP. To support these
+ // scripts on XP, listed in the rest of slots are widely used
+ // fonts.
+ static const UChar* ethiopicFonts[] = {L"Nyala", L"Abyssinica SIL", L"Ethiopia Jiret", L"Visual Geez Unicode", L"GF Zemen Unicode", 0};
+ static const UChar* oriyaFonts[] = {L"Kalinga", L"ori1Uni", L"Lohit Oriya", 0};
+ static const UChar* laoFonts[] = {L"DokChampa", L"Saysettha OT", L"Phetsarath OT", L"Code2000", 0};
+ static const UChar* tibetanFonts[] = {L"Microsoft Himalaya", L"Jomolhari", L"Tibetan Machine Uni", 0};
+ static const UChar* sinhalaFonts[] = {L"Iskoola Pota", L"AksharUnicode", 0};
+ static const UChar* yiFonts[] = {L"Microsoft Yi Balti", L"Nuosu SIL", L"Code2000", 0};
+ // http://www.bethmardutho.org/support/meltho/download/index.php
+ static const UChar* syriacFonts[] = {L"Estrangelo Edessa", L"Estrangelo Nisibin", L"Code2000", 0};
+ // No Myanmar/Burmese font is shipped with Windows, yet. Try a few
+ // widely available/used ones that supports Unicode 5.1 or later.
+ static const UChar* myanmarFonts[] = {L"Padauk", L"Parabaik", L"Myanmar3", L"Code2000", 0};
+
+ static const ScriptToFontFamilies scriptToFontFamilies[] = {
+ {USCRIPT_MALAYALAM, malayalamFonts},
+ {USCRIPT_KHMER, khmerFonts},
+ {USCRIPT_ETHIOPIC, ethiopicFonts},
+ {USCRIPT_ORIYA, oriyaFonts},
+ {USCRIPT_LAO, laoFonts},
+ {USCRIPT_TIBETAN, tibetanFonts},
+ {USCRIPT_SINHALA, sinhalaFonts},
+ {USCRIPT_YI, yiFonts},
+ {USCRIPT_SYRIAC, syriacFonts},
+ {USCRIPT_MYANMAR, myanmarFonts},
+ };
+
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontMap); ++i)
+ scriptFontMap[fontMap[i].script] = fontMap[i].family;
+
+ // FIXME: Instead of scanning the hard-coded list, we have to
+ // use EnumFont* to 'inspect' fonts to pick up fonts covering scripts
+ // when it's possible (e.g. using OS/2 table). If we do that, this
+ // had better be pulled out of here.
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(scriptToFontFamilies); ++i) {
+ UScriptCode script = scriptToFontFamilies[i].script;
+ scriptFontMap[script] = 0;
+ const UChar** familyPtr = scriptToFontFamilies[i].families;
+ while (*familyPtr) {
+ if (isFontPresent(*familyPtr)) {
+ scriptFontMap[script] = *familyPtr;
+ break;
+ }
+ ++familyPtr;
+ }
+ }
+
+ // Initialize the locale-dependent mapping.
+ // Since Chrome synchronizes the ICU default locale with its UI locale,
+ // this ICU locale tells the current UI locale of Chrome.
+ icu::Locale locale = icu::Locale::getDefault();
+ const UChar* localeFamily = 0;
+ if (locale == icu::Locale::getJapanese())
+ localeFamily = scriptFontMap[USCRIPT_HIRAGANA];
+ else if (locale == icu::Locale::getKorean())
+ localeFamily = scriptFontMap[USCRIPT_HANGUL];
+ else if (locale == icu::Locale::getTraditionalChinese())
+ localeFamily = scriptFontMap[USCRIPT_TRADITIONAL_HAN];
+ else {
+ // For other locales, use the simplified Chinese font for Han.
+ localeFamily = scriptFontMap[USCRIPT_SIMPLIFIED_HAN];
+ }
+ if (localeFamily)
+ scriptFontMap[USCRIPT_HAN] = localeFamily;
+}
+
+// There are a lot of characters in USCRIPT_COMMON that can be covered
+// by fonts for scripts closely related to them. See
+// http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:]
+// FIXME: make this more efficient with a wider coverage
+UScriptCode getScriptBasedOnUnicodeBlock(int ucs4)
+{
+ UBlockCode block = ublock_getCode(ucs4);
+ switch (block) {
+ case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
+ return USCRIPT_HAN;
+ case UBLOCK_HIRAGANA:
+ case UBLOCK_KATAKANA:
+ return USCRIPT_HIRAGANA;
+ case UBLOCK_ARABIC:
+ return USCRIPT_ARABIC;
+ case UBLOCK_THAI:
+ return USCRIPT_THAI;
+ case UBLOCK_GREEK:
+ return USCRIPT_GREEK;
+ case UBLOCK_DEVANAGARI:
+ // For Danda and Double Danda (U+0964, U+0965), use a Devanagari
+ // font for now although they're used by other scripts as well.
+ // Without a context, we can't do any better.
+ return USCRIPT_DEVANAGARI;
+ case UBLOCK_ARMENIAN:
+ return USCRIPT_ARMENIAN;
+ case UBLOCK_GEORGIAN:
+ return USCRIPT_GEORGIAN;
+ case UBLOCK_KANNADA:
+ return USCRIPT_KANNADA;
+ default:
+ return USCRIPT_COMMON;
+ }
+}
+
+UScriptCode getScript(int ucs4)
+{
+ UErrorCode err = U_ZERO_ERROR;
+ UScriptCode script = uscript_getScript(ucs4, &err);
+ // If script is invalid, common or inherited or there's an error,
+ // infer a script based on the unicode block of a character.
+ if (script <= USCRIPT_INHERITED || U_FAILURE(err))
+ script = getScriptBasedOnUnicodeBlock(ucs4);
+ return script;
+}
+
+const int kUndefinedAscent = std::numeric_limits<int>::min();
+
+// Given an HFONT, return the ascent. If GetTextMetrics fails,
+// kUndefinedAscent is returned, instead.
+int getAscent(HFONT hfont)
+{
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, hfont);
+ TEXTMETRIC tm;
+ BOOL gotMetrics = GetTextMetrics(dc, &tm);
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+ return gotMetrics ? tm.tmAscent : kUndefinedAscent;
+}
+
+struct FontData {
+ FontData()
+ : hfont(0)
+ , ascent(kUndefinedAscent)
+ , scriptCache(0)
+ {
+ }
+
+ HFONT hfont;
+ int ascent;
+ mutable SCRIPT_CACHE scriptCache;
+};
+
+// Again, using hash_map does not earn us much here. page_cycler_test intl2
+// gave us a 'better' result with map than with hash_map even though they're
+// well-within 1-sigma of each other so that the difference is not significant.
+// On the other hand, some pages in intl2 seem to take longer to load with map
+// in the 1st pass. Need to experiment further.
+typedef HashMap<String, FontData> FontDataCache;
+
+} // namespace
+
+// FIXME: this is font fallback code version 0.1
+// - Cover all the scripts
+// - Get the default font for each script/generic family from the
+// preference instead of hardcoding in the source.
+// (at least, read values from the registry for IE font settings).
+// - Support generic families (from FontDescription)
+// - If the default font for a script is not available,
+// try some more fonts known to support it. Finally, we can
+// use EnumFontFamilies or similar APIs to come up with a list of
+// fonts supporting the script and cache the result.
+// - Consider using UnicodeSet (or UnicodeMap) converted from
+// GLYPHSET (BMP) or directly read from truetype cmap tables to
+// keep track of which character is supported by which font
+// - Update script_font_cache in response to WM_FONTCHANGE
+
+const UChar* getFontFamilyForScript(UScriptCode script,
+ FontDescription::GenericFamilyType generic)
+{
+ static ScriptToFontMap scriptFontMap;
+ static bool initialized = false;
+ if (!initialized) {
+ initializeScriptFontMap(scriptFontMap);
+ initialized = true;
+ }
+ if (script == USCRIPT_INVALID_CODE)
+ return 0;
+ ASSERT(script < USCRIPT_CODE_LIMIT);
+ return scriptFontMap[script];
+}
+
+// FIXME:
+// - Handle 'Inherited', 'Common' and 'Unknown'
+// (see http://www.unicode.org/reports/tr24/#Usage_Model )
+// For 'Inherited' and 'Common', perhaps we need to
+// accept another parameter indicating the previous family
+// and just return it.
+// - All the characters (or characters up to the point a single
+// font can cover) need to be taken into account
+const UChar* getFallbackFamily(const UChar* characters,
+ int length,
+ FontDescription::GenericFamilyType generic,
+ UChar32* charChecked,
+ UScriptCode* scriptChecked)
+{
+ ASSERT(characters && characters[0] && length > 0);
+ UScriptCode script = USCRIPT_COMMON;
+
+ // Sometimes characters common to script (e.g. space) is at
+ // the beginning of a string so that we need to skip them
+ // to get a font required to render the string.
+ int i = 0;
+ UChar32 ucs4 = 0;
+ while (i < length && script == USCRIPT_COMMON) {
+ U16_NEXT(characters, i, length, ucs4);
+ script = getScript(ucs4);
+ }
+
+ // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for
+ // Han (determined in a locale-dependent way above). Full-width ASCII
+ // characters are rather widely used in Japanese and Chinese documents and
+ // they're fully covered by Chinese, Japanese and Korean fonts.
+ if (0xFF00 < ucs4 && ucs4 < 0xFF5F)
+ script = USCRIPT_HAN;
+
+ if (script == USCRIPT_COMMON)
+ script = getScriptBasedOnUnicodeBlock(ucs4);
+
+ const UChar* family = getFontFamilyForScript(script, generic);
+ // Another lame work-around to cover non-BMP characters.
+ // If the font family for script is not found or the character is
+ // not in BMP (> U+FFFF), we resort to the hard-coded list of
+ // fallback fonts for now.
+ if (!family || ucs4 > 0xFFFF) {
+ int plane = ucs4 >> 16;
+ switch (plane) {
+ case 1:
+ family = L"code2001";
+ break;
+ case 2:
+ // Use a Traditional Chinese ExtB font if in Traditional Chinese locale.
+ // Otherwise, use a Simplified Chinese ExtB font. Windows Japanese
+ // fonts do support a small subset of ExtB (that are included in JIS X 0213),
+ // but its coverage is rather sparse.
+ // Eventually, this should be controlled by lang/xml:lang.
+ if (icu::Locale::getDefault() == icu::Locale::getTraditionalChinese())
+ family = L"pmingliu-extb";
+ else
+ family = L"simsun-extb";
+ break;
+ default:
+ family = L"lucida sans unicode";
+ }
+ }
+
+ if (charChecked)
+ *charChecked = ucs4;
+ if (scriptChecked)
+ *scriptChecked = script;
+ return family;
+}
+
+// Be aware that this is not thread-safe.
+bool getDerivedFontData(const UChar* family,
+ int style,
+ LOGFONT* logfont,
+ int* ascent,
+ HFONT* hfont,
+ SCRIPT_CACHE** scriptCache)
+{
+ ASSERT(logfont);
+ ASSERT(family);
+ ASSERT(*family);
+
+ // It does not matter that we leak font data when we exit.
+ static FontDataCache fontDataCache;
+
+ // FIXME: This comes up pretty high in the profile so that
+ // we need to measure whether using SHA256 (after coercing all the
+ // fields to char*) is faster than String::format.
+ String fontKey = String::format("%1d:%d:%ls", style, logfont->lfHeight, family);
+ FontDataCache::iterator iter = fontDataCache.find(fontKey);
+ FontData* derived;
+ if (iter == fontDataCache.end()) {
+ ASSERT(wcslen(family) < LF_FACESIZE);
+ wcscpy_s(logfont->lfFaceName, LF_FACESIZE, family);
+ // FIXME: CreateFontIndirect always comes up with
+ // a font even if there's no font matching the name. Need to
+ // check it against what we actually want (as is done in
+ // FontCacheWin.cpp)
+ pair<FontDataCache::iterator, bool> entry = fontDataCache.add(fontKey, FontData());
+ derived = &entry.first->second;
+ derived->hfont = CreateFontIndirect(logfont);
+ // GetAscent may return kUndefinedAscent, but we still want to
+ // cache it so that we won't have to call CreateFontIndirect once
+ // more for HFONT next time.
+ derived->ascent = getAscent(derived->hfont);
+ } else {
+ derived = &iter->second;
+ // Last time, GetAscent failed so that only HFONT was
+ // cached. Try once more assuming that TryPreloadFont
+ // was called by a caller between calls.
+ if (kUndefinedAscent == derived->ascent)
+ derived->ascent = getAscent(derived->hfont);
+ }
+ *hfont = derived->hfont;
+ *ascent = derived->ascent;
+ *scriptCache = &(derived->scriptCache);
+ return *ascent != kUndefinedAscent;
+}
+
+int getStyleFromLogfont(const LOGFONT* logfont)
+{
+ // FIXME: consider defining UNDEFINED or INVALID for style and
+ // returning it when logfont is 0
+ if (!logfont) {
+ ASSERT_NOT_REACHED();
+ return FontStyleNormal;
+ }
+ return (logfont->lfItalic ? FontStyleItalic : FontStyleNormal) |
+ (logfont->lfUnderline ? FontStyleUnderlined : FontStyleNormal) |
+ (logfont->lfWeight >= 700 ? FontStyleBold : FontStyleNormal);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h
new file mode 100644
index 0000000..b637ede
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 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.
+ */
+
+// A collection of utilities for font handling.
+
+// FIXME: Move all methods to the files that have their callsites and remove this file.
+// *Utils files are not very WebKit-ty.
+
+#ifndef FontUtilsChromiumWin_h
+#define FontUtilsChromiumWin_h
+
+#include <usp10.h>
+#include <wchar.h>
+#include <windows.h>
+
+#include "FontDescription.h"
+#include <unicode/uscript.h>
+
+namespace WebCore {
+
+// Return a font family that supports a script and belongs to |generic| font
+// family. It can return NULL and a caller has to implement its own fallback.
+const UChar* getFontFamilyForScript(UScriptCode, FontDescription::GenericFamilyType);
+
+// Return a font family that can render |characters| based on
+// what script characters belong to. When char_checked is non-NULL,
+// it's filled with the character used to determine the script.
+// When script_checked is non-NULL, the script used to determine
+// the family is returned.
+// FIXME: This function needs a total overhaul.
+const UChar* getFallbackFamily(const UChar* characters, int length,
+ FontDescription::GenericFamilyType,
+ UChar32* charChecked,
+ UScriptCode* scriptChecked);
+
+// Derive a new HFONT by replacing lfFaceName of LOGFONT with |family|,
+// calculate the ascent for the derived HFONT, and initialize SCRIPT_CACHE
+// in FontData.
+// |style| is only used for cache key generation. |style| is
+// bit-wise OR of BOLD(1), UNDERLINED(2) and ITALIC(4) and
+// should match what's contained in LOGFONT. It should be calculated
+// by calling GetStyleFromLogFont.
+// Returns false if the font is not accessible, in which case |ascent| field
+// of |fontdata| is set to kUndefinedAscent.
+// Be aware that this is not thread-safe.
+// FIXME: Instead of having three out params, we'd better have one
+// (|*FontData|), but somehow it mysteriously messes up the layout for
+// certain complex script pages (e.g. hi.wikipedia.org) and also crashes
+// at the start-up if recently visited page list includes pages with complex
+// scripts in their title. Moreover, somehow the very first-pass of
+// intl2 page-cycler test is noticeably slower with one out param than
+// the current version although the subsequent 9 passes take about the
+// same time.
+bool getDerivedFontData(const UChar* family, int style, LOGFONT*, int* ascent, HFONT*, SCRIPT_CACHE**);
+
+enum {
+ FontStyleNormal = 0,
+ FontStyleBold = 1,
+ FontStyleItalic = 2,
+ FontStyleUnderlined = 4
+};
+
+// Derive style (bit-wise OR of FONT_STYLE_BOLD, FONT_STYLE_UNDERLINED, and
+// FONT_STYLE_ITALIC) from LOGFONT. Returns 0 if |*logfont| is NULL.
+int getStyleFromLogfont(const LOGFONT*);
+
+} // namespace WebCore
+
+#endif // FontUtilsChromiumWin_h
diff --git a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp
new file mode 100644
index 0000000..697cf5e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+
+#include "GLES2Canvas.h"
+
+#include "DrawingBuffer.h"
+#include "FloatRect.h"
+#include "GraphicsContext3D.h"
+#include "IntRect.h"
+#include "PlatformString.h"
+#include "SharedGraphicsContext3D.h"
+#include "SolidFillShader.h"
+#include "TexShader.h"
+#include "Texture.h"
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+struct GLES2Canvas::State {
+ State()
+ : m_fillColor(0, 0, 0, 255)
+ , m_alpha(1.0f)
+ , m_compositeOp(CompositeSourceOver)
+ {
+ }
+ Color m_fillColor;
+ float m_alpha;
+ CompositeOperator m_compositeOp;
+ AffineTransform m_ctm;
+};
+
+GLES2Canvas::GLES2Canvas(SharedGraphicsContext3D* context, DrawingBuffer* drawingBuffer, const IntSize& size)
+ : m_size(size)
+ , m_context(context)
+ , m_drawingBuffer(drawingBuffer)
+ , m_state(0)
+{
+ m_flipMatrix.translate(-1.0f, 1.0f);
+ m_flipMatrix.scale(2.0f / size.width(), -2.0f / size.height());
+
+ m_stateStack.append(State());
+ m_state = &m_stateStack.last();
+}
+
+GLES2Canvas::~GLES2Canvas()
+{
+}
+
+void GLES2Canvas::bindFramebuffer()
+{
+ m_drawingBuffer->bind();
+}
+
+void GLES2Canvas::clearRect(const FloatRect& rect)
+{
+ bindFramebuffer();
+ if (m_state->m_ctm.isIdentity()) {
+ m_context->scissor(rect);
+ m_context->enable(GraphicsContext3D::SCISSOR_TEST);
+ m_context->clearColor(Color(RGBA32(0)));
+ m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
+ m_context->disable(GraphicsContext3D::SCISSOR_TEST);
+ } else {
+ save();
+ setCompositeOperation(CompositeClear);
+ fillRect(rect, Color(RGBA32(0)), ColorSpaceDeviceRGB);
+ restore();
+ }
+}
+
+void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ m_context->applyCompositeOperator(m_state->m_compositeOp);
+ m_context->useQuadVertices();
+
+ AffineTransform matrix(m_flipMatrix);
+ matrix.multLeft(m_state->m_ctm);
+ matrix.translate(rect.x(), rect.y());
+ matrix.scale(rect.width(), rect.height());
+
+ m_context->useFillSolidProgram(matrix, color);
+
+ bindFramebuffer();
+ m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4);
+}
+
+void GLES2Canvas::fillRect(const FloatRect& rect)
+{
+ fillRect(rect, m_state->m_fillColor, ColorSpaceDeviceRGB);
+}
+
+void GLES2Canvas::setFillColor(const Color& color, ColorSpace colorSpace)
+{
+ m_state->m_fillColor = color;
+}
+
+void GLES2Canvas::setAlpha(float alpha)
+{
+ m_state->m_alpha = alpha;
+}
+
+void GLES2Canvas::translate(float x, float y)
+{
+ m_state->m_ctm.translate(x, y);
+}
+
+void GLES2Canvas::rotate(float angleInRadians)
+{
+ m_state->m_ctm.rotate(angleInRadians * (180.0f / M_PI));
+}
+
+void GLES2Canvas::scale(const FloatSize& size)
+{
+ m_state->m_ctm.scale(size.width(), size.height());
+}
+
+void GLES2Canvas::concatCTM(const AffineTransform& affine)
+{
+ m_state->m_ctm.multLeft(affine);
+}
+
+void GLES2Canvas::save()
+{
+ m_stateStack.append(State(m_stateStack.last()));
+ m_state = &m_stateStack.last();
+}
+
+void GLES2Canvas::restore()
+{
+ ASSERT(!m_stateStack.isEmpty());
+ m_stateStack.removeLast();
+ m_state = &m_stateStack.last();
+}
+
+void GLES2Canvas::drawTexturedRect(unsigned texture, const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace colorSpace, CompositeOperator compositeOp)
+{
+ m_context->applyCompositeOperator(compositeOp);
+
+ m_context->useQuadVertices();
+ m_context->setActiveTexture(GraphicsContext3D::TEXTURE0);
+
+ m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, texture);
+
+ drawQuad(textureSize, srcRect, dstRect, m_state->m_ctm, m_state->m_alpha);
+}
+
+void GLES2Canvas::drawTexturedRect(Texture* texture, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace colorSpace, CompositeOperator compositeOp)
+{
+ drawTexturedRect(texture, srcRect, dstRect, m_state->m_ctm, m_state->m_alpha, colorSpace, compositeOp);
+}
+
+
+void GLES2Canvas::drawTexturedRect(Texture* texture, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform& transform, float alpha, ColorSpace colorSpace, CompositeOperator compositeOp)
+{
+ m_context->applyCompositeOperator(compositeOp);
+ const TilingData& tiles = texture->tiles();
+ IntRect tileIdxRect = tiles.overlappedTileIndices(srcRect);
+
+ m_context->useQuadVertices();
+ m_context->setActiveTexture(GraphicsContext3D::TEXTURE0);
+
+ for (int y = tileIdxRect.y(); y <= tileIdxRect.bottom(); y++) {
+ for (int x = tileIdxRect.x(); x <= tileIdxRect.right(); x++)
+ drawTexturedRectTile(texture, tiles.tileIndex(x, y), srcRect, dstRect, transform, alpha);
+ }
+}
+
+void GLES2Canvas::drawTexturedRectTile(Texture* texture, int tile, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform& transform, float alpha)
+{
+ if (dstRect.isEmpty())
+ return;
+
+ const TilingData& tiles = texture->tiles();
+
+ texture->bindTile(tile);
+
+ FloatRect srcRectClippedInTileSpace;
+ FloatRect dstRectIntersected;
+ tiles.intersectDrawQuad(srcRect, dstRect, tile, &srcRectClippedInTileSpace, &dstRectIntersected);
+
+ IntRect tileBoundsWithBorder = tiles.tileBoundsWithBorder(tile);
+
+ drawQuad(tileBoundsWithBorder.size(), srcRectClippedInTileSpace, dstRectIntersected, transform, alpha);
+}
+
+void GLES2Canvas::drawQuad(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform& transform, float alpha)
+{
+ AffineTransform matrix(m_flipMatrix);
+ matrix.multLeft(transform);
+ matrix.translate(dstRect.x(), dstRect.y());
+ matrix.scale(dstRect.width(), dstRect.height());
+
+ AffineTransform texMatrix;
+ texMatrix.scale(1.0f / textureSize.width(), 1.0f / textureSize.height());
+ texMatrix.translate(srcRect.x(), srcRect.y());
+ texMatrix.scale(srcRect.width(), srcRect.height());
+
+ bindFramebuffer();
+
+ m_context->useTextureProgram(matrix, texMatrix, alpha);
+ m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4);
+ checkGLError("glDrawArrays");
+}
+
+void GLES2Canvas::setCompositeOperation(CompositeOperator op)
+{
+ m_state->m_compositeOp = op;
+}
+
+Texture* GLES2Canvas::createTexture(NativeImagePtr ptr, Texture::Format format, int width, int height)
+{
+ return m_context->createTexture(ptr, format, width, height);
+}
+
+Texture* GLES2Canvas::getTexture(NativeImagePtr ptr)
+{
+ return m_context->getTexture(ptr);
+}
+
+void GLES2Canvas::checkGLError(const char* header)
+{
+#ifndef NDEBUG
+ unsigned err;
+ while ((err = m_context->getError()) != GraphicsContext3D::NO_ERROR) {
+ const char* errorStr = "*** UNKNOWN ERROR ***";
+ switch (err) {
+ case GraphicsContext3D::INVALID_ENUM:
+ errorStr = "GraphicsContext3D::INVALID_ENUM";
+ break;
+ case GraphicsContext3D::INVALID_VALUE:
+ errorStr = "GraphicsContext3D::INVALID_VALUE";
+ break;
+ case GraphicsContext3D::INVALID_OPERATION:
+ errorStr = "GraphicsContext3D::INVALID_OPERATION";
+ break;
+ case GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION:
+ errorStr = "GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION";
+ break;
+ case GraphicsContext3D::OUT_OF_MEMORY:
+ errorStr = "GraphicsContext3D::OUT_OF_MEMORY";
+ break;
+ }
+ if (header)
+ LOG_ERROR("%s: %s", header, errorStr);
+ else
+ LOG_ERROR("%s", errorStr);
+ }
+#endif
+}
+
+}
+
diff --git a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h
new file mode 100644
index 0000000..6fc1a0e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 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 GLES2Canvas_h
+#define GLES2Canvas_h
+
+#include "AffineTransform.h"
+#include "Color.h"
+#include "ColorSpace.h"
+#include "GraphicsTypes.h"
+#include "ImageSource.h"
+#include "Texture.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Color;
+class DrawingBuffer;
+class FloatRect;
+class GraphicsContext3D;
+class SharedGraphicsContext3D;
+
+class GLES2Canvas : public Noncopyable {
+public:
+ GLES2Canvas(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&);
+ ~GLES2Canvas();
+
+ void fillRect(const FloatRect&, const Color&, ColorSpace);
+ void fillRect(const FloatRect&);
+ void clearRect(const FloatRect&);
+ void setFillColor(const Color&, ColorSpace);
+ void setAlpha(float alpha);
+ void setCompositeOperation(CompositeOperator);
+ void translate(float x, float y);
+ void rotate(float angleInRadians);
+ void scale(const FloatSize&);
+ void concatCTM(const AffineTransform&);
+
+ void save();
+ void restore();
+
+ // non-standard functions
+ // These are not standard GraphicsContext functions, and should be pushed
+ // down into a PlatformContextGLES2 at some point.
+ void drawTexturedRect(unsigned texture, const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace, CompositeOperator);
+ void drawTexturedRect(Texture*, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha, ColorSpace, CompositeOperator);
+ void drawTexturedRect(Texture*, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace, CompositeOperator);
+ Texture* createTexture(NativeImagePtr, Texture::Format, int width, int height);
+ Texture* getTexture(NativeImagePtr);
+
+ SharedGraphicsContext3D* context() const { return m_context; }
+
+ void bindFramebuffer();
+
+ DrawingBuffer* drawingBuffer() const { return m_drawingBuffer; }
+
+private:
+ void drawTexturedRectTile(Texture* texture, int tile, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha);
+ void drawQuad(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha);
+ void applyCompositeOperator(CompositeOperator);
+ void checkGLError(const char* header);
+
+ IntSize m_size;
+
+ SharedGraphicsContext3D* m_context;
+ DrawingBuffer* m_drawingBuffer;
+
+ struct State;
+ WTF::Vector<State> m_stateStack;
+ State* m_state;
+ AffineTransform m_flipMatrix;
+};
+
+}
+
+#endif // GLES2Canvas_h
diff --git a/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
new file mode 100644
index 0000000..e71f66a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2008, 2009 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.
+ */
+
+#include "config.h"
+#include <windows.h>
+#include <vector>
+
+#include "ChromiumBridge.h"
+#include "Font.h"
+#include "GlyphPageTreeNode.h"
+#include "SimpleFontData.h"
+#include "UniscribeHelperTextRun.h"
+#include "WindowsVersion.h"
+
+namespace WebCore {
+
+// Fills one page of font data pointers with 0 to indicate that there
+// are no glyphs for the characters.
+static void fillEmptyGlyphs(GlyphPage* page)
+{
+ for (int i = 0; i < GlyphPage::size; ++i)
+ page->setGlyphDataForIndex(i, 0, 0);
+}
+
+// Lazily initializes space glyph
+static Glyph initSpaceGlyph(HDC dc, Glyph* spaceGlyph)
+{
+ if (*spaceGlyph)
+ return *spaceGlyph;
+
+ static wchar_t space = ' ';
+ GetGlyphIndices(dc, &space, 1, spaceGlyph, 0);
+ return *spaceGlyph;
+}
+
+// Fills |length| glyphs starting at |offset| in a |page| in the Basic
+// Multilingual Plane (<= U+FFFF). The input buffer size should be the
+// same as |length|. We can use the standard Windows GDI functions here.
+// Returns true if any glyphs were found.
+static bool fillBMPGlyphs(unsigned offset,
+ unsigned length,
+ UChar* buffer,
+ GlyphPage* page,
+ const SimpleFontData* fontData,
+ bool recurse)
+{
+ HDC dc = GetDC((HWND)0);
+ HGDIOBJ oldFont = SelectObject(dc, fontData->platformData().hfont());
+
+ TEXTMETRIC tm = {0};
+ if (!GetTextMetrics(dc, &tm)) {
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ if (recurse) {
+ if (ChromiumBridge::ensureFontLoaded(fontData->platformData().hfont()))
+ return fillBMPGlyphs(offset, length, buffer, page, fontData, false);
+ else {
+ fillEmptyGlyphs(page);
+ return false;
+ }
+ } else {
+ // FIXME: Handle gracefully the error if this call also fails.
+ // See http://crbug.com/6401
+ LOG_ERROR("Unable to get the text metrics after second attempt");
+ fillEmptyGlyphs(page);
+ return false;
+ }
+ }
+
+ // FIXME: GetGlyphIndices() sets each item of localGlyphBuffer[]
+ // with the one of the values listed below.
+ // * With the GGI_MARK_NONEXISTING_GLYPHS flag
+ // + If the font has a glyph available for the character,
+ // localGlyphBuffer[i] > 0x0.
+ // + If the font does not have glyphs available for the character,
+ // localGlyphBuffer[i] = 0x1F (TrueType Collection?) or
+ // 0xFFFF (OpenType?).
+ // * Without the GGI_MARK_NONEXISTING_GLYPHS flag
+ // + If the font has a glyph available for the character,
+ // localGlyphBuffer[i] > 0x0.
+ // + If the font does not have glyphs available for the character,
+ // localGlyphBuffer[i] = 0x80.
+ // (Windows automatically assigns the glyph for a box character to
+ // prevent ExtTextOut() from returning errors.)
+ // To avoid from hurting the rendering performance, this code just
+ // tells WebKit whether or not the all glyph indices for the given
+ // characters are 0x80 (i.e. a possibly-invalid glyph) and let it
+ // use alternative fonts for the characters.
+ // Although this may cause a problem, it seems to work fine as far as I
+ // have tested. (Obviously, I need more tests.)
+ WORD localGlyphBuffer[GlyphPage::size];
+
+ // FIXME: I find some Chinese characters can not be correctly displayed
+ // when call GetGlyphIndices without flag GGI_MARK_NONEXISTING_GLYPHS,
+ // because the corresponding glyph index is set as 0x20 when current font
+ // does not have glyphs available for the character. According a blog post
+ // http://blogs.msdn.com/michkap/archive/2006/06/28/649791.aspx
+ // I think we should switch to the way about calling GetGlyphIndices with
+ // flag GGI_MARK_NONEXISTING_GLYPHS, it should be OK according the
+ // description of MSDN.
+ // Also according to Jungshik and Hironori's suggestion and modification
+ // we treat turetype and raster Font as different way when windows version
+ // is less than Vista.
+ GetGlyphIndices(dc, buffer, length, localGlyphBuffer, GGI_MARK_NONEXISTING_GLYPHS);
+
+ // Copy the output to the GlyphPage
+ bool haveGlyphs = false;
+ int invalidGlyph = 0xFFFF;
+ const DWORD cffTableTag = 0x20464643; // 4-byte identifier for OpenType CFF table ('CFF ').
+ if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE) && (GetFontData(dc, cffTableTag, 0, 0, 0) == GDI_ERROR))
+ invalidGlyph = 0x1F;
+
+ Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled.
+
+ for (unsigned i = 0; i < length; i++) {
+ UChar c = buffer[i];
+ Glyph glyph = localGlyphBuffer[i];
+ const SimpleFontData* glyphFontData = fontData;
+ // When this character should be a space, we ignore whatever the font
+ // says and use a space. Otherwise, if fonts don't map one of these
+ // space or zero width glyphs, we will get a box.
+ if (Font::treatAsSpace(c)) {
+ // Hard code the glyph indices for characters that should be
+ // treated like spaces.
+ glyph = initSpaceGlyph(dc, &spaceGlyph);
+ } else if (glyph == invalidGlyph) {
+ // WebKit expects both the glyph index and FontData
+ // pointer to be 0 if the glyph is not present
+ glyph = 0;
+ glyphFontData = 0;
+ } else
+ haveGlyphs = true;
+ page->setGlyphDataForCharacter(offset + i, glyph, glyphFontData);
+ }
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+ return haveGlyphs;
+}
+
+// For non-BMP characters, each is two words (UTF-16) and the input buffer
+// size is 2 * |length|. Since GDI doesn't know how to handle non-BMP
+// characters, we must use Uniscribe to tell us the glyph indices.
+//
+// We don't want to call this in the case of "regular" characters since some
+// fonts may not have the correct combining rules for accents. See the notes
+// at the bottom of ScriptGetCMap. We can't use ScriptGetCMap, though, since
+// it doesn't seem to support UTF-16, despite what this blog post says:
+// http://blogs.msdn.com/michkap/archive/2006/06/29/650680.aspx
+//
+// So we fire up the full Uniscribe doohicky, give it our string, and it will
+// correctly handle the UTF-16 for us. The hard part is taking this and getting
+// the glyph indices back out that correspond to the correct input characters,
+// since they may be missing.
+//
+// Returns true if any glyphs were found.
+static bool fillNonBMPGlyphs(unsigned offset,
+ unsigned length,
+ UChar* buffer,
+ GlyphPage* page,
+ const SimpleFontData* fontData)
+{
+ bool haveGlyphs = false;
+
+ UniscribeHelperTextRun state(buffer, length * 2, false,
+ fontData->platformData().hfont(),
+ fontData->platformData().scriptCache(),
+ fontData->platformData().scriptFontProperties());
+ state.setInhibitLigate(true);
+ state.setDisableFontFallback(true);
+ state.init();
+
+ for (unsigned i = 0; i < length; i++) {
+ // Each character in this input buffer is a surrogate pair, which
+ // consists of two UChars. So, the offset for its i-th character is
+ // (i * 2).
+ WORD glyph = state.firstGlyphForCharacter(i * 2);
+ if (glyph) {
+ haveGlyphs = true;
+ page->setGlyphDataForIndex(offset + i, glyph, fontData);
+ } else
+ // Clear both glyph and fontData fields.
+ page->setGlyphDataForIndex(offset + i, 0, 0);
+ }
+ return haveGlyphs;
+}
+
+// We're supposed to return true if there are any glyphs in the range
+// specified by |offset| and |length| in our font,
+// false if there are none.
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* characterBuffer,
+ unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // We have to handle BMP and non-BMP characters differently.
+ // FIXME: Add assertions to make sure that buffer is entirely in BMP
+ // or entirely in non-BMP.
+ if (bufferLength == length)
+ return fillBMPGlyphs(offset, length, characterBuffer, this, fontData, true);
+
+ if (bufferLength == 2 * length) {
+ // A non-BMP input buffer will be twice as long as output glyph buffer
+ // because each character in the non-BMP input buffer will be
+ // represented by a surrogate pair (two UChar's).
+ return fillNonBMPGlyphs(offset, length, characterBuffer, this, fontData);
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp
new file mode 100644
index 0000000..5e8d148
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Apple 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.
+ */
+
+
+/** FIXME
+ * This file borrows code heavily from platform/graphics/win/GraphicsLayerCACF.cpp
+ * (and hence it includes both copyrights)
+ * Ideally the common code (mostly the code that keeps track of the layer hierarchy)
+ * should be kept separate and shared between platforms. It would be a well worthwhile
+ * effort once the Windows implementation (binaries and headers) of CoreAnimation is
+ * checked in to the WebKit repository. Until then only Apple can make this happen.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayerChromium.h"
+
+#include "Canvas2DLayerChromium.h"
+#include "ContentLayerChromium.h"
+#include "DrawingBuffer.h"
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "Image.h"
+#include "ImageLayerChromium.h"
+#include "LayerChromium.h"
+#include "PlatformString.h"
+#include "SystemTime.h"
+
+#include <wtf/CurrentTime.h>
+#include <wtf/StringExtras.h>
+#include <wtf/text/CString.h>
+
+using namespace std;
+
+namespace WebCore {
+
+static void setLayerBorderColor(LayerChromium& layer, const Color& color)
+{
+ layer.setBorderColor(color);
+}
+
+static void clearBorderColor(LayerChromium& layer)
+{
+ layer.setBorderColor(static_cast<RGBA32>(0));
+}
+
+static void setLayerBackgroundColor(LayerChromium& layer, const Color& color)
+{
+ layer.setBackgroundColor(color);
+}
+
+static void clearLayerBackgroundColor(LayerChromium& layer)
+{
+ layer.setBackgroundColor(static_cast<RGBA32>(0));
+}
+
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerChromium(client);
+}
+
+GraphicsLayerChromium::GraphicsLayerChromium(GraphicsLayerClient* client)
+ : GraphicsLayer(client)
+ , m_contentsLayerPurpose(NoContentsLayer)
+ , m_contentsLayerHasBackgroundColor(false)
+{
+ m_layer = ContentLayerChromium::create(this);
+
+ updateDebugIndicators();
+}
+
+GraphicsLayerChromium::~GraphicsLayerChromium()
+{
+ if (m_layer)
+ m_layer->setOwner(0);
+ if (m_contentsLayer)
+ m_contentsLayer->setOwner(0);
+ if (m_transformLayer)
+ m_transformLayer->setOwner(0);
+}
+
+void GraphicsLayerChromium::setName(const String& inName)
+{
+ String name = String::format("GraphicsLayerChromium(%p) GraphicsLayer(%p) ", m_layer.get(), this) + inName;
+ GraphicsLayer::setName(name);
+}
+
+bool GraphicsLayerChromium::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ bool childrenChanged = GraphicsLayer::setChildren(children);
+ // FIXME: GraphicsLayer::setChildren calls addChild() for each sublayer, which
+ // will end up calling updateSublayerList() N times.
+ if (childrenChanged)
+ updateSublayerList();
+
+ return childrenChanged;
+}
+
+void GraphicsLayerChromium::addChild(GraphicsLayer* childLayer)
+{
+ GraphicsLayer::addChild(childLayer);
+ updateSublayerList();
+}
+
+void GraphicsLayerChromium::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+ GraphicsLayer::addChildAtIndex(childLayer, index);
+ updateSublayerList();
+}
+
+void GraphicsLayerChromium::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildBelow(childLayer, sibling);
+ updateSublayerList();
+}
+
+void GraphicsLayerChromium::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer *sibling)
+{
+ GraphicsLayer::addChildAbove(childLayer, sibling);
+ updateSublayerList();
+}
+
+bool GraphicsLayerChromium::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ updateSublayerList();
+ return true;
+ }
+ return false;
+}
+
+void GraphicsLayerChromium::removeFromParent()
+{
+ GraphicsLayer::removeFromParent();
+ layerForSuperlayer()->removeFromSuperlayer();
+}
+
+void GraphicsLayerChromium::setPosition(const FloatPoint& point)
+{
+ GraphicsLayer::setPosition(point);
+ updateLayerPosition();
+}
+
+void GraphicsLayerChromium::setAnchorPoint(const FloatPoint3D& point)
+{
+ if (point == m_anchorPoint)
+ return;
+
+ GraphicsLayer::setAnchorPoint(point);
+ updateAnchorPoint();
+}
+
+void GraphicsLayerChromium::setSize(const FloatSize& size)
+{
+ if (size == m_size)
+ return;
+
+ GraphicsLayer::setSize(size);
+ updateLayerSize();
+}
+
+void GraphicsLayerChromium::setTransform(const TransformationMatrix& transform)
+{
+ if (transform == m_transform)
+ return;
+
+ GraphicsLayer::setTransform(transform);
+ updateTransform();
+}
+
+void GraphicsLayerChromium::setChildrenTransform(const TransformationMatrix& transform)
+{
+ if (transform == m_childrenTransform)
+ return;
+
+ GraphicsLayer::setChildrenTransform(transform);
+ updateChildrenTransform();
+}
+
+void GraphicsLayerChromium::setPreserves3D(bool preserves3D)
+{
+ if (preserves3D == m_preserves3D)
+ return;
+
+ GraphicsLayer::setPreserves3D(preserves3D);
+ updateLayerPreserves3D();
+}
+
+void GraphicsLayerChromium::setMasksToBounds(bool masksToBounds)
+{
+ if (masksToBounds == m_masksToBounds)
+ return;
+
+ GraphicsLayer::setMasksToBounds(masksToBounds);
+ updateMasksToBounds();
+}
+
+void GraphicsLayerChromium::setDrawsContent(bool drawsContent)
+{
+ if (drawsContent == m_drawsContent)
+ return;
+
+ GraphicsLayer::setDrawsContent(drawsContent);
+ updateLayerDrawsContent();
+}
+
+void GraphicsLayerChromium::setBackgroundColor(const Color& color)
+{
+ if (m_backgroundColorSet && m_backgroundColor == color)
+ return;
+
+ GraphicsLayer::setBackgroundColor(color);
+
+ m_contentsLayerHasBackgroundColor = true;
+ updateLayerBackgroundColor();
+}
+
+void GraphicsLayerChromium::clearBackgroundColor()
+{
+ if (!m_backgroundColorSet)
+ return;
+
+ GraphicsLayer::clearBackgroundColor();
+ clearLayerBackgroundColor(*m_contentsLayer);
+}
+
+void GraphicsLayerChromium::setContentsOpaque(bool opaque)
+{
+ if (m_contentsOpaque == opaque)
+ return;
+
+ GraphicsLayer::setContentsOpaque(opaque);
+ updateContentsOpaque();
+}
+
+void GraphicsLayerChromium::setBackfaceVisibility(bool visible)
+{
+ if (m_backfaceVisibility == visible)
+ return;
+
+ GraphicsLayer::setBackfaceVisibility(visible);
+ updateBackfaceVisibility();
+}
+
+void GraphicsLayerChromium::setOpacity(float opacity)
+{
+ float clampedOpacity = max(min(opacity, 1.0f), 0.0f);
+
+ if (m_opacity == clampedOpacity)
+ return;
+
+ GraphicsLayer::setOpacity(clampedOpacity);
+ primaryLayer()->setOpacity(opacity);
+}
+
+void GraphicsLayerChromium::setContentsNeedsDisplay()
+{
+ if (m_contentsLayer)
+ m_contentsLayer->setNeedsDisplay();
+}
+
+void GraphicsLayerChromium::setNeedsDisplay()
+{
+ if (drawsContent())
+ m_layer->setNeedsDisplay();
+}
+
+void GraphicsLayerChromium::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ if (drawsContent())
+ m_layer->setNeedsDisplay(rect);
+}
+
+void GraphicsLayerChromium::setContentsRect(const IntRect& rect)
+{
+ if (rect == m_contentsRect)
+ return;
+
+ GraphicsLayer::setContentsRect(rect);
+ updateContentsRect();
+}
+
+void GraphicsLayerChromium::setContentsToImage(Image* image)
+{
+ bool childrenChanged = false;
+ if (image) {
+ if (!m_contentsLayer.get() || m_contentsLayerPurpose != ContentsLayerForImage) {
+ RefPtr<ImageLayerChromium> imageLayer = ImageLayerChromium::create(this);
+ setupContentsLayer(imageLayer.get());
+ m_contentsLayer = imageLayer;
+ m_contentsLayerPurpose = ContentsLayerForImage;
+ childrenChanged = true;
+ }
+ ImageLayerChromium* imageLayer = static_cast<ImageLayerChromium*>(m_contentsLayer.get());
+ imageLayer->setContents(image);
+ updateContentsRect();
+ } else {
+ if (m_contentsLayer) {
+ childrenChanged = true;
+
+ // The old contents layer will be removed via updateSublayerList.
+ m_contentsLayer = 0;
+ }
+ }
+
+ if (childrenChanged)
+ updateSublayerList();
+}
+
+void GraphicsLayerChromium::setContentsToCanvas(PlatformLayer* platformLayer)
+{
+ bool childrenChanged = false;
+ if (platformLayer) {
+ platformLayer->setOwner(this);
+ if (m_contentsLayer.get() != platformLayer) {
+ setupContentsLayer(platformLayer);
+ m_contentsLayer = platformLayer;
+ m_contentsLayerPurpose = ContentsLayerForCanvas;
+ childrenChanged = true;
+ }
+ m_contentsLayer->setNeedsDisplay();
+ updateContentsRect();
+ } else {
+ if (m_contentsLayer) {
+ childrenChanged = true;
+
+ // The old contents layer will be removed via updateSublayerList.
+ m_contentsLayer = 0;
+ }
+ }
+
+ if (childrenChanged)
+ updateSublayerList();
+}
+
+void GraphicsLayerChromium::setContentsToMedia(PlatformLayer* layer)
+{
+ bool childrenChanged = false;
+ if (layer) {
+ if (!m_contentsLayer.get() || m_contentsLayerPurpose != ContentsLayerForVideo) {
+ setupContentsLayer(layer);
+ m_contentsLayer = layer;
+ m_contentsLayerPurpose = ContentsLayerForVideo;
+ childrenChanged = true;
+ }
+ layer->setOwner(this);
+ layer->setNeedsDisplay();
+ updateContentsRect();
+ } else {
+ if (m_contentsLayer) {
+ childrenChanged = true;
+
+ // The old contents layer will be removed via updateSublayerList.
+ m_contentsLayer = 0;
+ }
+ }
+
+ if (childrenChanged)
+ updateSublayerList();
+}
+
+PlatformLayer* GraphicsLayerChromium::hostLayerForSublayers() const
+{
+ return m_transformLayer ? m_transformLayer.get() : m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerChromium::layerForSuperlayer() const
+{
+ return m_transformLayer ? m_transformLayer.get() : m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerChromium::platformLayer() const
+{
+ return primaryLayer();
+}
+
+void GraphicsLayerChromium::setDebugBackgroundColor(const Color& color)
+{
+ if (color.isValid())
+ setLayerBackgroundColor(*m_layer, color);
+ else
+ clearLayerBackgroundColor(*m_layer);
+}
+
+void GraphicsLayerChromium::setDebugBorder(const Color& color, float borderWidth)
+{
+ if (color.isValid()) {
+ setLayerBorderColor(*m_layer, color);
+ m_layer->setBorderWidth(borderWidth);
+ } else {
+ clearBorderColor(*m_layer);
+ m_layer->setBorderWidth(0);
+ }
+}
+
+void GraphicsLayerChromium::updateSublayerList()
+{
+ Vector<RefPtr<LayerChromium> > newSublayers;
+
+ if (m_transformLayer) {
+ // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind.
+ newSublayers.append(m_layer.get());
+ } else if (m_contentsLayer) {
+ // FIXME: add the contents layer in the correct order with negative z-order children.
+ // This does not cause visible rendering issues because currently contents layers are only used
+ // for replaced elements that don't have children.
+ newSublayers.append(m_contentsLayer.get());
+ }
+
+ const Vector<GraphicsLayer*>& childLayers = children();
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerChromium* curChild = static_cast<GraphicsLayerChromium*>(childLayers[i]);
+
+ LayerChromium* childLayer = curChild->layerForSuperlayer();
+ newSublayers.append(childLayer);
+ }
+
+ for (size_t i = 0; i < newSublayers.size(); ++i)
+ newSublayers[i]->removeFromSuperlayer();
+
+ if (m_transformLayer) {
+ m_transformLayer->setSublayers(newSublayers);
+
+ if (m_contentsLayer) {
+ // If we have a transform layer, then the contents layer is parented in the
+ // primary layer (which is itself a child of the transform layer).
+ m_layer->removeAllSublayers();
+ m_layer->addSublayer(m_contentsLayer);
+ }
+ } else
+ m_layer->setSublayers(newSublayers);
+}
+
+void GraphicsLayerChromium::updateLayerPosition()
+{
+ // Position is offset on the layer by the layer anchor point.
+ FloatPoint layerPosition(m_position.x() + m_anchorPoint.x() * m_size.width(),
+ m_position.y() + m_anchorPoint.y() * m_size.height());
+
+ primaryLayer()->setPosition(layerPosition);
+}
+
+void GraphicsLayerChromium::updateLayerSize()
+{
+ IntSize layerSize(m_size.width(), m_size.height());
+ if (m_transformLayer) {
+ m_transformLayer->setBounds(layerSize);
+ // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative.
+ FloatPoint centerPoint(m_size.width() / 2, m_size.height() / 2);
+ m_layer->setPosition(centerPoint);
+ }
+
+ m_layer->setBounds(layerSize);
+
+ // Note that we don't resize m_contentsLayer. It's up the caller to do that.
+
+ // If we've changed the bounds, we need to recalculate the position
+ // of the layer, taking anchor point into account.
+ updateLayerPosition();
+}
+
+void GraphicsLayerChromium::updateAnchorPoint()
+{
+ primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y()));
+ primaryLayer()->setAnchorPointZ(m_anchorPoint.z());
+ updateLayerPosition();
+}
+
+void GraphicsLayerChromium::updateTransform()
+{
+ primaryLayer()->setTransform(m_transform);
+}
+
+void GraphicsLayerChromium::updateChildrenTransform()
+{
+ primaryLayer()->setSublayerTransform(m_childrenTransform);
+}
+
+void GraphicsLayerChromium::updateMasksToBounds()
+{
+ m_layer->setMasksToBounds(m_masksToBounds);
+ updateDebugIndicators();
+}
+
+void GraphicsLayerChromium::updateContentsOpaque()
+{
+ m_layer->setOpaque(m_contentsOpaque);
+}
+
+void GraphicsLayerChromium::updateBackfaceVisibility()
+{
+ m_layer->setDoubleSided(m_backfaceVisibility);
+}
+
+void GraphicsLayerChromium::updateLayerPreserves3D()
+{
+ if (m_preserves3D && !m_transformLayer) {
+ // Create the transform layer.
+ m_transformLayer = LayerChromium::create(this);
+
+ // Copy the position from this layer.
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+
+ m_layer->setPosition(FloatPoint(m_size.width() / 2.0f, m_size.height() / 2.0f));
+
+ m_layer->setAnchorPoint(FloatPoint(0.5f, 0.5f));
+ TransformationMatrix identity;
+ m_layer->setTransform(identity);
+
+ // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer.
+ m_layer->setOpacity(1);
+
+ // Move this layer to be a child of the transform layer.
+ if (m_layer->superlayer())
+ m_layer->superlayer()->replaceSublayer(m_layer.get(), m_transformLayer.get());
+ m_transformLayer->addSublayer(m_layer.get());
+
+ updateSublayerList();
+ } else if (!m_preserves3D && m_transformLayer) {
+ // Relace the transformLayer in the parent with this layer.
+ m_layer->removeFromSuperlayer();
+ m_transformLayer->superlayer()->replaceSublayer(m_transformLayer.get(), m_layer.get());
+
+ // Release the transform layer.
+ m_transformLayer = 0;
+
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+
+ updateSublayerList();
+ }
+
+ updateOpacityOnLayer();
+}
+
+void GraphicsLayerChromium::updateLayerDrawsContent()
+{
+ if (m_drawsContent)
+ m_layer->setNeedsDisplay();
+
+ updateDebugIndicators();
+}
+
+void GraphicsLayerChromium::updateLayerBackgroundColor()
+{
+ if (!m_contentsLayer)
+ return;
+
+ // We never create the contents layer just for background color yet.
+ if (m_backgroundColorSet)
+ setLayerBackgroundColor(*m_contentsLayer, m_backgroundColor);
+ else
+ clearLayerBackgroundColor(*m_contentsLayer);
+}
+
+void GraphicsLayerChromium::updateContentsVideo()
+{
+ // FIXME: Implement
+}
+
+void GraphicsLayerChromium::updateContentsRect()
+{
+ if (!m_contentsLayer)
+ return;
+
+ m_contentsLayer->setPosition(FloatPoint(m_contentsRect.x(), m_contentsRect.y()));
+ m_contentsLayer->setBounds(IntSize(m_contentsRect.width(), m_contentsRect.height()));
+}
+
+void GraphicsLayerChromium::setupContentsLayer(LayerChromium* contentsLayer)
+{
+ if (contentsLayer == m_contentsLayer)
+ return;
+
+ if (m_contentsLayer) {
+ m_contentsLayer->removeFromSuperlayer();
+ m_contentsLayer = 0;
+ }
+
+ if (contentsLayer) {
+ m_contentsLayer = contentsLayer;
+
+ m_contentsLayer->setAnchorPoint(FloatPoint(0, 0));
+
+ // Insert the content layer first. Video elements require this, because they have
+ // shadow content that must display in front of the video.
+ m_layer->insertSublayer(m_contentsLayer.get(), 0);
+
+ updateContentsRect();
+
+ if (showDebugBorders()) {
+ setLayerBorderColor(*m_contentsLayer, Color(0, 0, 128, 180));
+ m_contentsLayer->setBorderWidth(1);
+ }
+ }
+ updateDebugIndicators();
+}
+
+// This function simply mimics the operation of GraphicsLayerCA
+void GraphicsLayerChromium::updateOpacityOnLayer()
+{
+ primaryLayer()->setOpacity(m_opacity);
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h
new file mode 100644
index 0000000..130c25c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 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 GraphicsLayerChromium_h
+#define GraphicsLayerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsContext.h"
+#include "GraphicsLayer.h"
+
+namespace WebCore {
+
+class LayerChromium;
+
+class GraphicsLayerChromium : public GraphicsLayer {
+public:
+ GraphicsLayerChromium(GraphicsLayerClient*);
+ virtual ~GraphicsLayerChromium();
+
+ virtual void setName(const String&);
+
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
+ virtual void addChild(GraphicsLayer*);
+ virtual void addChildAtIndex(GraphicsLayer*, int index);
+ virtual void addChildAbove(GraphicsLayer*, GraphicsLayer* sibling);
+ virtual void addChildBelow(GraphicsLayer*, GraphicsLayer* sibling);
+ virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+
+ virtual void removeFromParent();
+
+ virtual void setPosition(const FloatPoint&);
+ virtual void setAnchorPoint(const FloatPoint3D&);
+ virtual void setSize(const FloatSize&);
+
+ virtual void setTransform(const TransformationMatrix&);
+
+ virtual void setChildrenTransform(const TransformationMatrix&);
+
+ virtual void setPreserves3D(bool);
+ virtual void setMasksToBounds(bool);
+ virtual void setDrawsContent(bool);
+
+ virtual void setBackgroundColor(const Color&);
+ virtual void clearBackgroundColor();
+
+ virtual void setContentsOpaque(bool);
+ virtual void setBackfaceVisibility(bool);
+
+ virtual void setOpacity(float);
+
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+ virtual void setContentsNeedsDisplay();
+
+ virtual void setContentsRect(const IntRect&);
+
+ virtual void setContentsToImage(Image*);
+ virtual void setContentsToMedia(PlatformLayer*);
+ virtual void setContentsToCanvas(PlatformLayer*);
+
+ virtual PlatformLayer* platformLayer() const;
+
+ virtual void setDebugBackgroundColor(const Color&);
+ virtual void setDebugBorder(const Color&, float borderWidth);
+
+ void notifySyncRequired()
+ {
+ if (m_client)
+ m_client->notifySyncRequired(this);
+ }
+
+private:
+ void updateOpacityOnLayer();
+
+ LayerChromium* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
+ LayerChromium* hostLayerForSublayers() const;
+ LayerChromium* layerForSuperlayer() const;
+
+ void updateSublayerList();
+ void updateLayerPosition();
+ void updateLayerSize();
+ void updateAnchorPoint();
+ void updateTransform();
+ void updateChildrenTransform();
+ void updateMasksToBounds();
+ void updateContentsOpaque();
+ void updateBackfaceVisibility();
+ void updateLayerPreserves3D();
+ void updateLayerDrawsContent();
+ void updateLayerBackgroundColor();
+
+ void updateContentsImage();
+ void updateContentsVideo();
+ void updateContentsRect();
+
+ void setupContentsLayer(LayerChromium*);
+ LayerChromium* contentsLayer() const { return m_contentsLayer.get(); }
+
+ RefPtr<LayerChromium> m_layer;
+ RefPtr<LayerChromium> m_transformLayer;
+ RefPtr<LayerChromium> m_contentsLayer;
+
+ enum ContentsLayerPurpose {
+ NoContentsLayer = 0,
+ ContentsLayerForImage,
+ ContentsLayerForVideo,
+ ContentsLayerForCanvas,
+ };
+
+ ContentsLayerPurpose m_contentsLayerPurpose;
+ bool m_contentsLayerHasBackgroundColor : 1;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp b/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp
new file mode 100644
index 0000000..056d8eb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2009 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.
+ */
+
+#include "config.h"
+
+#include "FontPlatformData.h"
+#include "wtf/OwnArrayPtr.h"
+
+#include "SkFontHost.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkUtils.h"
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+}
+
+// This file implements the callbacks which Harfbuzz requires by using Skia
+// calls. See the Harfbuzz source for references about what these callbacks do.
+
+namespace WebCore {
+
+static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
+{
+ // HB_Fixed is a 26.6 fixed point format.
+ return value * 64;
+}
+
+static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ unsigned codepoints = 0;
+ for (hb_uint32 i = 0; i < length; i++) {
+ if (!SkUTF16_IsHighSurrogate(characters[i]))
+ codepoints++;
+ if (codepoints > *glyphsSize)
+ return 0;
+ }
+
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), reinterpret_cast<uint16_t*>(glyphs));
+
+ // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
+ // |glyphs| array needs to be converted.
+ for (int i = numGlyphs - 1; i >= 0; --i) {
+ uint16_t value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t));
+ glyphs[i] = value;
+ }
+
+ *glyphsSize = numGlyphs;
+ return 1;
+}
+
+static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ OwnArrayPtr<uint16_t> glyphs16(new uint16_t[numGlyphs]);
+ if (!glyphs16.get())
+ return;
+ for (unsigned i = 0; i < numGlyphs; ++i)
+ glyphs16[i] = glyphs[i];
+ paint.getTextWidths(glyphs16.get(), numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
+
+ // The |advances| values which Skia outputs are SkScalars, which are floats
+ // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
+ // These two formats are both 32-bits long.
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ float value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(float));
+ advances[i] = SkiaScalarToHarfbuzzFixed(value);
+ }
+}
+
+static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ OwnArrayPtr<uint16_t> glyphs16(new uint16_t[length]);
+ if (!glyphs16.get())
+ return 0;
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16.get());
+
+ bool canRender = true;
+ for (int i = 0; i < numGlyphs; ++i) {
+ if (!glyphs16[i]) {
+ canRender = false;
+ break;
+ }
+ }
+
+ return canRender;
+}
+
+static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ if (flags & HB_ShaperFlag_UseDesignMetrics)
+ return HB_Err_Invalid_Argument; // This is requesting pre-hinted positions. We can't support this.
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ uint16_t glyph16 = glyph;
+ SkPath path;
+ paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
+ int numPoints = path.getPoints(0, 0);
+ if (point >= static_cast<unsigned>(numPoints))
+ return HB_Err_Invalid_SubTable;
+ SkPoint* points = reinterpret_cast<SkPoint*>(fastMalloc(sizeof(SkPoint) * (point + 1)));
+ if (!points)
+ return HB_Err_Invalid_SubTable;
+ // Skia does let us get a single point from the path.
+ path.getPoints(points, point + 1);
+ *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
+ *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
+ *resultingNumPoints = numPoints;
+ fastFree(points);
+
+ return HB_Err_Ok;
+}
+
+static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ uint16_t glyph16 = glyph;
+ SkScalar width;
+ SkRect bounds;
+ paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
+
+ metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
+ metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
+ metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
+ metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
+
+ metrics->xOffset = SkiaScalarToHarfbuzzFixed(width);
+ // We can't actually get the |y| correct because Skia doesn't export
+ // the vertical advance. However, nor we do ever render vertical text at
+ // the moment so it's unimportant.
+ metrics->yOffset = 0;
+}
+
+static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ SkPaint::FontMetrics skiaMetrics;
+ paint.getFontMetrics(&skiaMetrics);
+
+ switch (metric) {
+ case HB_FontAscent:
+ return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
+ // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
+ default:
+ return 0;
+ }
+}
+
+HB_FontClass harfbuzzSkiaClass = {
+ stringToGlyphs,
+ glyphsToAdvances,
+ canRender,
+ getOutlinePoint,
+ getGlyphMetrics,
+ getFontMetric,
+};
+
+HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(voidface);
+
+ const size_t tableSize = SkFontHost::GetTableSize(font->uniqueID(), tag);
+ if (!tableSize)
+ return HB_Err_Invalid_Argument;
+ // If Harfbuzz specified a NULL buffer then it's asking for the size of the table.
+ if (!buffer) {
+ *len = tableSize;
+ return HB_Err_Ok;
+ }
+
+ if (*len < tableSize)
+ return HB_Err_Invalid_Argument;
+ SkFontHost::GetTableData(font->uniqueID(), tag, 0, tableSize, buffer);
+ return HB_Err_Ok;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.h b/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.h
new file mode 100644
index 0000000..f7e0496
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009, 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 HarfbuzzSkia_h
+#define HarfbuzzSkia_h
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-unicode.h"
+}
+
+namespace WebCore {
+ HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
+ extern const HB_FontClass harfbuzzSkiaClass;
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp b/Source/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp
new file mode 100644
index 0000000..16f55e2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2008, 2009 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.
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+Icon::Icon(const PlatformIcon& icon)
+ : m_icon(icon)
+{
+}
+
+Icon::~Icon()
+{
+}
+
+void Icon::paint(GraphicsContext*, const IntRect&)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/IconChromiumMac.cpp b/Source/WebCore/platform/graphics/chromium/IconChromiumMac.cpp
new file mode 100644
index 0000000..a24afb2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/IconChromiumMac.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "PassRefPtr.h"
+
+// FIXME: These are temporary stubs, we need real implementations which
+// may come in the form of IconChromium.cpp. The Windows Chromium
+// implementation is currently in IconWin.cpp.
+
+namespace WebCore {
+
+Icon::~Icon()
+{
+}
+
+void Icon::paint(GraphicsContext*, const IntRect&)
+{
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/chromium/IconChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/IconChromiumWin.cpp
new file mode 100644
index 0000000..e958d4a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/IconChromiumWin.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008, 2009, 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.
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "GraphicsContext.h"
+#include "PlatformContextSkia.h"
+#include "PlatformString.h"
+#include "SkiaUtils.h"
+
+namespace WebCore {
+
+Icon::Icon(const PlatformIcon& icon)
+ : m_icon(icon)
+{
+}
+
+Icon::~Icon()
+{
+ if (m_icon)
+ DestroyIcon(m_icon);
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (context->paintingDisabled())
+ return;
+
+ HDC hdc = context->platformContext()->canvas()->beginPlatformPaint();
+ DrawIconEx(hdc, rect.x(), rect.y(), m_icon, rect.width(), rect.height(), 0, 0, DI_NORMAL);
+ context->platformContext()->canvas()->endPlatformPaint();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/ImageBufferData.h b/Source/WebCore/platform/graphics/chromium/ImageBufferData.h
new file mode 100644
index 0000000..504b893
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/ImageBufferData.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008, 2009, 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 ImageBufferData_h
+#define ImageBufferData_h
+
+#include "PlatformContextSkia.h"
+
+#include "skia/ext/platform_canvas.h"
+
+namespace WebCore {
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ skia::PlatformCanvas m_canvas;
+ PlatformContextSkia m_platformContext;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/Source/WebCore/platform/graphics/chromium/ImageChromium.cpp b/Source/WebCore/platform/graphics/chromium/ImageChromium.cpp
new file mode 100644
index 0000000..e90d566
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/ImageChromium.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2008-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.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "ChromiumBridge.h"
+
+namespace WebCore {
+
+// Other Image methods are implemented in ImageSkia.cpp
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ return ChromiumBridge::loadPlatformImageResource(name);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/ImageChromiumMac.mm b/Source/WebCore/platform/graphics/chromium/ImageChromiumMac.mm
new file mode 100644
index 0000000..073a409
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/ImageChromiumMac.mm
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008, 2009, 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.
+ */
+
+// A wrapper around Uniscribe that provides a reasonable API.
+
+#include "config.h"
+#include "BitmapImage.h"
+
+#include "ChromiumBridge.h"
+#include "Image.h"
+
+namespace WebCore {
+
+PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+{
+ return ChromiumBridge::loadPlatformImageResource(name);
+}
+
+// FIXME: These are temporary stubs, we need real implementations which
+// may come in the form of ImageChromium.cpp. The Windows Chromium
+// implementation is currently in ImageSkia.cpp.
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp
new file mode 100644
index 0000000..cd299c1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "ImageLayerChromium.h"
+
+#include "Image.h"
+#include "LayerRendererChromium.h"
+#include "LayerTexture.h"
+
+#if PLATFORM(SKIA)
+#include "NativeImageSkia.h"
+#include "PlatformContextSkia.h"
+#endif
+
+#if PLATFORM(CG)
+#include <CoreGraphics/CGBitmapContext.h>
+#include <CoreGraphics/CGContext.h>
+#include <CoreGraphics/CGImage.h>
+#include <wtf/RetainPtr.h>
+#endif
+
+namespace WebCore {
+
+PassRefPtr<ImageLayerChromium> ImageLayerChromium::create(GraphicsLayerChromium* owner)
+{
+ return adoptRef(new ImageLayerChromium(owner));
+}
+
+ImageLayerChromium::ImageLayerChromium(GraphicsLayerChromium* owner)
+ : ContentLayerChromium(owner)
+ , m_contents(0)
+{
+}
+
+void ImageLayerChromium::setContents(Image* contents)
+{
+ // Check if the image has changed.
+ if (m_contents == contents)
+ return;
+ m_contents = contents;
+ setNeedsDisplay();
+}
+
+void ImageLayerChromium::updateContentsIfDirty()
+{
+ ASSERT(layerRenderer());
+
+ // FIXME: Remove this test when tiled layers are implemented.
+ if (requiresClippedUpdateRect()) {
+ // Use the base version of updateContents which draws a subset of the
+ // image to a bitmap, as the pixel contents can't be uploaded directly.
+ ContentLayerChromium::updateContentsIfDirty();
+ return;
+ }
+
+ void* pixels = 0;
+ IntSize bitmapSize;
+
+ NativeImagePtr nativeImage = m_contents->nativeImageForCurrentFrame();
+
+#if PLATFORM(SKIA)
+ // The layer contains an Image.
+ NativeImageSkia* skiaImage = static_cast<NativeImageSkia*>(nativeImage);
+ const SkBitmap* skiaBitmap = skiaImage;
+ bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height());
+ ASSERT(skiaBitmap);
+#elif PLATFORM(CG)
+ // NativeImagePtr is a CGImageRef on Mac OS X.
+ int width = CGImageGetWidth(nativeImage);
+ int height = CGImageGetHeight(nativeImage);
+ bitmapSize = IntSize(width, height);
+#endif
+
+ // Clip the dirty rect to the bitmap dimensions.
+ IntRect dirtyRect(m_dirtyRect);
+ dirtyRect.intersect(IntRect(IntPoint(0, 0), bitmapSize));
+
+ if (!m_contentsTexture || !m_contentsTexture->isValid(bitmapSize, GraphicsContext3D::RGBA))
+ dirtyRect = IntRect(IntPoint(0, 0), bitmapSize);
+ else if (!m_contentsDirty) {
+ m_contentsTexture->reserve(bitmapSize, GraphicsContext3D::RGBA);
+ return;
+ }
+
+#if PLATFORM(SKIA)
+ SkAutoLockPixels lock(*skiaBitmap);
+ SkBitmap::Config skiaConfig = skiaBitmap->config();
+ // FIXME: do we need to support more image configurations?
+ if (skiaConfig == SkBitmap::kARGB_8888_Config)
+ pixels = skiaBitmap->getPixels();
+#elif PLATFORM(CG)
+ // FIXME: we should get rid of this temporary copy where possible.
+ int tempRowBytes = width * 4;
+ Vector<uint8_t> tempVector;
+ tempVector.resize(height * tempRowBytes);
+ // Note we do not zero this vector since we are going to
+ // completely overwrite its contents with the image below.
+ // Try to reuse the color space from the image to preserve its colors.
+ // Some images use a color space (such as indexed) unsupported by the bitmap context.
+ RetainPtr<CGColorSpaceRef> colorSpaceReleaser;
+ CGColorSpaceRef colorSpace = CGImageGetColorSpace(nativeImage);
+ CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
+ switch (colorSpaceModel) {
+ case kCGColorSpaceModelMonochrome:
+ case kCGColorSpaceModelRGB:
+ case kCGColorSpaceModelCMYK:
+ case kCGColorSpaceModelLab:
+ case kCGColorSpaceModelDeviceN:
+ break;
+ default:
+ colorSpaceReleaser.adoptCF(CGColorSpaceCreateDeviceRGB());
+ colorSpace = colorSpaceReleaser.get();
+ break;
+ }
+ RetainPtr<CGContextRef> tempContext(AdoptCF, CGBitmapContextCreate(tempVector.data(),
+ width, height, 8, tempRowBytes,
+ colorSpace,
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+ CGContextSetBlendMode(tempContext.get(), kCGBlendModeCopy);
+ CGContextDrawImage(tempContext.get(),
+ CGRectMake(0, 0, static_cast<CGFloat>(width), static_cast<CGFloat>(height)),
+ nativeImage);
+ pixels = tempVector.data();
+#else
+#error "Need to implement for your platform."
+#endif
+
+ if (pixels)
+ updateTextureRect(pixels, bitmapSize, dirtyRect);
+}
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h
new file mode 100644
index 0000000..a5c1450
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 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 ImageLayerChromium_h
+#define ImageLayerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "ContentLayerChromium.h"
+
+#if PLATFORM(CG)
+#include <wtf/RetainPtr.h>
+#endif
+
+namespace WebCore {
+
+class Image;
+
+// A Layer that contains only an Image element.
+class ImageLayerChromium : public ContentLayerChromium {
+public:
+ static PassRefPtr<ImageLayerChromium> create(GraphicsLayerChromium* owner = 0);
+
+ virtual void updateContentsIfDirty();
+ virtual bool drawsContent() { return m_contents; }
+
+ void setContents(Image* image);
+
+private:
+ ImageLayerChromium(GraphicsLayerChromium* owner);
+
+ RefPtr<Image> m_contents;
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp
new file mode 100644
index 0000000..b7ab098
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "LayerChromium.h"
+
+#include "GraphicsContext3D.h"
+#include "LayerRendererChromium.h"
+#if PLATFORM(SKIA)
+#include "NativeImageSkia.h"
+#include "PlatformContextSkia.h"
+#endif
+#include "RenderLayerBacking.h"
+#include "skia/ext/platform_canvas.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+using namespace std;
+
+const unsigned LayerChromium::s_positionAttribLocation = 0;
+const unsigned LayerChromium::s_texCoordAttribLocation = 1;
+
+static unsigned loadShader(GraphicsContext3D* context, unsigned type, const char* shaderSource)
+{
+ unsigned shader = context->createShader(type);
+ if (!shader)
+ return 0;
+ String sourceString(shaderSource);
+ GLC(context, context->shaderSource(shader, sourceString));
+ GLC(context, context->compileShader(shader));
+ int compiled = 0;
+ GLC(context, context->getShaderiv(shader, GraphicsContext3D::COMPILE_STATUS, &compiled));
+ if (!compiled) {
+ GLC(context, context->deleteShader(shader));
+ return 0;
+ }
+ return shader;
+}
+
+LayerChromium::SharedValues::SharedValues(GraphicsContext3D* context)
+ : m_context(context)
+ , m_quadVerticesVbo(0)
+ , m_quadElementsVbo(0)
+ , m_maxTextureSize(0)
+ , m_borderShaderProgram(0)
+ , m_borderShaderMatrixLocation(-1)
+ , m_borderShaderColorLocation(-1)
+ , m_initialized(false)
+{
+ // Vertex positions and texture coordinates for the 4 corners of a 1x1 quad.
+ float vertices[] = { -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
+ -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
+ 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
+ 0.5f, 0.5f, 0.0f, 1.0f, 1.0f };
+ uint16_t indices[] = { 0, 1, 2, 0, 2, 3, // The two triangles that make up the layer quad.
+ 0, 1, 2, 3}; // A line path for drawing the layer border.
+
+ GLC(m_context, m_quadVerticesVbo = m_context->createBuffer());
+ GLC(m_context, m_quadElementsVbo = m_context->createBuffer());
+ GLC(m_context, m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVerticesVbo));
+ GLC(m_context, m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, sizeof(vertices), vertices, GraphicsContext3D::STATIC_DRAW));
+ GLC(m_context, m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_quadElementsVbo));
+ GLC(m_context, m_context->bufferData(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GraphicsContext3D::STATIC_DRAW));
+
+ // Get the max texture size supported by the system.
+ GLC(m_context, m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize));
+
+ // Shaders for drawing the debug borders around the layers.
+ char borderVertexShaderString[] =
+ "attribute vec4 a_position; \n"
+ "uniform mat4 matrix; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = matrix * a_position; \n"
+ "} \n";
+ char borderFragmentShaderString[] =
+ "precision mediump float; \n"
+ "uniform vec4 color; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = vec4(color.xyz * color.w, color.w);\n"
+ "} \n";
+
+ m_borderShaderProgram = createShaderProgram(m_context, borderVertexShaderString, borderFragmentShaderString);
+ if (!m_borderShaderProgram) {
+ LOG_ERROR("ContentLayerChromium: Failed to create shader program");
+ return;
+ }
+
+ m_borderShaderMatrixLocation = m_context->getUniformLocation(m_borderShaderProgram, "matrix");
+ m_borderShaderColorLocation = m_context->getUniformLocation(m_borderShaderProgram, "color");
+ ASSERT(m_borderShaderMatrixLocation != -1);
+ ASSERT(m_borderShaderColorLocation != -1);
+
+ m_initialized = true;
+}
+
+LayerChromium::SharedValues::~SharedValues()
+{
+ GLC(m_context, m_context->deleteBuffer(m_quadVerticesVbo));
+ GLC(m_context, m_context->deleteBuffer(m_quadElementsVbo));
+ if (m_borderShaderProgram)
+ GLC(m_context, m_context->deleteProgram(m_borderShaderProgram));
+}
+
+
+PassRefPtr<LayerChromium> LayerChromium::create(GraphicsLayerChromium* owner)
+{
+ return adoptRef(new LayerChromium(owner));
+}
+
+LayerChromium::LayerChromium(GraphicsLayerChromium* owner)
+ : m_owner(owner)
+ , m_contentsDirty(false)
+ , m_targetRenderSurface(0)
+ , m_superlayer(0)
+ , m_anchorPoint(0.5, 0.5)
+ , m_backgroundColor(0, 0, 0, 0)
+ , m_borderColor(0, 0, 0, 0)
+ , m_opacity(1.0)
+ , m_zPosition(0.0)
+ , m_anchorPointZ(0)
+ , m_borderWidth(0)
+ , m_clearsContext(false)
+ , m_doubleSided(true)
+ , m_hidden(false)
+ , m_masksToBounds(false)
+ , m_opaque(true)
+ , m_geometryFlipped(false)
+ , m_needsDisplayOnBoundsChange(false)
+ , m_drawDepth(0)
+ , m_layerRenderer(0)
+ , m_renderSurface(0)
+{
+}
+
+LayerChromium::~LayerChromium()
+{
+ // Our superlayer should be holding a reference to us so there should be no
+ // way for us to be destroyed while we still have a superlayer.
+ ASSERT(!superlayer());
+
+ // Remove the superlayer reference from all sublayers.
+ removeAllSublayers();
+}
+
+void LayerChromium::cleanupResources()
+{
+ if (m_renderSurface)
+ m_renderSurface->cleanupResources();
+}
+
+void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer)
+{
+ // If we're changing layer renderers then we need to free up any resources
+ // allocated by the old renderer.
+ if (layerRenderer() && layerRenderer() != renderer) {
+ cleanupResources();
+ setNeedsDisplay();
+ }
+
+ m_layerRenderer = renderer;
+}
+
+RenderSurfaceChromium* LayerChromium::createRenderSurface()
+{
+ m_renderSurface = new RenderSurfaceChromium(this);
+ return m_renderSurface.get();
+}
+
+unsigned LayerChromium::createShaderProgram(GraphicsContext3D* context, const char* vertexShaderSource, const char* fragmentShaderSource)
+{
+ unsigned vertexShader = loadShader(context, GraphicsContext3D::VERTEX_SHADER, vertexShaderSource);
+ if (!vertexShader) {
+ LOG_ERROR("Failed to create vertex shader");
+ return 0;
+ }
+
+ unsigned fragmentShader = loadShader(context, GraphicsContext3D::FRAGMENT_SHADER, fragmentShaderSource);
+ if (!fragmentShader) {
+ GLC(context, context->deleteShader(vertexShader));
+ LOG_ERROR("Failed to create fragment shader");
+ return 0;
+ }
+
+ unsigned programObject = context->createProgram();
+ if (!programObject) {
+ LOG_ERROR("Failed to create shader program");
+ return 0;
+ }
+
+ GLC(context, context->attachShader(programObject, vertexShader));
+ GLC(context, context->attachShader(programObject, fragmentShader));
+
+ // Bind the common attrib locations.
+ GLC(context, context->bindAttribLocation(programObject, s_positionAttribLocation, "a_position"));
+ GLC(context, context->bindAttribLocation(programObject, s_texCoordAttribLocation, "a_texCoord"));
+
+ GLC(context, context->linkProgram(programObject));
+ int linked = 0;
+ GLC(context, context->getProgramiv(programObject, GraphicsContext3D::LINK_STATUS, &linked));
+ if (!linked) {
+ LOG_ERROR("Failed to link shader program");
+ GLC(context, context->deleteProgram(programObject));
+ return 0;
+ }
+
+ GLC(context, context->deleteShader(vertexShader));
+ GLC(context, context->deleteShader(fragmentShader));
+ return programObject;
+}
+
+void LayerChromium::setNeedsCommit()
+{
+ // Call notifySyncRequired(), which for non-root layers plumbs through to
+ // call setRootLayerNeedsDisplay() on the WebView, which will cause LayerRendererChromium
+ // to render a frame.
+ // This function has no effect on root layers.
+ if (m_owner)
+ m_owner->notifySyncRequired();
+}
+
+void LayerChromium::addSublayer(PassRefPtr<LayerChromium> sublayer)
+{
+ insertSublayer(sublayer, numSublayers());
+}
+
+void LayerChromium::insertSublayer(PassRefPtr<LayerChromium> sublayer, size_t index)
+{
+ index = min(index, m_sublayers.size());
+ sublayer->removeFromSuperlayer();
+ sublayer->setSuperlayer(this);
+ m_sublayers.insert(index, sublayer);
+ setNeedsCommit();
+}
+
+void LayerChromium::removeFromSuperlayer()
+{
+ if (m_superlayer)
+ m_superlayer->removeSublayer(this);
+}
+
+void LayerChromium::removeSublayer(LayerChromium* sublayer)
+{
+ int foundIndex = indexOfSublayer(sublayer);
+ if (foundIndex == -1)
+ return;
+
+ sublayer->setSuperlayer(0);
+ m_sublayers.remove(foundIndex);
+ setNeedsCommit();
+}
+
+void LayerChromium::replaceSublayer(LayerChromium* reference, PassRefPtr<LayerChromium> newLayer)
+{
+ ASSERT_ARG(reference, reference);
+ ASSERT_ARG(reference, reference->superlayer() == this);
+
+ if (reference == newLayer)
+ return;
+
+ int referenceIndex = indexOfSublayer(reference);
+ if (referenceIndex == -1) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
+ reference->removeFromSuperlayer();
+
+ if (newLayer) {
+ newLayer->removeFromSuperlayer();
+ insertSublayer(newLayer, referenceIndex);
+ }
+}
+
+int LayerChromium::indexOfSublayer(const LayerChromium* reference)
+{
+ for (size_t i = 0; i < m_sublayers.size(); i++) {
+ if (m_sublayers[i] == reference)
+ return i;
+ }
+ return -1;
+}
+
+void LayerChromium::setBounds(const IntSize& size)
+{
+ if (m_bounds == size)
+ return;
+
+ bool firstResize = !m_bounds.width() && !m_bounds.height() && size.width() && size.height();
+
+ m_bounds = size;
+ m_backingStoreSize = size;
+
+ if (firstResize)
+ setNeedsDisplay(FloatRect(0, 0, m_bounds.width(), m_bounds.height()));
+ else
+ setNeedsCommit();
+}
+
+void LayerChromium::setFrame(const FloatRect& rect)
+{
+ if (rect == m_frame)
+ return;
+
+ m_frame = rect;
+ setNeedsDisplay(FloatRect(0, 0, m_bounds.width(), m_bounds.height()));
+}
+
+const LayerChromium* LayerChromium::rootLayer() const
+{
+ const LayerChromium* layer = this;
+ for (LayerChromium* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { }
+ return layer;
+}
+
+void LayerChromium::removeAllSublayers()
+{
+ while (m_sublayers.size()) {
+ LayerChromium* layer = m_sublayers[0].get();
+ ASSERT(layer->superlayer());
+ layer->removeFromSuperlayer();
+ }
+}
+
+void LayerChromium::setSublayers(const Vector<RefPtr<LayerChromium> >& sublayers)
+{
+ if (sublayers == m_sublayers)
+ return;
+
+ removeAllSublayers();
+ size_t listSize = sublayers.size();
+ for (size_t i = 0; i < listSize; i++)
+ addSublayer(sublayers[i]);
+}
+
+LayerChromium* LayerChromium::superlayer() const
+{
+ return m_superlayer;
+}
+
+void LayerChromium::setNeedsDisplay(const FloatRect& dirtyRect)
+{
+ // Simply mark the contents as dirty. For non-root layers, the call to
+ // setNeedsCommit will schedule a fresh compositing pass.
+ // For the root layer, setNeedsCommit has no effect.
+ m_contentsDirty = true;
+
+ m_dirtyRect.unite(dirtyRect);
+ setNeedsCommit();
+}
+
+void LayerChromium::setNeedsDisplay()
+{
+ m_dirtyRect.setLocation(FloatPoint());
+ m_dirtyRect.setSize(m_bounds);
+ m_contentsDirty = true;
+ setNeedsCommit();
+}
+
+void LayerChromium::resetNeedsDisplay()
+{
+ m_dirtyRect = FloatRect();
+ m_contentsDirty = false;
+}
+
+void LayerChromium::toGLMatrix(float* flattened, const TransformationMatrix& m)
+{
+ flattened[0] = m.m11();
+ flattened[1] = m.m12();
+ flattened[2] = m.m13();
+ flattened[3] = m.m14();
+ flattened[4] = m.m21();
+ flattened[5] = m.m22();
+ flattened[6] = m.m23();
+ flattened[7] = m.m24();
+ flattened[8] = m.m31();
+ flattened[9] = m.m32();
+ flattened[10] = m.m33();
+ flattened[11] = m.m34();
+ flattened[12] = m.m41();
+ flattened[13] = m.m42();
+ flattened[14] = m.m43();
+ flattened[15] = m.m44();
+}
+
+GraphicsContext3D* LayerChromium::layerRendererContext() const
+{
+ ASSERT(layerRenderer());
+ return layerRenderer()->context();
+}
+
+void LayerChromium::drawTexturedQuad(GraphicsContext3D* context, const TransformationMatrix& projectionMatrix, const TransformationMatrix& drawMatrix,
+ float width, float height, float opacity,
+ int matrixLocation, int alphaLocation)
+{
+ static float glMatrix[16];
+
+ TransformationMatrix renderMatrix = drawMatrix;
+
+ // Apply a scaling factor to size the quad from 1x1 to its intended size.
+ renderMatrix.scale3d(width, height, 1);
+
+ // Apply the projection matrix before sending the transform over to the shader.
+ renderMatrix.multiply(projectionMatrix);
+
+ toGLMatrix(&glMatrix[0], renderMatrix);
+
+ GLC(context, context->uniformMatrix4fv(matrixLocation, false, &glMatrix[0], 1));
+
+ if (alphaLocation != -1)
+ GLC(context, context->uniform1f(alphaLocation, opacity));
+
+ GLC(context, context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0));
+}
+
+void LayerChromium::drawDebugBorder()
+{
+ static float glMatrix[16];
+ if (!borderColor().alpha())
+ return;
+
+ ASSERT(layerRenderer());
+ const SharedValues* sv = layerRenderer()->layerSharedValues();
+ ASSERT(sv && sv->initialized());
+ layerRenderer()->useShader(sv->borderShaderProgram());
+ TransformationMatrix renderMatrix = drawTransform();
+ renderMatrix.scale3d(bounds().width(), bounds().height(), 1);
+ renderMatrix.multiply(layerRenderer()->projectionMatrix());
+ toGLMatrix(&glMatrix[0], renderMatrix);
+ GraphicsContext3D* context = layerRendererContext();
+ GLC(context, context->uniformMatrix4fv(sv->borderShaderMatrixLocation(), false, &glMatrix[0], 1));
+
+ GLC(context, context->uniform4f(sv->borderShaderColorLocation(), borderColor().red() / 255.0, borderColor().green() / 255.0, borderColor().blue() / 255.0, 1));
+
+ GLC(context, context->lineWidth(borderWidth()));
+
+ // The indices for the line are stored in the same array as the triangle indices.
+ GLC(context, context->drawElements(GraphicsContext3D::LINE_LOOP, 4, GraphicsContext3D::UNSIGNED_SHORT, 6 * sizeof(unsigned short)));
+}
+
+const IntRect LayerChromium::getDrawRect() const
+{
+ // Form the matrix used by the shader to map the corners of the layer's
+ // bounds into the view space.
+ FloatRect layerRect(-0.5 * bounds().width(), -0.5 * bounds().height(), bounds().width(), bounds().height());
+ IntRect mappedRect = enclosingIntRect(drawTransform().mapRect(layerRect));
+ return mappedRect;
+}
+
+// Returns true if any of the layer's descendants has drawable content.
+bool LayerChromium::descendantsDrawContent()
+{
+ const Vector<RefPtr<LayerChromium> >& sublayers = getSublayers();
+ for (size_t i = 0; i < sublayers.size(); ++i)
+ if (sublayers[i]->descendantsDrawContentRecursive())
+ return true;
+ return false;
+}
+
+// Returns true if either this layer or one of its descendants has drawable content.
+bool LayerChromium::descendantsDrawContentRecursive()
+{
+ if (drawsContent())
+ return true;
+
+ const Vector<RefPtr<LayerChromium> >& sublayers = getSublayers();
+ for (size_t i = 0; i < sublayers.size(); ++i)
+ if (sublayers[i]->descendantsDrawContentRecursive())
+ return true;
+ return false;
+}
+
+// static
+void LayerChromium::prepareForDraw(const SharedValues* sv)
+{
+ GraphicsContext3D* context = sv->context();
+ GLC(context, context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, sv->quadVerticesVbo()));
+ GLC(context, context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, sv->quadElementsVbo()));
+ unsigned offset = 0;
+ GLC(context, context->vertexAttribPointer(s_positionAttribLocation, 3, GraphicsContext3D::FLOAT, false, 5 * sizeof(float), offset));
+ offset += 3 * sizeof(float);
+ GLC(context, context->vertexAttribPointer(s_texCoordAttribLocation, 2, GraphicsContext3D::FLOAT, false, 5 * sizeof(float), offset));
+ GLC(context, context->enableVertexAttribArray(s_positionAttribLocation));
+ GLC(context, context->enableVertexAttribArray(s_texCoordAttribLocation));
+}
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerChromium.h
new file mode 100644
index 0000000..a0a690f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 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 LayerChromium_h
+#define LayerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "FloatPoint.h"
+#include "GraphicsContext.h"
+#include "GraphicsLayerChromium.h"
+#include "PlatformString.h"
+#include "RenderSurfaceChromium.h"
+#include "TransformationMatrix.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+
+namespace skia {
+class PlatformCanvas;
+}
+
+namespace WebCore {
+
+class GraphicsContext3D;
+class LayerRendererChromium;
+
+// Base class for composited layers. Special layer types are derived from
+// this class.
+class LayerChromium : public RefCounted<LayerChromium> {
+ friend class LayerRendererChromium;
+ friend class LayerTilerChromium;
+public:
+ static PassRefPtr<LayerChromium> create(GraphicsLayerChromium* owner = 0);
+
+ virtual ~LayerChromium();
+
+ const LayerChromium* rootLayer() const;
+ LayerChromium* superlayer() const;
+ void addSublayer(PassRefPtr<LayerChromium>);
+ void insertSublayer(PassRefPtr<LayerChromium>, size_t index);
+ void replaceSublayer(LayerChromium* reference, PassRefPtr<LayerChromium> newLayer);
+ void removeFromSuperlayer();
+ void removeAllSublayers();
+ void setSublayers(const Vector<RefPtr<LayerChromium> >&);
+ const Vector<RefPtr<LayerChromium> >& getSublayers() const { return m_sublayers; }
+
+ void setAnchorPoint(const FloatPoint& anchorPoint) { m_anchorPoint = anchorPoint; setNeedsCommit(); }
+ FloatPoint anchorPoint() const { return m_anchorPoint; }
+
+ void setAnchorPointZ(float anchorPointZ) { m_anchorPointZ = anchorPointZ; setNeedsCommit(); }
+ float anchorPointZ() const { return m_anchorPointZ; }
+
+ void setBackgroundColor(const Color& color) { m_backgroundColor = color; setNeedsCommit(); }
+ Color backgroundColor() const { return m_backgroundColor; }
+
+ void setBorderColor(const Color& color) { m_borderColor = color; setNeedsCommit(); }
+ Color borderColor() const { return m_borderColor; }
+
+ void setBorderWidth(float width) { m_borderWidth = width; setNeedsCommit(); }
+ float borderWidth() const { return m_borderWidth; }
+
+ void setBounds(const IntSize&);
+ IntSize bounds() const { return m_bounds; }
+
+ void setClearsContext(bool clears) { m_clearsContext = clears; setNeedsCommit(); }
+ bool clearsContext() const { return m_clearsContext; }
+
+ void setDoubleSided(bool doubleSided) { m_doubleSided = doubleSided; setNeedsCommit(); }
+ bool doubleSided() const { return m_doubleSided; }
+
+ void setFrame(const FloatRect&);
+ FloatRect frame() const { return m_frame; }
+
+ void setHidden(bool hidden) { m_hidden = hidden; setNeedsCommit(); }
+ bool isHidden() const { return m_hidden; }
+
+ void setMasksToBounds(bool masksToBounds) { m_masksToBounds = masksToBounds; }
+ bool masksToBounds() const { return m_masksToBounds; }
+
+ void setName(const String& name) { m_name = name; }
+ String name() const { return m_name; }
+
+ void setNeedsDisplay(const FloatRect& dirtyRect);
+ void setNeedsDisplay();
+ const FloatRect& dirtyRect() const { return m_dirtyRect; }
+ void resetNeedsDisplay();
+
+ void setNeedsDisplayOnBoundsChange(bool needsDisplay) { m_needsDisplayOnBoundsChange = needsDisplay; }
+
+ void setOpacity(float opacity) { m_opacity = opacity; setNeedsCommit(); }
+ float opacity() const { return m_opacity; }
+
+ void setOpaque(bool opaque) { m_opaque = opaque; setNeedsCommit(); }
+ bool opaque() const { return m_opaque; }
+
+ void setPosition(const FloatPoint& position) { m_position = position; setNeedsCommit(); }
+ FloatPoint position() const { return m_position; }
+
+ void setZPosition(float zPosition) { m_zPosition = zPosition; setNeedsCommit(); }
+ float zPosition() const { return m_zPosition; }
+
+ void setSublayerTransform(const TransformationMatrix& transform) { m_sublayerTransform = transform; setNeedsCommit(); }
+ const TransformationMatrix& sublayerTransform() const { return m_sublayerTransform; }
+
+ void setTransform(const TransformationMatrix& transform) { m_transform = transform; setNeedsCommit(); }
+ const TransformationMatrix& transform() const { return m_transform; }
+
+ // FIXME: This setting is currently ignored.
+ void setGeometryFlipped(bool flipped) { m_geometryFlipped = flipped; setNeedsCommit(); }
+ bool geometryFlipped() const { return m_geometryFlipped; }
+
+ const TransformationMatrix& drawTransform() const { return m_drawTransform; }
+ float drawOpacity() const { return m_drawOpacity; }
+
+ bool preserves3D() { return m_owner && m_owner->preserves3D(); }
+
+ // Derived types must override this method if they need to react to a change
+ // in the LayerRendererChromium.
+ virtual void setLayerRenderer(LayerRendererChromium*);
+
+ void setOwner(GraphicsLayerChromium* owner) { m_owner = owner; }
+
+ // Returns the rect containtaining this layer in the current view's coordinate system.
+ const IntRect getDrawRect() const;
+
+ // These methods typically need to be overwritten by derived classes.
+ virtual bool drawsContent() { return false; }
+ virtual void updateContentsIfDirty() { }
+ virtual void draw() { }
+
+ void drawDebugBorder();
+
+ RenderSurfaceChromium* createRenderSurface();
+
+ // Stores values that are shared between instances of this class that are
+ // associated with the same LayerRendererChromium (and hence the same GL
+ // context).
+ class SharedValues {
+ public:
+ explicit SharedValues(GraphicsContext3D*);
+ ~SharedValues();
+
+ GraphicsContext3D* context() const { return m_context; }
+ unsigned quadVerticesVbo() const { return m_quadVerticesVbo; }
+ unsigned quadElementsVbo() const { return m_quadElementsVbo; }
+ int maxTextureSize() const { return m_maxTextureSize; }
+ unsigned borderShaderProgram() const { return m_borderShaderProgram; }
+ int borderShaderMatrixLocation() const { return m_borderShaderMatrixLocation; }
+ int borderShaderColorLocation() const { return m_borderShaderColorLocation; }
+ bool initialized() const { return m_initialized; }
+
+ private:
+ GraphicsContext3D* m_context;
+ unsigned m_quadVerticesVbo;
+ unsigned m_quadElementsVbo;
+ int m_maxTextureSize;
+ unsigned m_borderShaderProgram;
+ int m_borderShaderMatrixLocation;
+ int m_borderShaderColorLocation;
+ bool m_initialized;
+ };
+
+ static void prepareForDraw(const SharedValues*);
+
+ LayerRendererChromium* layerRenderer() const { return m_layerRenderer.get(); }
+
+ static unsigned createShaderProgram(GraphicsContext3D*, const char* vertexShaderSource, const char* fragmentShaderSource);
+
+ static void drawTexturedQuad(GraphicsContext3D*, const TransformationMatrix& projectionMatrix, const TransformationMatrix& layerMatrix,
+ float width, float height, float opacity,
+ int matrixLocation, int alphaLocation);
+
+protected:
+ GraphicsLayerChromium* m_owner;
+ LayerChromium(GraphicsLayerChromium* owner);
+
+ // This is called to clean up resources being held in the same context as
+ // layerRendererContext(). Subclasses should override this method if they
+ // hold context-dependent resources such as textures.
+ virtual void cleanupResources();
+
+ GraphicsContext3D* layerRendererContext() const;
+
+ // Returns true if any of the layer's descendants has content to draw.
+ bool descendantsDrawContent();
+
+ static void toGLMatrix(float*, const TransformationMatrix&);
+
+ IntSize m_bounds;
+ FloatRect m_dirtyRect;
+ bool m_contentsDirty;
+
+ // Render surface this layer draws into. This is a surface that can belong
+ // either to this layer (if m_targetRenderSurface == m_renderSurface) or
+ // to an ancestor of this layer. The target render surface determines the
+ // coordinate system the layer's transforms are relative to.
+ RenderSurfaceChromium* m_targetRenderSurface;
+
+ // All layer shaders share the same attribute locations for the vertex positions
+ // and texture coordinates. This allows switching shaders without rebinding attribute
+ // arrays.
+ static const unsigned s_positionAttribLocation;
+ static const unsigned s_texCoordAttribLocation;
+
+private:
+ void setNeedsCommit();
+
+ void setSuperlayer(LayerChromium* superlayer) { m_superlayer = superlayer; }
+
+ size_t numSublayers() const
+ {
+ return m_sublayers.size();
+ }
+
+ // Returns the index of the sublayer or -1 if not found.
+ int indexOfSublayer(const LayerChromium*);
+
+ // This should only be called from removeFromSuperlayer.
+ void removeSublayer(LayerChromium*);
+
+ bool descendantsDrawContentRecursive();
+
+ Vector<RefPtr<LayerChromium> > m_sublayers;
+ LayerChromium* m_superlayer;
+
+ // Layer properties.
+ IntSize m_backingStoreSize;
+ FloatPoint m_position;
+ FloatPoint m_anchorPoint;
+ Color m_backgroundColor;
+ Color m_borderColor;
+ float m_opacity;
+ float m_zPosition;
+ float m_anchorPointZ;
+ float m_borderWidth;
+ float m_drawOpacity;
+ bool m_clearsContext;
+ bool m_doubleSided;
+ bool m_hidden;
+ bool m_masksToBounds;
+ bool m_opaque;
+ bool m_geometryFlipped;
+ bool m_needsDisplayOnBoundsChange;
+
+ // The global depth value of the center of the layer. This value is used
+ // to sort layers from back to front.
+ float m_drawDepth;
+
+ // Points to the layer renderer that updates and draws this layer.
+ RefPtr<LayerRendererChromium> m_layerRenderer;
+
+ FloatRect m_frame;
+ TransformationMatrix m_transform;
+ TransformationMatrix m_sublayerTransform;
+ TransformationMatrix m_drawTransform;
+
+ // The scissor rectangle that should be used when this layer is drawn.
+ // Inherited by the parent layer and further restricted if this layer masks
+ // to bounds.
+ IntRect m_scissorRect;
+
+ // Render surface associated with this layer. The layer and its descendants
+ // will render to this surface.
+ OwnPtr<RenderSurfaceChromium> m_renderSurface;
+
+ // Hierarchical bounding rect containing the layer and its descendants.
+ IntRect m_drawableContentRect;
+
+ String m_name;
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
new file mode 100644
index 0000000..8d77bea
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
@@ -0,0 +1,803 @@
+/*
+ * Copyright (C) 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.
+ */
+
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "LayerRendererChromium.h"
+
+#include "Canvas2DLayerChromium.h"
+#include "GraphicsContext3D.h"
+#include "LayerChromium.h"
+#include "LayerTexture.h"
+#include "NotImplemented.h"
+#include "TextureManager.h"
+#include "WebGLLayerChromium.h"
+#if PLATFORM(SKIA)
+#include "NativeImageSkia.h"
+#include "PlatformContextSkia.h"
+#elif PLATFORM(CG)
+#include <CoreGraphics/CGBitmapContext.h>
+#endif
+
+namespace WebCore {
+
+// FIXME: Make this limit adjustable and give it a useful value.
+static size_t textureMemoryLimitBytes = 64 * 1024 * 1024;
+
+static TransformationMatrix orthoMatrix(float left, float right, float bottom, float top)
+{
+ float deltaX = right - left;
+ float deltaY = top - bottom;
+ TransformationMatrix ortho;
+ if (!deltaX || !deltaY)
+ return ortho;
+ ortho.setM11(2.0f / deltaX);
+ ortho.setM41(-(right + left) / deltaX);
+ ortho.setM22(2.0f / deltaY);
+ ortho.setM42(-(top + bottom) / deltaY);
+
+ // Z component of vertices is always set to zero as we don't use the depth buffer
+ // while drawing.
+ ortho.setM33(0);
+
+ return ortho;
+}
+
+// Returns true if the matrix has no rotation, skew or perspective components to it.
+static bool isScaleOrTranslation(const TransformationMatrix& m)
+{
+ return !m.m12() && !m.m13() && !m.m14()
+ && !m.m21() && !m.m23() && !m.m24()
+ && !m.m31() && !m.m32() && !m.m43()
+ && m.m44();
+
+}
+
+bool LayerRendererChromium::compareLayerZ(const LayerChromium* a, const LayerChromium* b)
+{
+ return a->m_drawDepth < b->m_drawDepth;
+}
+
+PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context)
+{
+ if (!context)
+ return 0;
+
+ RefPtr<LayerRendererChromium> layerRenderer(adoptRef(new LayerRendererChromium(context)));
+ if (!layerRenderer->hardwareCompositing())
+ return 0;
+
+ return layerRenderer.release();
+}
+
+LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context)
+ : m_rootLayerTextureWidth(0)
+ , m_rootLayerTextureHeight(0)
+ , m_rootLayer(0)
+ , m_scrollPosition(IntPoint(-1, -1))
+ , m_currentShader(0)
+ , m_currentRenderSurface(0)
+ , m_offscreenFramebufferId(0)
+ , m_compositeOffscreen(false)
+ , m_context(context)
+ , m_defaultRenderSurface(0)
+{
+ m_hardwareCompositing = initializeSharedObjects();
+ m_rootLayerTiler = LayerTilerChromium::create(this, IntSize(256, 256));
+ ASSERT(m_rootLayerTiler);
+}
+
+LayerRendererChromium::~LayerRendererChromium()
+{
+ cleanupSharedObjects();
+
+ // Because the tilers need to clean up textures, clean them up explicitly
+ // before the GraphicsContext3D is destroyed.
+ m_rootLayerTiler.clear();
+ m_horizontalScrollbarTiler.clear();
+ m_verticalScrollbarTiler.clear();
+}
+
+GraphicsContext3D* LayerRendererChromium::context()
+{
+ return m_context.get();
+}
+
+void LayerRendererChromium::debugGLCall(GraphicsContext3D* context, const char* command, const char* file, int line)
+{
+ unsigned long error = context->getError();
+ if (error != GraphicsContext3D::NO_ERROR)
+ LOG_ERROR("GL command failed: File: %s\n\tLine %d\n\tcommand: %s, error %x\n", file, line, command, static_cast<int>(error));
+}
+
+void LayerRendererChromium::useShader(unsigned programId)
+{
+ if (programId != m_currentShader) {
+ GLC(m_context.get(), m_context->useProgram(programId));
+ m_currentShader = programId;
+ }
+}
+
+IntRect LayerRendererChromium::verticalScrollbarRect(const IntRect& visibleRect, const IntRect& contentRect)
+{
+ IntRect verticalScrollbar(IntPoint(contentRect.right(), contentRect.y()), IntSize(visibleRect.width() - contentRect.width(), visibleRect.height()));
+ return verticalScrollbar;
+}
+
+IntRect LayerRendererChromium::horizontalScrollbarRect(const IntRect& visibleRect, const IntRect& contentRect)
+{
+ IntRect horizontalScrollbar(IntPoint(contentRect.x(), contentRect.bottom()), IntSize(visibleRect.width(), visibleRect.height() - contentRect.height()));
+ return horizontalScrollbar;
+}
+
+void LayerRendererChromium::invalidateRootLayerRect(const IntRect& dirtyRect, const IntRect& visibleRect, const IntRect& contentRect)
+{
+ if (contentRect.intersects(dirtyRect))
+ m_rootLayerTiler->invalidateRect(dirtyRect);
+ if (m_horizontalScrollbarTiler) {
+ IntRect scrollbar = horizontalScrollbarRect(visibleRect, contentRect);
+ if (dirtyRect.intersects(scrollbar)) {
+ m_horizontalScrollbarTiler->setLayerPosition(scrollbar.location());
+ m_horizontalScrollbarTiler->invalidateRect(dirtyRect);
+ }
+ }
+ if (m_verticalScrollbarTiler) {
+ IntRect scrollbar = verticalScrollbarRect(visibleRect, contentRect);
+ if (dirtyRect.intersects(scrollbar)) {
+ m_verticalScrollbarTiler->setLayerPosition(scrollbar.location());
+ m_verticalScrollbarTiler->invalidateRect(dirtyRect);
+ }
+ }
+}
+
+void LayerRendererChromium::updateAndDrawRootLayer(TilePaintInterface& tilePaint, TilePaintInterface& scrollbarPaint, const IntRect& visibleRect, const IntRect& contentRect)
+{
+ m_rootLayerTiler->update(tilePaint, visibleRect);
+ m_rootLayerTiler->draw(visibleRect);
+
+ if (visibleRect.width() > contentRect.width()) {
+ IntRect verticalScrollbar = verticalScrollbarRect(visibleRect, contentRect);
+ IntSize tileSize = verticalScrollbar.size().shrunkTo(IntSize(m_maxTextureSize, m_maxTextureSize));
+ if (!m_verticalScrollbarTiler)
+ m_verticalScrollbarTiler = LayerTilerChromium::create(this, tileSize);
+ else
+ m_verticalScrollbarTiler->setTileSize(tileSize);
+ m_verticalScrollbarTiler->setLayerPosition(verticalScrollbar.location());
+ m_verticalScrollbarTiler->update(scrollbarPaint, visibleRect);
+ m_verticalScrollbarTiler->draw(visibleRect);
+ }
+
+ if (visibleRect.height() > contentRect.height()) {
+ IntRect horizontalScrollbar = horizontalScrollbarRect(visibleRect, contentRect);
+ IntSize tileSize = horizontalScrollbar.size().shrunkTo(IntSize(m_maxTextureSize, m_maxTextureSize));
+ if (!m_horizontalScrollbarTiler)
+ m_horizontalScrollbarTiler = LayerTilerChromium::create(this, tileSize);
+ else
+ m_horizontalScrollbarTiler->setTileSize(tileSize);
+ m_horizontalScrollbarTiler->setLayerPosition(horizontalScrollbar.location());
+ m_horizontalScrollbarTiler->update(scrollbarPaint, visibleRect);
+ m_horizontalScrollbarTiler->draw(visibleRect);
+ }
+}
+
+void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect& contentRect,
+ const IntPoint& scrollPosition, TilePaintInterface& tilePaint,
+ TilePaintInterface& scrollbarPaint)
+{
+ ASSERT(m_hardwareCompositing);
+
+ if (!m_rootLayer)
+ return;
+
+ makeContextCurrent();
+
+ // If the size of the visible area has changed then allocate a new texture
+ // to store the contents of the root layer and adjust the projection matrix
+ // and viewport.
+ int visibleRectWidth = visibleRect.width();
+ int visibleRectHeight = visibleRect.height();
+
+ if (!m_rootLayer->m_renderSurface)
+ m_rootLayer->createRenderSurface();
+ m_rootLayer->m_renderSurface->m_contentRect = IntRect(0, 0, visibleRectWidth, visibleRectHeight);
+
+ if (visibleRectWidth != m_rootLayerTextureWidth || visibleRectHeight != m_rootLayerTextureHeight) {
+ m_rootLayerTextureWidth = visibleRectWidth;
+ m_rootLayerTextureHeight = visibleRectHeight;
+
+ // Reset the current render surface to force an update of the viewport and
+ // projection matrix next time useRenderSurface is called.
+ m_currentRenderSurface = 0;
+ }
+
+ // The GL viewport covers the entire visible area, including the scrollbars.
+ GLC(m_context.get(), m_context->viewport(0, 0, visibleRectWidth, visibleRectHeight));
+
+ // Bind the common vertex attributes used for drawing all the layers.
+ LayerChromium::prepareForDraw(layerSharedValues());
+
+ // FIXME: These calls can be made once, when the compositor context is initialized.
+ GLC(m_context.get(), m_context->disable(GraphicsContext3D::DEPTH_TEST));
+ GLC(m_context.get(), m_context->disable(GraphicsContext3D::CULL_FACE));
+
+ // Blending disabled by default. Root layer alpha channel on Windows is incorrect when Skia uses ClearType.
+ GLC(m_context.get(), m_context->disable(GraphicsContext3D::BLEND));
+
+ m_scrollPosition = scrollPosition;
+
+ ASSERT(m_rootLayer->m_renderSurface);
+ m_defaultRenderSurface = m_rootLayer->m_renderSurface.get();
+
+ useRenderSurface(m_defaultRenderSurface);
+
+ // Clear to blue to make it easier to spot unrendered regions.
+ m_context->clearColor(0, 0, 1, 1);
+ m_context->colorMask(true, true, true, true);
+ m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
+ // Mask out writes to alpha channel: subpixel antialiasing via Skia results in invalid
+ // zero alpha values on text glyphs. The root layer is always opaque.
+ m_context->colorMask(true, true, true, false);
+
+ updateAndDrawRootLayer(tilePaint, scrollbarPaint, visibleRect, contentRect);
+
+ // Set the root visible/content rects --- used by subsequent drawLayers calls.
+ m_rootVisibleRect = visibleRect;
+ m_rootContentRect = contentRect;
+
+ // Scissor out the scrollbars to avoid rendering on top of them.
+ IntRect rootScissorRect(contentRect);
+ // The scissorRect should not include the scroll offset.
+ rootScissorRect.move(-m_scrollPosition.x(), -m_scrollPosition.y());
+ m_rootLayer->m_scissorRect = rootScissorRect;
+
+ Vector<LayerChromium*> renderSurfaceLayerList;
+ renderSurfaceLayerList.append(m_rootLayer.get());
+
+ TransformationMatrix identityMatrix;
+ m_defaultRenderSurface->m_layerList.clear();
+ updateLayersRecursive(m_rootLayer.get(), identityMatrix, renderSurfaceLayerList, m_defaultRenderSurface->m_layerList);
+
+ // The shader used to render layers returns pre-multiplied alpha colors
+ // so we need to send the blending mode appropriately.
+ GLC(m_context.get(), m_context->enable(GraphicsContext3D::BLEND));
+ GLC(m_context.get(), m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
+ GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST));
+
+ // Update the contents of the render surfaces. We traverse the array from
+ // back to front to guarantee that nested render surfaces get rendered in the
+ // correct order.
+ for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
+ LayerChromium* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex];
+ ASSERT(renderSurfaceLayer->m_renderSurface);
+
+ // Render surfaces whose drawable area has zero width or height
+ // will have no layers associated with them and should be skipped.
+ if (!renderSurfaceLayer->m_renderSurface->m_layerList.size())
+ continue;
+
+ if (useRenderSurface(renderSurfaceLayer->m_renderSurface.get())) {
+ if (renderSurfaceLayer != m_rootLayer) {
+ GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));
+ GLC(m_context.get(), m_context->clearColor(0, 0, 0, 0));
+ GLC(m_context.get(), m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT));
+ GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST));
+ }
+
+ Vector<LayerChromium*>& layerList = renderSurfaceLayer->m_renderSurface->m_layerList;
+ ASSERT(layerList.size());
+ for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex)
+ drawLayer(layerList[layerIndex], renderSurfaceLayer->m_renderSurface.get());
+ }
+ }
+
+ GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));
+ GLC(m_context.get(), m_context->disable(GraphicsContext3D::BLEND));
+}
+
+void LayerRendererChromium::finish()
+{
+ m_context->finish();
+}
+
+void LayerRendererChromium::present()
+{
+ // We're done! Time to swapbuffers!
+
+ // Note that currently this has the same effect as swapBuffers; we should
+ // consider exposing a different entry point on GraphicsContext3D.
+ m_context->prepareTexture();
+}
+
+void LayerRendererChromium::setRootLayer(PassRefPtr<LayerChromium> layer)
+{
+ m_rootLayer = layer;
+ m_rootLayerTiler->invalidateEntireLayer();
+ if (m_horizontalScrollbarTiler)
+ m_horizontalScrollbarTiler->invalidateEntireLayer();
+ if (m_verticalScrollbarTiler)
+ m_verticalScrollbarTiler->invalidateEntireLayer();
+}
+
+void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& rect)
+{
+ ASSERT(rect.right() <= rootLayerTextureSize().width()
+ && rect.bottom() <= rootLayerTextureSize().height());
+
+ if (!pixels)
+ return;
+
+ makeContextCurrent();
+
+ GLC(m_context.get(), m_context->readPixels(rect.x(), rect.y(), rect.width(), rect.height(),
+ GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels));
+}
+
+// FIXME: This method should eventually be replaced by a proper texture manager.
+unsigned LayerRendererChromium::createLayerTexture()
+{
+ unsigned textureId = 0;
+ GLC(m_context.get(), textureId = m_context->createTexture());
+ GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
+ // Do basic linear filtering on resize.
+ GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
+ GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
+ // NPOT textures in GL ES only work when the wrap mode is set to GraphicsContext3D::CLAMP_TO_EDGE.
+ GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
+ GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));
+ return textureId;
+}
+
+void LayerRendererChromium::deleteLayerTexture(unsigned textureId)
+{
+ if (!textureId)
+ return;
+
+ GLC(m_context.get(), m_context->deleteTexture(textureId));
+}
+
+// Returns true if any part of the layer falls within the visibleRect
+bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const TransformationMatrix& matrix, const IntRect& visibleRect)
+{
+ // Form the matrix used by the shader to map the corners of the layer's
+ // bounds into clip space.
+ TransformationMatrix renderMatrix = matrix;
+ renderMatrix.scale3d(layer->bounds().width(), layer->bounds().height(), 1);
+ renderMatrix.multiply(m_projectionMatrix);
+
+ FloatRect layerRect(-0.5, -0.5, 1, 1);
+ FloatRect mappedRect = renderMatrix.mapRect(layerRect);
+
+ // The layer is visible if it intersects any part of a rectangle whose origin
+ // is at (-1, -1) and size is 2x2.
+ return mappedRect.intersects(FloatRect(-1, -1, 2, 2));
+}
+
+// Recursively walks the layer tree starting at the given node and computes all the
+// necessary transformations, scissor rectangles, render surfaces, etc.
+void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, Vector<LayerChromium*>& renderSurfaceLayerList, Vector<LayerChromium*>& layerList)
+{
+ layer->setLayerRenderer(this);
+
+ // Compute the new matrix transformation that will be applied to this layer and
+ // all its sublayers. It's important to remember that the layer's position
+ // is the position of the layer's anchor point. Also, the coordinate system used
+ // assumes that the origin is at the lower left even though the coordinates the browser
+ // gives us for the layers are for the upper left corner. The Y flip happens via
+ // the orthographic projection applied at render time.
+ // The transformation chain for the layer is (using the Matrix x Vector order):
+ // M = M[p] * Tr[l] * M[l] * Tr[c]
+ // Where M[p] is the parent matrix passed down to the function
+ // Tr[l] is the translation matrix locating the layer's anchor point
+ // Tr[c] is the translation offset between the anchor point and the center of the layer
+ // M[l] is the layer's matrix (applied at the anchor point)
+ // This transform creates a coordinate system whose origin is the center of the layer.
+ // Note that the final matrix used by the shader for the layer is P * M * S . This final product
+ // is computed in drawTexturedQuad().
+ // Where: P is the projection matrix
+ // M is the layer's matrix computed above
+ // S is the scale adjustment (to scale up to the layer size)
+ IntSize bounds = layer->bounds();
+ FloatPoint anchorPoint = layer->anchorPoint();
+ FloatPoint position = layer->position();
+
+ // Offset between anchor point and the center of the quad.
+ float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width();
+ float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height();
+
+ TransformationMatrix layerLocalTransform;
+ // LT = Tr[l]
+ layerLocalTransform.translate3d(position.x(), position.y(), layer->anchorPointZ());
+ // LT = Tr[l] * M[l]
+ layerLocalTransform.multLeft(layer->transform());
+ // LT = Tr[l] * M[l] * Tr[c]
+ layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());
+
+ TransformationMatrix combinedTransform = parentMatrix;
+ combinedTransform = combinedTransform.multLeft(layerLocalTransform);
+
+ FloatRect layerRect(-0.5 * layer->bounds().width(), -0.5 * layer->bounds().height(), layer->bounds().width(), layer->bounds().height());
+ IntRect transformedLayerRect;
+
+ // The layer and its descendants render on a new RenderSurface if any of
+ // these conditions hold:
+ // 1. The layer clips its descendants and its transform is not a simple translation.
+ // 2. If the layer has opacity != 1 and does not have a preserves-3d transform style.
+ // If a layer preserves-3d then we don't create a RenderSurface for it to avoid flattening
+ // out its children. The opacity value of the children layers is multiplied by the opacity
+ // of their parent.
+ bool useSurfaceForClipping = layer->masksToBounds() && !isScaleOrTranslation(combinedTransform);
+ bool useSurfaceForOpacity = layer->opacity() != 1 && !layer->preserves3D();
+ if ((useSurfaceForClipping || useSurfaceForOpacity) && layer->descendantsDrawContent()) {
+ RenderSurfaceChromium* renderSurface = layer->m_renderSurface.get();
+ if (!renderSurface)
+ renderSurface = layer->createRenderSurface();
+
+ // The origin of the new surface is the upper left corner of the layer.
+ layer->m_drawTransform = TransformationMatrix();
+ layer->m_drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0);
+
+ transformedLayerRect = IntRect(0, 0, bounds.width(), bounds.height());
+
+ // Layer's opacity will be applied when drawing the render surface.
+ renderSurface->m_drawOpacity = layer->opacity();
+ if (layer->superlayer()->preserves3D())
+ renderSurface->m_drawOpacity *= layer->superlayer()->drawOpacity();
+ layer->m_drawOpacity = 1;
+
+ TransformationMatrix layerOriginTransform = combinedTransform;
+ layerOriginTransform.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0);
+ renderSurface->m_originTransform = layerOriginTransform;
+ if (layerOriginTransform.isInvertible() && layer->superlayer()) {
+ TransformationMatrix parentToLayer = layerOriginTransform.inverse();
+
+ layer->m_scissorRect = parentToLayer.mapRect(layer->superlayer()->m_scissorRect);
+ } else
+ layer->m_scissorRect = IntRect();
+
+ // The render surface scissor rect is the scissor rect that needs to
+ // be applied before drawing the render surface onto its containing
+ // surface and is therefore expressed in the superlayer's coordinate system.
+ renderSurface->m_scissorRect = layer->superlayer()->m_scissorRect;
+
+ renderSurface->m_layerList.clear();
+
+ renderSurfaceLayerList.append(layer);
+ } else {
+ // DT = M[p] * LT
+ layer->m_drawTransform = combinedTransform;
+ transformedLayerRect = enclosingIntRect(layer->m_drawTransform.mapRect(layerRect));
+
+ layer->m_drawOpacity = layer->opacity();
+
+ if (layer->superlayer()) {
+ if (layer->superlayer()->preserves3D())
+ layer->m_drawOpacity *= layer->superlayer()->m_drawOpacity;
+
+ // Layers inherit the scissor rect from their superlayer.
+ layer->m_scissorRect = layer->superlayer()->m_scissorRect;
+
+ layer->m_targetRenderSurface = layer->superlayer()->m_targetRenderSurface;
+ }
+
+ if (layer != m_rootLayer)
+ layer->m_renderSurface = 0;
+
+ if (layer->masksToBounds())
+ layer->m_scissorRect.intersect(transformedLayerRect);
+ }
+
+ if (layer->m_renderSurface)
+ layer->m_targetRenderSurface = layer->m_renderSurface.get();
+ else {
+ ASSERT(layer->superlayer());
+ layer->m_targetRenderSurface = layer->superlayer()->m_targetRenderSurface;
+ }
+
+ // m_drawableContentRect is always stored in the coordinate system of the
+ // RenderSurface the layer draws into.
+ if (layer->drawsContent())
+ layer->m_drawableContentRect = transformedLayerRect;
+ else
+ layer->m_drawableContentRect = IntRect();
+
+ TransformationMatrix sublayerMatrix = layer->m_drawTransform;
+
+ // Flatten to 2D if the layer doesn't preserve 3D.
+ if (!layer->preserves3D()) {
+ sublayerMatrix.setM13(0);
+ sublayerMatrix.setM23(0);
+ sublayerMatrix.setM31(0);
+ sublayerMatrix.setM32(0);
+ sublayerMatrix.setM33(1);
+ sublayerMatrix.setM34(0);
+ sublayerMatrix.setM43(0);
+ }
+
+ // Apply the sublayer transform at the center of the layer.
+ sublayerMatrix.multLeft(layer->sublayerTransform());
+
+ // The origin of the sublayers is the top left corner of the layer, not the
+ // center. The matrix passed down to the sublayers is therefore:
+ // M[s] = M * Tr[-center]
+ sublayerMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0);
+
+ Vector<LayerChromium*>& descendants = (layer->m_renderSurface ? layer->m_renderSurface->m_layerList : layerList);
+ descendants.append(layer);
+ unsigned thisLayerIndex = descendants.size() - 1;
+
+ const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers();
+ for (size_t i = 0; i < sublayers.size(); ++i) {
+ LayerChromium* sublayer = sublayers[i].get();
+ updateLayersRecursive(sublayer, sublayerMatrix, renderSurfaceLayerList, descendants);
+
+ if (sublayer->m_renderSurface) {
+ RenderSurfaceChromium* sublayerRenderSurface = sublayer->m_renderSurface.get();
+ const IntRect& contentRect = sublayerRenderSurface->contentRect();
+ FloatRect sublayerRect(-0.5 * contentRect.width(), -0.5 * contentRect.height(),
+ contentRect.width(), contentRect.height());
+ layer->m_drawableContentRect.unite(enclosingIntRect(sublayerRenderSurface->m_drawTransform.mapRect(sublayerRect)));
+ descendants.append(sublayer);
+ } else
+ layer->m_drawableContentRect.unite(sublayer->m_drawableContentRect);
+ }
+
+ if (layer->masksToBounds())
+ layer->m_drawableContentRect.intersect(transformedLayerRect);
+
+ if (layer->m_renderSurface && layer != m_rootLayer) {
+ RenderSurfaceChromium* renderSurface = layer->m_renderSurface.get();
+ renderSurface->m_contentRect = layer->m_drawableContentRect;
+ FloatPoint surfaceCenter = renderSurface->contentRectCenter();
+
+ // Restrict the RenderSurface size to the portion that's visible.
+ FloatSize centerOffsetDueToClipping;
+ renderSurface->m_contentRect.intersect(layer->m_scissorRect);
+ FloatPoint clippedSurfaceCenter = renderSurface->contentRectCenter();
+ centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter;
+
+ // The RenderSurface backing texture cannot exceed the maximum supported
+ // texture size.
+ renderSurface->m_contentRect.setWidth(std::min(renderSurface->m_contentRect.width(), m_maxTextureSize));
+ renderSurface->m_contentRect.setHeight(std::min(renderSurface->m_contentRect.height(), m_maxTextureSize));
+
+ if (renderSurface->m_contentRect.isEmpty())
+ renderSurface->m_layerList.clear();
+
+ // Since the layer starts a new render surface we need to adjust its
+ // scissor rect to be expressed in the new surface's coordinate system.
+ layer->m_scissorRect = layer->m_drawableContentRect;
+
+ // Adjust the origin of the transform to be the center of the render surface.
+ renderSurface->m_drawTransform = renderSurface->m_originTransform;
+ renderSurface->m_drawTransform.translate3d(surfaceCenter.x() + centerOffsetDueToClipping.width(), surfaceCenter.y() + centerOffsetDueToClipping.height(), 0);
+ }
+
+ // Compute the depth value of the center of the layer which will be used when
+ // sorting the layers for the preserves-3d property.
+ TransformationMatrix& layerDrawMatrix = layer->m_renderSurface ? layer->m_renderSurface->m_drawTransform : layer->m_drawTransform;
+ if (layer->superlayer()) {
+ if (!layer->superlayer()->preserves3D())
+ layer->m_drawDepth = layer->superlayer()->m_drawDepth;
+ else
+ layer->m_drawDepth = layerDrawMatrix.m43();
+ } else
+ layer->m_drawDepth = 0;
+
+ // If preserves-3d then sort all the descendants by the Z coordinate of their
+ // center. If the preserves-3d property is also set on the superlayer then
+ // skip the sorting as the superlayer will sort all the descendants anyway.
+ if (layer->preserves3D() && (!layer->superlayer() || !layer->superlayer()->preserves3D()))
+ std::stable_sort(&descendants.at(thisLayerIndex), descendants.end(), compareLayerZ);
+}
+
+void LayerRendererChromium::setCompositeOffscreen(bool compositeOffscreen)
+{
+ m_compositeOffscreen = compositeOffscreen;
+
+ if (!m_rootLayer) {
+ m_compositeOffscreen = false;
+ return;
+ }
+
+ if (m_compositeOffscreen) {
+ // Need to explicitly set a LayerRendererChromium for the layer with the offscreen texture,
+ // or else the call to prepareContentsTexture() in useRenderSurface() will fail.
+ m_rootLayer->setLayerRenderer(this);
+ } else
+ m_rootLayer->m_renderSurface.clear();
+}
+
+bool LayerRendererChromium::useRenderSurface(RenderSurfaceChromium* renderSurface)
+{
+ if (m_currentRenderSurface == renderSurface)
+ return true;
+
+ m_currentRenderSurface = renderSurface;
+
+ if (renderSurface == m_defaultRenderSurface && !m_compositeOffscreen) {
+ GLC(m_context.get(), m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0));
+ setDrawViewportRect(renderSurface->m_contentRect, true);
+ return true;
+ }
+
+ GLC(m_context.get(), m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_offscreenFramebufferId));
+
+ if (!renderSurface->prepareContentsTexture())
+ return false;
+
+ renderSurface->m_contentsTexture->framebufferTexture2D();
+
+#if !defined ( NDEBUG )
+ if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+#endif
+
+ setDrawViewportRect(renderSurface->m_contentRect, false);
+ return true;
+}
+
+void LayerRendererChromium::drawLayer(LayerChromium* layer, RenderSurfaceChromium* targetSurface)
+{
+ if (layer->m_renderSurface && layer->m_renderSurface != targetSurface) {
+ layer->m_renderSurface->draw();
+ return;
+ }
+
+ if (layer->m_bounds.isEmpty())
+ return;
+
+ setScissorToRect(layer->m_scissorRect);
+
+ // Check if the layer falls within the visible bounds of the page.
+ IntRect layerRect = layer->getDrawRect();
+ bool isLayerVisible = layer->m_scissorRect.intersects(layerRect);
+ if (!isLayerVisible)
+ return;
+
+ // FIXME: Need to take into account the transform of the containing
+ // RenderSurface here, otherwise single-sided layers that draw on
+ // transformed surfaces won't always be culled properly.
+ if (!layer->doubleSided() && layer->m_drawTransform.m33() < 0)
+ return;
+
+ if (layer->drawsContent()) {
+ // Update the contents of the layer if necessary.
+ layer->updateContentsIfDirty();
+ m_context->makeContextCurrent();
+ layer->draw();
+ }
+
+ // Draw the debug border if there is one.
+ layer->drawDebugBorder();
+}
+
+// Sets the scissor region to the given rectangle. The coordinate system for the
+// scissorRect has its origin at the top left corner of the current visible rect.
+void LayerRendererChromium::setScissorToRect(const IntRect& scissorRect)
+{
+ // The scissor coordinates must be supplied in viewport space so we need to offset
+ // by the relative position of the top left corner of the current render surface.
+ int scissorX = scissorRect.x() - m_currentRenderSurface->m_contentRect.x();
+ // When rendering to the default render surface we're rendering upside down so the top
+ // of the GL scissor is the bottom of our layer.
+ // But, if rendering to offscreen texture, we reverse our sense of 'upside down'.
+ int scissorY;
+ if (m_currentRenderSurface == m_defaultRenderSurface && !m_compositeOffscreen)
+ scissorY = m_currentRenderSurface->m_contentRect.height() - (scissorRect.bottom() - m_currentRenderSurface->m_contentRect.y());
+ else
+ scissorY = scissorRect.y() - m_currentRenderSurface->m_contentRect.y();
+ GLC(m_context.get(), m_context->scissor(scissorX, scissorY, scissorRect.width(), scissorRect.height()));
+}
+
+bool LayerRendererChromium::makeContextCurrent()
+{
+ m_context->makeContextCurrent();
+ return true;
+}
+
+// Checks whether a given size is within the maximum allowed texture size range.
+bool LayerRendererChromium::checkTextureSize(const IntSize& textureSize)
+{
+ if (textureSize.width() > m_maxTextureSize || textureSize.height() > m_maxTextureSize)
+ return false;
+ return true;
+}
+
+// Sets the coordinate range of content that ends being drawn onto the target render surface.
+// The target render surface is assumed to have an origin at 0, 0 and the width and height of
+// of the drawRect.
+void LayerRendererChromium::setDrawViewportRect(const IntRect& drawRect, bool flipY)
+{
+ if (flipY)
+ m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.right(), drawRect.bottom(), drawRect.y());
+ else
+ m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.right(), drawRect.y(), drawRect.bottom());
+ GLC(m_context.get(), m_context->viewport(0, 0, drawRect.width(), drawRect.height()));
+}
+
+
+
+void LayerRendererChromium::resizeOnscreenContent(const IntSize& size)
+{
+ if (m_context)
+ m_context->reshape(size.width(), size.height());
+}
+
+bool LayerRendererChromium::initializeSharedObjects()
+{
+ makeContextCurrent();
+
+ // Get the max texture size supported by the system.
+ m_maxTextureSize = 0;
+ GLC(m_context.get(), m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize));
+
+ // Create an FBO for doing offscreen rendering.
+ GLC(m_context.get(), m_offscreenFramebufferId = m_context->createFramebuffer());
+
+ m_layerSharedValues = adoptPtr(new LayerChromium::SharedValues(m_context.get()));
+ m_contentLayerSharedValues = adoptPtr(new ContentLayerChromium::SharedValues(m_context.get()));
+ m_canvasLayerSharedValues = adoptPtr(new CanvasLayerChromium::SharedValues(m_context.get()));
+ m_videoLayerSharedValues = adoptPtr(new VideoLayerChromium::SharedValues(m_context.get()));
+ m_pluginLayerSharedValues = adoptPtr(new PluginLayerChromium::SharedValues(m_context.get()));
+ m_renderSurfaceSharedValues = adoptPtr(new RenderSurfaceChromium::SharedValues(m_context.get()));
+
+ if (!m_layerSharedValues->initialized() || !m_contentLayerSharedValues->initialized() || !m_canvasLayerSharedValues->initialized()
+ || !m_videoLayerSharedValues->initialized() || !m_pluginLayerSharedValues->initialized() || !m_renderSurfaceSharedValues->initialized()) {
+ cleanupSharedObjects();
+ return false;
+ }
+
+ m_textureManager = TextureManager::create(m_context.get(), textureMemoryLimitBytes, m_maxTextureSize);
+ return true;
+}
+
+void LayerRendererChromium::cleanupSharedObjects()
+{
+ makeContextCurrent();
+
+ m_layerSharedValues.clear();
+ m_contentLayerSharedValues.clear();
+ m_canvasLayerSharedValues.clear();
+ m_videoLayerSharedValues.clear();
+ m_pluginLayerSharedValues.clear();
+ m_renderSurfaceSharedValues.clear();
+ if (m_offscreenFramebufferId)
+ GLC(m_context.get(), m_context->deleteFramebuffer(m_offscreenFramebufferId));
+
+ m_textureManager.clear();
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h
new file mode 100644
index 0000000..3d3e784
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 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 LayerRendererChromium_h
+#define LayerRendererChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "CanvasLayerChromium.h"
+#include "ContentLayerChromium.h"
+#include "IntRect.h"
+#include "LayerChromium.h"
+#include "LayerTilerChromium.h"
+#include "PluginLayerChromium.h"
+#include "RenderSurfaceChromium.h"
+#include "SkBitmap.h"
+#include "VideoLayerChromium.h"
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(CG)
+#include <CoreGraphics/CGContext.h>
+#include <wtf/RetainPtr.h>
+#endif
+
+namespace WebCore {
+
+class GraphicsContext3D;
+
+// Class that handles drawing of composited render layers using GL.
+class LayerRendererChromium : public RefCounted<LayerRendererChromium> {
+public:
+ static PassRefPtr<LayerRendererChromium> create(PassRefPtr<GraphicsContext3D> graphicsContext3D);
+
+ ~LayerRendererChromium();
+
+ GraphicsContext3D* context();
+
+ void invalidateRootLayerRect(const IntRect& dirtyRect, const IntRect& visibleRect, const IntRect& contentRect);
+
+ // updates and draws the current layers onto the backbuffer
+ void drawLayers(const IntRect& visibleRect, const IntRect& contentRect,
+ const IntPoint& scrollPosition, TilePaintInterface& tilePaint,
+ TilePaintInterface& scrollbarPaint);
+
+ // waits for rendering to finish
+ void finish();
+
+ // puts backbuffer onscreen
+ void present();
+
+ void setRootLayer(PassRefPtr<LayerChromium> layer);
+ LayerChromium* rootLayer() { return m_rootLayer.get(); }
+ void transferRootLayer(LayerRendererChromium* other) { other->m_rootLayer = m_rootLayer.release(); }
+
+ bool hardwareCompositing() const { return m_hardwareCompositing; }
+
+ void setCompositeOffscreen(bool);
+ bool isCompositingOffscreen() { return m_compositeOffscreen; }
+ LayerTexture* getOffscreenLayerTexture() { return m_compositeOffscreen ? m_rootLayer->m_renderSurface->m_contentsTexture.get() : 0; }
+
+ void setRootLayerCanvasSize(const IntSize&);
+
+ GraphicsContext* rootLayerGraphicsContext() const { return m_rootLayerGraphicsContext.get(); }
+
+ unsigned createLayerTexture();
+ void deleteLayerTexture(unsigned);
+
+ static void debugGLCall(GraphicsContext3D*, const char* command, const char* file, int line);
+
+ const TransformationMatrix& projectionMatrix() const { return m_projectionMatrix; }
+
+ void useShader(unsigned);
+
+ bool checkTextureSize(const IntSize&);
+
+ const LayerChromium::SharedValues* layerSharedValues() const { return m_layerSharedValues.get(); }
+ const ContentLayerChromium::SharedValues* contentLayerSharedValues() const { return m_contentLayerSharedValues.get(); }
+ const CanvasLayerChromium::SharedValues* canvasLayerSharedValues() const { return m_canvasLayerSharedValues.get(); }
+ const VideoLayerChromium::SharedValues* videoLayerSharedValues() const { return m_videoLayerSharedValues.get(); }
+ const PluginLayerChromium::SharedValues* pluginLayerSharedValues() const { return m_pluginLayerSharedValues.get(); }
+ const RenderSurfaceChromium::SharedValues* renderSurfaceSharedValues() const { return m_renderSurfaceSharedValues.get(); }
+
+ void resizeOnscreenContent(const IntSize&);
+
+ IntSize rootLayerTextureSize() const { return IntSize(m_rootLayerTextureWidth, m_rootLayerTextureHeight); }
+ IntRect rootLayerContentRect() const { return m_rootContentRect; }
+ void getFramebufferPixels(void *pixels, const IntRect& rect);
+
+ TextureManager* textureManager() const { return m_textureManager.get(); }
+
+ void setScissorToRect(const IntRect&);
+
+private:
+ explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D> graphicsContext3D);
+ void updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, Vector<LayerChromium*>& renderSurfaceLayerList, Vector<LayerChromium*>& layerList);
+
+ void drawLayer(LayerChromium*, RenderSurfaceChromium*);
+
+ void updateAndDrawRootLayer(TilePaintInterface& tilePaint, TilePaintInterface& scrollbarPaint, const IntRect& visibleRect, const IntRect& contentRect);
+
+ bool isLayerVisible(LayerChromium*, const TransformationMatrix&, const IntRect& visibleRect);
+
+ void setDrawViewportRect(const IntRect&, bool flipY);
+
+ bool useRenderSurface(RenderSurfaceChromium*);
+
+ bool makeContextCurrent();
+
+ static bool compareLayerZ(const LayerChromium*, const LayerChromium*);
+
+ bool initializeSharedObjects();
+ void cleanupSharedObjects();
+
+ static IntRect verticalScrollbarRect(const IntRect& visibleRect, const IntRect& contentRect);
+ static IntRect horizontalScrollbarRect(const IntRect& visibleRect, const IntRect& contentRect);
+
+ int m_rootLayerTextureWidth;
+ int m_rootLayerTextureHeight;
+
+ TransformationMatrix m_projectionMatrix;
+
+ RefPtr<LayerChromium> m_rootLayer;
+ OwnPtr<LayerTilerChromium> m_rootLayerTiler;
+ OwnPtr<LayerTilerChromium> m_horizontalScrollbarTiler;
+ OwnPtr<LayerTilerChromium> m_verticalScrollbarTiler;
+
+ IntPoint m_scrollPosition;
+ bool m_hardwareCompositing;
+
+ unsigned m_currentShader;
+ RenderSurfaceChromium* m_currentRenderSurface;
+
+ unsigned m_offscreenFramebufferId;
+ bool m_compositeOffscreen;
+
+#if PLATFORM(SKIA)
+ OwnPtr<skia::PlatformCanvas> m_rootLayerCanvas;
+ OwnPtr<PlatformContextSkia> m_rootLayerSkiaContext;
+ OwnPtr<GraphicsContext> m_rootLayerGraphicsContext;
+#elif PLATFORM(CG)
+ Vector<uint8_t> m_rootLayerBackingStore;
+ RetainPtr<CGContextRef> m_rootLayerCGContext;
+ OwnPtr<GraphicsContext> m_rootLayerGraphicsContext;
+#endif
+
+ IntSize m_rootLayerCanvasSize;
+
+ IntRect m_rootVisibleRect;
+ IntRect m_rootContentRect;
+
+ // Maximum texture dimensions supported.
+ int m_maxTextureSize;
+
+ // Store values that are shared between instances of each layer type
+ // associated with this instance of the compositor. Since there can be
+ // multiple instances of the compositor running in the same renderer process
+ // we cannot store these values in static variables.
+ OwnPtr<LayerChromium::SharedValues> m_layerSharedValues;
+ OwnPtr<ContentLayerChromium::SharedValues> m_contentLayerSharedValues;
+ OwnPtr<CanvasLayerChromium::SharedValues> m_canvasLayerSharedValues;
+ OwnPtr<VideoLayerChromium::SharedValues> m_videoLayerSharedValues;
+ OwnPtr<PluginLayerChromium::SharedValues> m_pluginLayerSharedValues;
+ OwnPtr<RenderSurfaceChromium::SharedValues> m_renderSurfaceSharedValues;
+
+ OwnPtr<TextureManager> m_textureManager;
+
+ RefPtr<GraphicsContext3D> m_context;
+
+ RenderSurfaceChromium* m_defaultRenderSurface;
+};
+
+// Setting DEBUG_GL_CALLS to 1 will call glGetError() after almost every GL
+// call made by the compositor. Useful for debugging rendering issues but
+// will significantly degrade performance.
+#define DEBUG_GL_CALLS 0
+
+#if DEBUG_GL_CALLS && !defined ( NDEBUG )
+#define GLC(context, x) { (x), LayerRendererChromium::debugGLCall(context, #x, __FILE__, __LINE__); }
+#else
+#define GLC(context, x) (x)
+#endif
+
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/LayerTexture.cpp b/Source/WebCore/platform/graphics/chromium/LayerTexture.cpp
new file mode 100644
index 0000000..32bfa0b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/LayerTexture.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "LayerTexture.h"
+
+#include "GraphicsContext3D.h"
+#include "TextureManager.h"
+
+namespace WebCore {
+
+LayerTexture::LayerTexture(GraphicsContext3D* context, TextureManager* manager)
+ : m_context(context)
+ , m_textureManager(manager)
+ , m_token(0)
+ , m_format(0)
+ , m_textureId(0)
+{
+}
+
+LayerTexture::~LayerTexture()
+{
+ if (m_token)
+ m_textureManager->releaseToken(m_token);
+}
+
+bool LayerTexture::isValid(const IntSize& size, unsigned format)
+{
+ return m_token && size == m_size && format == m_format && m_textureManager->hasTexture(m_token);
+}
+
+bool LayerTexture::reserve(const IntSize& size, unsigned format)
+{
+ if (!m_token)
+ m_token = m_textureManager->getToken();
+
+ if (size == m_size && format == m_format && m_textureManager->hasTexture(m_token))
+ m_textureManager->protectTexture(m_token);
+ else {
+ m_textureId = m_textureManager->requestTexture(m_token, size, format);
+ if (m_textureId) {
+ m_size = size;
+ m_format = format;
+ }
+ }
+
+ return m_textureId;
+}
+
+void LayerTexture::unreserve()
+{
+ if (m_token)
+ m_textureManager->unprotectTexture(m_token);
+}
+
+void LayerTexture::bindTexture()
+{
+ m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId);
+}
+
+void LayerTexture::framebufferTexture2D()
+{
+ m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_textureId, 0);
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
diff --git a/Source/WebCore/platform/graphics/chromium/LayerTexture.h b/Source/WebCore/platform/graphics/chromium/LayerTexture.h
new file mode 100644
index 0000000..312adfa
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/LayerTexture.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 LayerTexture_h
+#define LayerTexture_h
+
+#include "IntSize.h"
+#include "TextureManager.h"
+
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class GraphicsContext3D;
+class TextureManager;
+
+class LayerTexture : public Noncopyable {
+public:
+ static PassOwnPtr<LayerTexture> create(GraphicsContext3D* context, TextureManager* manager)
+ {
+ return adoptPtr(new LayerTexture(context, manager));
+ }
+ ~LayerTexture();
+
+ bool isValid(const IntSize&, unsigned format);
+ bool reserve(const IntSize&, unsigned format);
+ void unreserve();
+
+ void bindTexture();
+ void framebufferTexture2D();
+
+private:
+ LayerTexture(GraphicsContext3D*, TextureManager*);
+
+ RefPtr<GraphicsContext3D> m_context;
+ TextureManager* m_textureManager;
+ TextureToken m_token;
+ IntSize m_size;
+ unsigned m_format;
+ unsigned m_textureId;
+};
+
+}
+
+#endif
+
diff --git a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp
new file mode 100644
index 0000000..31649a4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "LayerTilerChromium.h"
+
+#include "GraphicsContext.h"
+#include "GraphicsContext3D.h"
+#include "LayerRendererChromium.h"
+
+#if PLATFORM(SKIA)
+#include "NativeImageSkia.h"
+#include "PlatformContextSkia.h"
+#elif PLATFORM(CG)
+#include <CoreGraphics/CGBitmapContext.h>
+#endif
+
+#include <wtf/PassOwnArrayPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<LayerTilerChromium> LayerTilerChromium::create(LayerRendererChromium* layerRenderer, const IntSize& tileSize)
+{
+ if (!layerRenderer || tileSize.isEmpty())
+ return 0;
+
+ return adoptPtr(new LayerTilerChromium(layerRenderer, tileSize));
+}
+
+LayerTilerChromium::LayerTilerChromium(LayerRendererChromium* layerRenderer, const IntSize& tileSize)
+ : m_layerRenderer(layerRenderer)
+{
+ setTileSize(tileSize);
+}
+
+LayerTilerChromium::~LayerTilerChromium()
+{
+ reset();
+}
+
+GraphicsContext3D* LayerTilerChromium::layerRendererContext() const
+{
+ ASSERT(layerRenderer());
+ return layerRenderer()->context();
+}
+
+void LayerTilerChromium::setTileSize(const IntSize& size)
+{
+ if (m_tileSize == size)
+ return;
+
+ reset();
+
+ m_tileSize = size;
+ m_tilePixels = adoptArrayPtr(new uint8_t[m_tileSize.width() * m_tileSize.height() * 4]);
+}
+
+void LayerTilerChromium::reset()
+{
+ for (size_t i = 0; i < m_tiles.size(); ++i) {
+ if (!m_tiles[i])
+ continue;
+ layerRenderer()->deleteLayerTexture(m_tiles[i]->releaseTextureId());
+ }
+ m_tiles.clear();
+ for (size_t i = 0; i < m_unusedTiles.size(); ++i) {
+ if (!m_unusedTiles[i])
+ continue;
+ layerRenderer()->deleteLayerTexture(m_unusedTiles[i]->releaseTextureId());
+ }
+ m_unusedTiles.clear();
+
+ m_layerSize = IntSize();
+ m_layerTileSize = IntSize();
+ m_lastUpdateLayerRect = IntRect();
+}
+
+LayerTilerChromium::Tile* LayerTilerChromium::createTile(int i, int j)
+{
+ const int index = tileIndex(i, j);
+ ASSERT(!m_tiles[index]);
+
+ if (m_unusedTiles.size() > 0) {
+ m_tiles[index] = m_unusedTiles.last().release();
+ m_unusedTiles.removeLast();
+ } else {
+ const unsigned int textureId = layerRenderer()->createLayerTexture();
+ OwnPtr<Tile> tile = adoptPtr(new Tile(textureId));
+
+ GraphicsContext3D* context = layerRendererContext();
+ GLC(context, context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_tileSize.width(), m_tileSize.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE));
+
+ m_tiles[index] = tile.release();
+ }
+
+ m_tiles[index]->m_dirtyLayerRect = tileLayerRect(i, j);
+ return m_tiles[index].get();
+}
+
+void LayerTilerChromium::invalidateTiles(const IntRect& oldLayerRect, const IntRect& newLayerRect)
+{
+ if (!m_tiles.size())
+ return;
+
+ IntRect oldContentRect = layerRectToContentRect(oldLayerRect);
+ int oldLeft, oldTop, oldRight, oldBottom;
+ contentRectToTileIndices(oldContentRect, oldLeft, oldTop, oldRight, oldBottom);
+
+ IntRect newContentRect = layerRectToContentRect(newLayerRect);
+ int newLeft, newTop, newRight, newBottom;
+ contentRectToTileIndices(newContentRect, newLeft, newTop, newRight, newBottom);
+
+ // Iterating through just the old tile indices is an optimization to avoid
+ // iterating through the entire m_tiles array.
+ for (int j = oldTop; j <= oldBottom; ++j) {
+ for (int i = oldLeft; i <= oldRight; ++i) {
+ if (i >= newLeft && i <= newRight && j >= newTop && j <= newBottom)
+ continue;
+
+ const int index = tileIndex(i, j);
+ if (m_tiles[index])
+ m_unusedTiles.append(m_tiles[index].release());
+ }
+ }
+}
+
+void LayerTilerChromium::contentRectToTileIndices(const IntRect& contentRect, int &left, int &top, int &right, int &bottom) const
+{
+ const IntRect layerRect = contentRectToLayerRect(contentRect);
+
+ left = layerRect.x() / m_tileSize.width();
+ top = layerRect.y() / m_tileSize.height();
+ right = (layerRect.right() - 1) / m_tileSize.width();
+ bottom = (layerRect.bottom() - 1) / m_tileSize.height();
+}
+
+IntRect LayerTilerChromium::contentRectToLayerRect(const IntRect& contentRect) const
+{
+ IntPoint pos(contentRect.x() - m_layerPosition.x(), contentRect.y() - m_layerPosition.y());
+ IntRect layerRect(pos, contentRect.size());
+
+ // Clip to the position.
+ if (pos.x() < 0 || pos.y() < 0)
+ layerRect = IntRect(IntPoint(0, 0), IntSize(contentRect.width() + pos.x(), contentRect.height() + pos.y()));
+ return layerRect;
+}
+
+IntRect LayerTilerChromium::layerRectToContentRect(const IntRect& layerRect) const
+{
+ IntRect contentRect = layerRect;
+ contentRect.move(m_layerPosition.x(), m_layerPosition.y());
+ return contentRect;
+}
+
+int LayerTilerChromium::tileIndex(int i, int j) const
+{
+ ASSERT(i >= 0 && j >= 0 && i < m_layerTileSize.width() && j < m_layerTileSize.height());
+ return i + j * m_layerTileSize.width();
+}
+
+IntRect LayerTilerChromium::tileContentRect(int i, int j) const
+{
+ IntPoint anchor(m_layerPosition.x() + i * m_tileSize.width(), m_layerPosition.y() + j * m_tileSize.height());
+ IntRect tile(anchor, m_tileSize);
+ return tile;
+}
+
+IntRect LayerTilerChromium::tileLayerRect(int i, int j) const
+{
+ IntPoint anchor(i * m_tileSize.width(), j * m_tileSize.height());
+ IntRect tile(anchor, m_tileSize);
+ return tile;
+}
+
+void LayerTilerChromium::invalidateRect(const IntRect& contentRect)
+{
+ if (contentRect.isEmpty())
+ return;
+
+ growLayerToContain(contentRect);
+
+ // Dirty rects are always in layer space, as the layer could be repositioned
+ // after invalidation.
+ IntRect layerRect = contentRectToLayerRect(contentRect);
+
+ int left, top, right, bottom;
+ contentRectToTileIndices(contentRect, left, top, right, bottom);
+ for (int j = top; j <= bottom; ++j) {
+ for (int i = left; i <= right; ++i) {
+ Tile* tile = m_tiles[tileIndex(i, j)].get();
+ if (!tile)
+ continue;
+ IntRect bound = tileLayerRect(i, j);
+ bound.intersect(layerRect);
+ tile->m_dirtyLayerRect.unite(bound);
+ }
+ }
+}
+
+void LayerTilerChromium::invalidateEntireLayer()
+{
+ for (size_t i = 0; i < m_tiles.size(); ++i) {
+ if (m_tiles[i])
+ m_unusedTiles.append(m_tiles[i].release());
+ }
+ m_tiles.clear();
+
+ m_layerSize = IntSize();
+ m_layerTileSize = IntSize();
+ m_lastUpdateLayerRect = IntRect();
+}
+
+void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& contentRect)
+{
+ // Invalidate old tiles that were previously used but aren't in use this
+ // frame so that they can get reused for new tiles.
+ IntRect layerRect = contentRectToLayerRect(contentRect);
+ invalidateTiles(m_lastUpdateLayerRect, layerRect);
+ m_lastUpdateLayerRect = layerRect;
+
+ growLayerToContain(contentRect);
+
+ // Create tiles as needed, expanding a dirty rect to contain all
+ // the dirty regions currently being drawn.
+ IntRect dirtyLayerRect;
+ int left, top, right, bottom;
+ contentRectToTileIndices(contentRect, left, top, right, bottom);
+ for (int j = top; j <= bottom; ++j) {
+ for (int i = left; i <= right; ++i) {
+ Tile* tile = m_tiles[tileIndex(i, j)].get();
+ if (!tile)
+ tile = createTile(i, j);
+ dirtyLayerRect.unite(tile->m_dirtyLayerRect);
+ }
+ }
+
+ if (dirtyLayerRect.isEmpty())
+ return;
+
+ const IntRect paintRect = layerRectToContentRect(dirtyLayerRect);
+ GraphicsContext3D* context = layerRendererContext();
+#if PLATFORM(SKIA)
+ OwnPtr<skia::PlatformCanvas> canvas(new skia::PlatformCanvas(paintRect.width(), paintRect.height(), false));
+ OwnPtr<PlatformContextSkia> skiaContext(new PlatformContextSkia(canvas.get()));
+ OwnPtr<GraphicsContext> graphicsContext(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(skiaContext.get())));
+
+ // Bring the canvas into the coordinate system of the paint rect.
+ canvas->translate(static_cast<SkScalar>(-paintRect.x()), static_cast<SkScalar>(-paintRect.y()));
+
+ painter.paint(*graphicsContext, paintRect);
+
+ // Get the contents of the updated rect.
+ const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false);
+ ASSERT(bitmap.width() == paintRect.width() && bitmap.height() == paintRect.height());
+ uint8_t* paintPixels = static_cast<uint8_t*>(bitmap.getPixels());
+#elif PLATFORM(CG)
+ Vector<uint8_t> canvasPixels;
+ int rowBytes = 4 * paintRect.width();
+ canvasPixels.resize(rowBytes * paintRect.height());
+ memset(canvasPixels.data(), 0, canvasPixels.size());
+ RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ RetainPtr<CGContextRef> m_cgContext;
+ m_cgContext.adoptCF(CGBitmapContextCreate(canvasPixels.data(),
+ paintRect.width(), paintRect.height(), 8, rowBytes,
+ colorSpace.get(),
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+ CGContextTranslateCTM(m_cgContext.get(), 0, paintRect.height());
+ CGContextScaleCTM(m_cgContext.get(), 1, -1);
+ OwnPtr<GraphicsContext> m_graphicsContext(new GraphicsContext(m_cgContext.get()));
+
+ // Bring the CoreGraphics context into the coordinate system of the paint rect.
+ CGContextTranslateCTM(m_cgContext.get(), -paintRect.x(), -paintRect.y());
+ painter.paint(*m_graphicsContext, paintRect);
+
+ // Get the contents of the updated rect.
+ ASSERT(static_cast<int>(CGBitmapContextGetWidth(m_cgContext.get())) == paintRect.width() && static_cast<int>(CGBitmapContextGetHeight(m_cgContext.get())) == paintRect.height());
+ uint8_t* paintPixels = static_cast<uint8_t*>(canvasPixels.data());
+#else
+#error "Need to implement for your platform."
+#endif
+
+ for (int j = top; j <= bottom; ++j) {
+ for (int i = left; i <= right; ++i) {
+ Tile* tile = m_tiles[tileIndex(i, j)].get();
+ if (!tile->dirty())
+ continue;
+
+ // Calculate page-space rectangle to copy from.
+ IntRect sourceRect = tileContentRect(i, j);
+ const IntPoint anchor = sourceRect.location();
+ sourceRect.intersect(layerRectToContentRect(tile->m_dirtyLayerRect));
+
+ // Calculate tile-space rectangle to upload into.
+ IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size());
+
+ // Offset from paint rectangle to this tile's dirty rectangle.
+ IntPoint paintOffset(sourceRect.x() - paintRect.x(), sourceRect.y() - paintRect.y());
+
+ uint8_t* pixelSource;
+ if (paintRect.width() == sourceRect.width() && !paintOffset.x())
+ pixelSource = &paintPixels[4 * paintOffset.y() * paintRect.width()];
+ else {
+ // Strides not equal, so do a row-by-row memcpy from the
+ // paint results into a temp buffer for uploading.
+ for (int row = 0; row < destRect.height(); ++row)
+ memcpy(&m_tilePixels[destRect.width() * 4 * row],
+ &paintPixels[4 * (paintOffset.x() + (paintOffset.y() + row) * paintRect.width())],
+ destRect.width() * 4);
+
+ pixelSource = &m_tilePixels[0];
+ }
+
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, tile->textureId()));
+ GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, destRect.x(), destRect.y(), destRect.width(), destRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixelSource));
+
+ tile->clearDirty();
+ }
+ }
+}
+
+void LayerTilerChromium::setLayerPosition(const IntPoint& layerPosition)
+{
+ m_layerPosition = layerPosition;
+}
+
+void LayerTilerChromium::draw(const IntRect& contentRect)
+{
+ // We reuse the shader program used by ContentLayerChromium.
+ GraphicsContext3D* context = layerRendererContext();
+ const ContentLayerChromium::SharedValues* contentLayerValues = layerRenderer()->contentLayerSharedValues();
+ layerRenderer()->useShader(contentLayerValues->contentShaderProgram());
+ GLC(context, context->uniform1i(contentLayerValues->shaderSamplerLocation(), 0));
+
+ int left, top, right, bottom;
+ contentRectToTileIndices(contentRect, left, top, right, bottom);
+ for (int j = top; j <= bottom; ++j) {
+ for (int i = left; i <= right; ++i) {
+ Tile* tile = m_tiles[tileIndex(i, j)].get();
+ ASSERT(tile);
+
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, tile->textureId()));
+
+ TransformationMatrix tileMatrix;
+ IntRect tileRect = tileContentRect(i, j);
+ tileMatrix.translate3d(tileRect.x() - contentRect.x() + tileRect.width() / 2.0, tileRect.y() - contentRect.y() + tileRect.height() / 2.0, 0);
+
+ LayerChromium::drawTexturedQuad(context, layerRenderer()->projectionMatrix(), tileMatrix, m_tileSize.width(), m_tileSize.height(), 1, contentLayerValues->shaderMatrixLocation(), contentLayerValues->shaderAlphaLocation());
+ }
+ }
+}
+
+void LayerTilerChromium::resizeLayer(const IntSize& size)
+{
+ if (m_layerSize == size)
+ return;
+
+ int width = (size.width() + m_tileSize.width() - 1) / m_tileSize.width();
+ int height = (size.height() + m_tileSize.height() - 1) / m_tileSize.height();
+
+ Vector<OwnPtr<Tile> > newTiles;
+ newTiles.resize(width * height);
+ for (int j = 0; j < m_layerTileSize.height(); ++j)
+ for (int i = 0; i < m_layerTileSize.width(); ++i)
+ newTiles[i + j * width].swap(m_tiles[i + j * m_layerTileSize.width()]);
+
+ m_tiles.swap(newTiles);
+ m_layerSize = size;
+ m_layerTileSize = IntSize(width, height);
+}
+
+void LayerTilerChromium::growLayerToContain(const IntRect& contentRect)
+{
+ // Grow the tile array to contain this content rect.
+ IntRect layerRect = contentRectToLayerRect(contentRect);
+ IntSize layerSize = IntSize(layerRect.right(), layerRect.bottom());
+
+ IntSize newSize = layerSize.expandedTo(m_layerSize);
+ resizeLayer(newSize);
+}
+
+LayerTilerChromium::Tile::~Tile()
+{
+ // Each tile doesn't have a reference to the context, so can't clean up
+ // its own texture. If this assert is hit, then the LayerTilerChromium
+ // destructor didn't clean this up.
+ ASSERT(!m_textureId);
+}
+
+unsigned int LayerTilerChromium::Tile::releaseTextureId()
+{
+ unsigned int id = m_textureId;
+ m_textureId = 0;
+ return id;
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h
new file mode 100644
index 0000000..c066fdf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 LayerTilerChromium_h
+#define LayerTilerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "LayerChromium.h"
+#include <wtf/OwnArrayPtr.h>
+
+namespace WebCore {
+
+class GraphicsContext3D;
+class LayerRendererChromium;
+
+class TilePaintInterface {
+public:
+ virtual void paint(GraphicsContext& context, const IntRect& contentRect) = 0;
+};
+
+class LayerTilerChromium : public Noncopyable {
+public:
+ static PassOwnPtr<LayerTilerChromium> create(LayerRendererChromium* layerRenderer, const IntSize& tileSize);
+
+ ~LayerTilerChromium();
+
+ void invalidateRect(const IntRect& contentRect);
+ void invalidateEntireLayer();
+ void update(TilePaintInterface& painter, const IntRect& contentRect);
+ void draw(const IntRect& contentRect);
+
+ // Set position of this tiled layer in content space.
+ void setLayerPosition(const IntPoint& position);
+ // Change the tile size. This may invalidate all the existing tiles.
+ void setTileSize(const IntSize& size);
+
+private:
+ LayerTilerChromium(LayerRendererChromium* layerRenderer, const IntSize& tileSize);
+
+ class Tile {
+ public:
+ explicit Tile(unsigned int textureId) : m_textureId(textureId) { }
+ ~Tile();
+
+ unsigned int textureId() const { return m_textureId; }
+ unsigned int releaseTextureId();
+
+ bool dirty() const { return !m_dirtyLayerRect.isEmpty(); }
+ void clearDirty() { m_dirtyLayerRect = IntRect(); }
+
+ // Layer-space dirty rectangle that needs to be repainted.
+ IntRect m_dirtyLayerRect;
+ private:
+ unsigned int m_textureId;
+ };
+
+ void resizeLayer(const IntSize& size);
+ // Grow layer size to contain this rectangle.
+ void growLayerToContain(const IntRect& contentRect);
+
+ LayerRendererChromium* layerRenderer() const { return m_layerRenderer; }
+ GraphicsContext3D* layerRendererContext() const;
+ Tile* createTile(int i, int j);
+ // Invalidate any tiles which do not intersect with the newLayerRect.
+ void invalidateTiles(const IntRect& oldLayerRect, const IntRect& newLayerRect);
+ void reset();
+ void contentRectToTileIndices(const IntRect& contentRect, int &left, int &top, int &right, int &bottom) const;
+ IntRect contentRectToLayerRect(const IntRect& contentRect) const;
+ IntRect layerRectToContentRect(const IntRect& layerRect) const;
+
+ // Returns the index into m_tiles for a given tile location.
+ int tileIndex(int i, int j) const;
+ // Returns the bounds in content space for a given tile location.
+ IntRect tileContentRect(int i, int j) const;
+ // Returns the bounds in layer space for a given tile location.
+ IntRect tileLayerRect(int i, int j) const;
+
+ IntSize m_tileSize;
+ IntSize m_layerSize;
+ IntSize m_layerTileSize;
+ IntRect m_lastUpdateLayerRect;
+ IntPoint m_layerPosition;
+
+ // Logical 2D array of tiles (dimensions of m_layerTileSize)
+ Vector<OwnPtr<Tile> > m_tiles;
+ // Linear array of unused tiles.
+ Vector<OwnPtr<Tile> > m_unusedTiles;
+
+ // Cache a tile-sized pixel buffer to draw into.
+ OwnArrayPtr<uint8_t> m_tilePixels;
+
+ LayerRendererChromium* m_layerRenderer;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h b/Source/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
new file mode 100644
index 0000000..534244d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2008, 2009, 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 MediaPlayerPrivateChromium_h
+#define MediaPlayerPrivateChromium_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayerPrivate.h"
+
+namespace WebCore {
+
+class MediaPlayerPrivate {
+public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // MediaPlayerPrivateChromium_h
diff --git a/Source/WebCore/platform/graphics/chromium/PlatformIcon.h b/Source/WebCore/platform/graphics/chromium/PlatformIcon.h
new file mode 100644
index 0000000..51613b8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/PlatformIcon.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2008, 2009, 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 PlatformIcon_h
+#define PlatformIcon_h
+
+typedef struct HICON__* HICON;
+
+namespace WebCore {
+
+typedef HICON PlatformIcon;
+
+} // namespace WebCore
+
+#endif // PlatformIcon_h
diff --git a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp
new file mode 100644
index 0000000..878c142
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "PluginLayerChromium.h"
+
+#include "GraphicsContext3D.h"
+#include "LayerRendererChromium.h"
+#include <GLES2/gl2.h>
+
+namespace WebCore {
+
+PluginLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context)
+ : m_context(context)
+ , m_shaderProgram(0)
+ , m_shaderSamplerLocation(-1)
+ , m_shaderMatrixLocation(-1)
+ , m_shaderAlphaLocation(-1)
+ , m_initialized(false)
+{
+ char vertexShaderString[] =
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "uniform mat4 matrix; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = matrix * a_position; \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+
+ char fragmentShaderString[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "uniform float alpha; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 texColor = texture2D(s_texture, vec2(v_texCoord.x, v_texCoord.y)); \n"
+ " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n"
+ "} \n";
+
+ m_shaderProgram = createShaderProgram(m_context, vertexShaderString, fragmentShaderString);
+ if (!m_shaderProgram) {
+ LOG_ERROR("PluginLayerChromium: Failed to create shader program");
+ return;
+ }
+
+ m_shaderSamplerLocation = m_context->getUniformLocation(m_shaderProgram, "s_texture");
+ m_shaderMatrixLocation = m_context->getUniformLocation(m_shaderProgram, "matrix");
+ m_shaderAlphaLocation = m_context->getUniformLocation(m_shaderProgram, "alpha");
+ ASSERT(m_shaderSamplerLocation != -1);
+ ASSERT(m_shaderMatrixLocation != -1);
+ ASSERT(m_shaderAlphaLocation != -1);
+
+ m_initialized = true;
+}
+
+PluginLayerChromium::SharedValues::~SharedValues()
+{
+ if (m_shaderProgram)
+ GLC(m_context, m_context->deleteProgram(m_shaderProgram));
+}
+
+PassRefPtr<PluginLayerChromium> PluginLayerChromium::create(GraphicsLayerChromium* owner)
+{
+ return adoptRef(new PluginLayerChromium(owner));
+}
+
+PluginLayerChromium::PluginLayerChromium(GraphicsLayerChromium* owner)
+ : LayerChromium(owner)
+{
+}
+
+void PluginLayerChromium::setTextureId(unsigned id)
+{
+ m_textureId = id;
+}
+
+void PluginLayerChromium::updateContentsIfDirty()
+{
+}
+
+void PluginLayerChromium::draw()
+{
+ ASSERT(layerRenderer());
+ const PluginLayerChromium::SharedValues* sv = layerRenderer()->pluginLayerSharedValues();
+ ASSERT(sv && sv->initialized());
+ GraphicsContext3D* context = layerRendererContext();
+ GLC(context, context->activeTexture(GL_TEXTURE0));
+ GLC(context, context->bindTexture(GL_TEXTURE_2D, m_textureId));
+
+ // FIXME: setting the texture parameters every time is redundant. Move this code somewhere
+ // where it will only happen once per texture.
+ GLC(context, context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ GLC(context, context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+ GLC(context, context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GLC(context, context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+
+ layerRenderer()->useShader(sv->shaderProgram());
+ GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0));
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(),
+ bounds().width(), bounds().height(), drawOpacity(),
+ sv->shaderMatrixLocation(), sv->shaderAlphaLocation());
+}
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h
new file mode 100644
index 0000000..853b328
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PluginLayerChromium_h
+#define PluginLayerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "LayerChromium.h"
+
+namespace WebCore {
+
+// A Layer containing a the rendered output of a plugin instance.
+class PluginLayerChromium : public LayerChromium {
+public:
+ static PassRefPtr<PluginLayerChromium> create(GraphicsLayerChromium* owner = 0);
+ virtual bool drawsContent() { return true; }
+ virtual void updateContentsIfDirty();
+ virtual void draw();
+
+ void setTextureId(unsigned textureId);
+
+ class SharedValues {
+ public:
+ SharedValues(GraphicsContext3D* context);
+ ~SharedValues();
+
+ unsigned shaderProgram() const { return m_shaderProgram; }
+ int shaderSamplerLocation() const { return m_shaderSamplerLocation; }
+ int shaderMatrixLocation() const { return m_shaderMatrixLocation; }
+ int shaderAlphaLocation() const { return m_shaderAlphaLocation; }
+ bool initialized() const { return m_initialized; }
+
+ private:
+ GraphicsContext3D* m_context;
+ unsigned m_shaderProgram;
+ int m_shaderSamplerLocation;
+ int m_shaderMatrixLocation;
+ int m_shaderAlphaLocation;
+ bool m_initialized;
+ };
+
+private:
+ PluginLayerChromium(GraphicsLayerChromium* owner);
+ unsigned m_textureId;
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp
new file mode 100644
index 0000000..e8b9a12
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "RenderSurfaceChromium.h"
+
+#include "GraphicsContext3D.h"
+#include "LayerRendererChromium.h"
+#include "LayerTexture.h"
+
+namespace WebCore {
+
+RenderSurfaceChromium::SharedValues::SharedValues(GraphicsContext3D* context)
+ : m_context(context)
+ , m_shaderProgram(0)
+ , m_shaderSamplerLocation(-1)
+ , m_shaderMatrixLocation(-1)
+ , m_shaderAlphaLocation(-1)
+ , m_initialized(false)
+{
+ // The following program composites layers whose contents are the results of a previous
+ // render operation and therefore doesn't perform any color swizzling. It is used
+ // in scrolling and for compositing offscreen textures.
+ char renderSurfaceVertexShaderString[] =
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "uniform mat4 matrix; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = matrix * a_position; \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+ char renderSurfaceFragmentShaderString[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "uniform float alpha; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 texColor = texture2D(s_texture, v_texCoord); \n"
+ " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n"
+ "} \n";
+
+ m_shaderProgram = LayerChromium::createShaderProgram(m_context, renderSurfaceVertexShaderString, renderSurfaceFragmentShaderString);
+ if (!m_shaderProgram) {
+ LOG_ERROR("RenderSurfaceChromium: Failed to create shader program");
+ return;
+ }
+
+ GLC(m_context, m_shaderSamplerLocation = m_context->getUniformLocation(m_shaderProgram, "s_texture"));
+ GLC(m_context, m_shaderMatrixLocation = m_context->getUniformLocation(m_shaderProgram, "matrix"));
+ GLC(m_context, m_shaderAlphaLocation = m_context->getUniformLocation(m_shaderProgram, "alpha"));
+ if (m_shaderSamplerLocation == -1 || m_shaderMatrixLocation == -1 || m_shaderAlphaLocation == -1) {
+ LOG_ERROR("Failed to initialize texture layer shader.");
+ return;
+ }
+ m_initialized = true;
+}
+
+RenderSurfaceChromium::SharedValues::~SharedValues()
+{
+ if (m_shaderProgram)
+ GLC(m_context, m_context->deleteProgram(m_shaderProgram));
+}
+
+RenderSurfaceChromium::RenderSurfaceChromium(LayerChromium* owningLayer)
+ : m_owningLayer(owningLayer)
+ , m_skipsDraw(false)
+{
+}
+
+RenderSurfaceChromium::~RenderSurfaceChromium()
+{
+ cleanupResources();
+}
+
+void RenderSurfaceChromium::cleanupResources()
+{
+ if (!m_contentsTexture)
+ return;
+
+ ASSERT(layerRenderer());
+
+ m_contentsTexture.clear();
+}
+
+LayerRendererChromium* RenderSurfaceChromium::layerRenderer()
+{
+ ASSERT(m_owningLayer);
+ return m_owningLayer->layerRenderer();
+}
+
+bool RenderSurfaceChromium::prepareContentsTexture()
+{
+ IntSize requiredSize(m_contentRect.size());
+ TextureManager* textureManager = layerRenderer()->textureManager();
+
+ if (!m_contentsTexture)
+ m_contentsTexture = LayerTexture::create(layerRenderer()->context(), textureManager);
+
+ if (!m_contentsTexture->reserve(requiredSize, GraphicsContext3D::RGBA)) {
+ m_skipsDraw = true;
+ return false;
+ }
+
+ m_skipsDraw = false;
+ return true;
+}
+
+void RenderSurfaceChromium::draw()
+{
+ if (m_skipsDraw || !m_contentsTexture)
+ return;
+
+ m_contentsTexture->bindTexture();
+
+ const RenderSurfaceChromium::SharedValues* sv = layerRenderer()->renderSurfaceSharedValues();
+ ASSERT(sv && sv->initialized());
+
+ layerRenderer()->useShader(sv->shaderProgram());
+ layerRenderer()->setScissorToRect(m_scissorRect);
+
+ LayerChromium::drawTexturedQuad(layerRenderer()->context(), layerRenderer()->projectionMatrix(), m_drawTransform,
+ m_contentRect.width(), m_contentRect.height(), m_drawOpacity,
+ sv->shaderMatrixLocation(), sv->shaderAlphaLocation());
+
+ m_contentsTexture->unreserve();
+}
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h
new file mode 100644
index 0000000..a93218f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 RenderSurfaceChromium_h
+#define RenderSurfaceChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "TextureManager.h"
+#include "TransformationMatrix.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class LayerChromium;
+class LayerRendererChromium;
+class LayerTexture;
+
+class RenderSurfaceChromium : public Noncopyable {
+ friend class LayerRendererChromium;
+public:
+ explicit RenderSurfaceChromium(LayerChromium*);
+ ~RenderSurfaceChromium();
+
+ bool prepareContentsTexture();
+ void cleanupResources();
+ void draw();
+
+ FloatPoint contentRectCenter() const { return FloatRect(m_contentRect).center(); }
+ IntRect contentRect() const { return m_contentRect; }
+
+ // Stores values that are shared between instances of this class that are
+ // associated with the same LayerRendererChromium (and hence the same GL
+ // context).
+ class SharedValues {
+ public:
+ explicit SharedValues(GraphicsContext3D*);
+ ~SharedValues();
+
+ unsigned shaderProgram() const { return m_shaderProgram; }
+ int shaderSamplerLocation() const { return m_shaderSamplerLocation; }
+ int shaderMatrixLocation() const { return m_shaderMatrixLocation; }
+ int shaderAlphaLocation() const { return m_shaderAlphaLocation; }
+ bool initialized() const { return m_initialized; }
+
+ private:
+ GraphicsContext3D* m_context;
+
+ unsigned m_shaderProgram;
+ int m_shaderSamplerLocation;
+ int m_shaderMatrixLocation;
+ int m_shaderAlphaLocation;
+ bool m_initialized;
+ };
+
+private:
+ LayerRendererChromium* layerRenderer();
+
+ LayerChromium* m_owningLayer;
+ IntRect m_contentRect;
+ bool m_skipsDraw;
+ OwnPtr<LayerTexture> m_contentsTexture;
+ float m_drawOpacity;
+ TransformationMatrix m_drawTransform;
+ TransformationMatrix m_originTransform;
+ IntRect m_scissorRect;
+ Vector<LayerChromium*> m_layerList;
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
new file mode 100644
index 0000000..204c565
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2008, 2009, 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "ChromiumBridge.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include <wtf/MathExtras.h>
+
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+#include <objidl.h>
+#include <mlang.h>
+
+namespace WebCore {
+
+static inline float scaleEmToUnits(float x, int unitsPerEm)
+{
+ return unitsPerEm ? x / static_cast<float>(unitsPerEm) : x;
+}
+
+void SimpleFontData::platformInit()
+{
+ if (!m_platformData.size()) {
+ m_ascent = 0;
+ m_descent = 0;
+ m_lineGap = 0;
+ m_lineSpacing = 0;
+ m_avgCharWidth = 0;
+ m_maxCharWidth = 0;
+ m_xHeight = 0;
+ m_unitsPerEm = 0;
+ return;
+ }
+
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont());
+
+ TEXTMETRIC textMetric = {0};
+ if (!GetTextMetrics(dc, &textMetric)) {
+ if (ChromiumBridge::ensureFontLoaded(m_platformData.hfont())) {
+ // Retry GetTextMetrics.
+ // FIXME: Handle gracefully the error if this call also fails.
+ // See http://crbug.com/6401.
+ if (!GetTextMetrics(dc, &textMetric))
+ LOG_ERROR("Unable to get the text metrics after second attempt");
+ }
+ }
+
+ m_avgCharWidth = textMetric.tmAveCharWidth;
+ m_maxCharWidth = textMetric.tmMaxCharWidth;
+
+ m_ascent = textMetric.tmAscent;
+ m_descent = textMetric.tmDescent;
+ m_lineGap = textMetric.tmExternalLeading;
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts.
+
+ OUTLINETEXTMETRIC outlineTextMetric;
+ if (GetOutlineTextMetrics(dc, sizeof(outlineTextMetric), &outlineTextMetric) > 0) {
+ // This is a TrueType font. We might be able to get an accurate xHeight.
+ GLYPHMETRICS glyphMetrics = {0};
+ MAT2 identityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
+ DWORD len = GetGlyphOutlineW(dc, 'x', GGO_METRICS, &glyphMetrics, 0, 0, &identityMatrix);
+ if (len != GDI_ERROR && glyphMetrics.gmBlackBoxY > 0)
+ m_xHeight = static_cast<float>(glyphMetrics.gmBlackBoxY);
+ }
+
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ // charwidths are set in platformInit.
+}
+
+void SimpleFontData::platformDestroy()
+{
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ LOGFONT winFont;
+ GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winFont);
+ float scaledSize = scaleFactor * fontDescription.computedSize();
+ winFont.lfHeight = -lroundf(scaledSize);
+ HFONT hfont = CreateFontIndirect(&winFont);
+ return new SimpleFontData(FontPlatformData(hfont, scaledSize), isCustomFont(), false);
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ // This used to be implemented with IMLangFontLink2, but since that code has
+ // been disabled, this would always return false anyway.
+ return false;
+}
+
+void SimpleFontData::determinePitch()
+{
+ // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont());
+
+ // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
+ // is *not* fixed pitch. Unbelievable but true.
+ TEXTMETRIC textMetric = {0};
+ if (!GetTextMetrics(dc, &textMetric)) {
+ if (ChromiumBridge::ensureFontLoaded(m_platformData.hfont())) {
+ // Retry GetTextMetrics.
+ // FIXME: Handle gracefully the error if this call also fails.
+ // See http://crbug.com/6401.
+ if (!GetTextMetrics(dc, &textMetric))
+ LOG_ERROR("Unable to get the text metrics after second attempt");
+ }
+ }
+
+ m_treatAsFixedPitch = ((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+}
+
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const
+{
+ return FloatRect();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (!m_platformData.size())
+ return 0;
+
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont());
+
+ int width = 0;
+ if (!GetCharWidthI(dc, glyph, 1, 0, &width)) {
+ // Ask the browser to preload the font and retry.
+ if (ChromiumBridge::ensureFontLoaded(m_platformData.hfont())) {
+ // FIXME: Handle gracefully the error if this call also fails.
+ // See http://crbug.com/6401.
+ if (!GetCharWidthI(dc, glyph, 1, 0, &width))
+ LOG_ERROR("Unable to get the char width after second attempt");
+ }
+ }
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ return static_cast<float>(width);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp
new file mode 100644
index 0000000..355d837
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2008, 2009, 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "Font.h"
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include "Logging.h"
+#include "VDMXParser.h"
+
+#include "SkFontHost.h"
+#include "SkPaint.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkTypes.h"
+
+namespace WebCore {
+
+// Smallcaps versions of fonts are 70% the size of the normal font.
+static const float smallCapsFraction = 0.7f;
+static const float emphasisMarkFraction = .5;
+// This is the largest VDMX table which we'll try to load and parse.
+static const size_t maxVDMXTableSize = 1024 * 1024; // 1 MB
+
+void SimpleFontData::platformInit()
+{
+ if (!m_platformData.size()) {
+ m_ascent = 0;
+ m_descent = 0;
+ m_lineGap = 0;
+ m_lineSpacing = 0;
+ m_avgCharWidth = 0;
+ m_maxCharWidth = 0;
+ m_xHeight = 0;
+ m_unitsPerEm = 0;
+ return;
+ }
+
+ SkPaint paint;
+ SkPaint::FontMetrics metrics;
+
+ m_platformData.setupPaint(&paint);
+ paint.getFontMetrics(&metrics);
+ const SkFontID fontID = m_platformData.uniqueID();
+
+ static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X');
+ int pixelSize = m_platformData.size() + 0.5;
+ int vdmxAscent, vdmxDescent;
+ bool isVDMXValid = false;
+
+ size_t vdmxSize = SkFontHost::GetTableSize(fontID, vdmxTag);
+ if (vdmxSize && vdmxSize < maxVDMXTableSize) {
+ uint8_t* vdmxTable = (uint8_t*) fastMalloc(vdmxSize);
+ if (vdmxTable
+ && SkFontHost::GetTableData(fontID, vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize
+ && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize))
+ isVDMXValid = true;
+ fastFree(vdmxTable);
+ }
+
+ // Beware those who step here: This code is designed to match Win32 font
+ // metrics *exactly*.
+ if (isVDMXValid) {
+ m_ascent = vdmxAscent;
+ m_descent = -vdmxDescent;
+ } else {
+ SkScalar height = -metrics.fAscent + metrics.fDescent + metrics.fLeading;
+ m_ascent = SkScalarRound(-metrics.fAscent);
+ m_descent = SkScalarRound(height) - m_ascent;
+ }
+
+ if (metrics.fXHeight)
+ m_xHeight = metrics.fXHeight;
+ else {
+ // hack taken from the Windows port
+ m_xHeight = static_cast<float>(m_ascent) * 0.56;
+ }
+
+ m_lineGap = SkScalarRound(metrics.fLeading);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ if (m_orientation == Vertical) {
+ static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a');
+ static const uint32_t vorgTag = SkSetFourByteTag('V', 'O', 'R', 'G');
+ size_t vheaSize = SkFontHost::GetTableSize(fontID, vheaTag);
+ size_t vorgSize = SkFontHost::GetTableSize(fontID, vorgTag);
+ if ((vheaSize <= 0) && (vorgSize <= 0))
+ m_orientation = Horizontal;
+ }
+
+ // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is
+ // calculated for us, but we need to calculate m_maxCharWidth and
+ // m_avgCharWidth in order for text entry widgets to be sized correctly.
+
+ SkScalar xRange = metrics.fXMax - metrics.fXMin;
+ m_maxCharWidth = SkScalarRound(xRange * SkScalarRound(m_platformData.size()));
+
+ if (metrics.fAvgCharWidth)
+ m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth);
+ else {
+ m_avgCharWidth = m_xHeight;
+
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+
+ if (glyphPageZero) {
+ static const UChar32 x_char = 'x';
+ const Glyph xGlyph = glyphPageZero->glyphDataForCharacter(x_char).glyph;
+
+ if (xGlyph)
+ m_avgCharWidth = widthForGlyph(xGlyph);
+ }
+ }
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ // charwidths are set in platformInit.
+}
+
+void SimpleFontData::platformDestroy()
+{
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ const float scaledSize = lroundf(fontDescription.computedSize() * scaleFactor);
+ return new SimpleFontData(FontPlatformData(m_platformData, scaledSize), isCustomFont(), false);
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, smallCapsFraction);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, emphasisMarkFraction);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ SkPaint paint;
+ static const unsigned maxBufferCount = 64;
+ uint16_t glyphs[maxBufferCount];
+
+ m_platformData.setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ while (length > 0) {
+ int n = SkMin32(length, SK_ARRAY_COUNT(glyphs));
+
+ // textToGlyphs takes a byte count so we double the character count.
+ int count = paint.textToGlyphs(characters, n * 2, glyphs);
+ for (int i = 0; i < count; i++) {
+ if (0 == glyphs[i])
+ return false; // missing glyph
+ }
+
+ characters += n;
+ length -= n;
+ }
+
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = platformData().isFixedPitch();
+}
+
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const
+{
+ return FloatRect();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (!m_platformData.size())
+ return 0;
+
+ SkASSERT(sizeof(glyph) == 2); // compile-time assert
+
+ SkPaint paint;
+
+ m_platformData.setupPaint(&paint);
+
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ SkScalar width = paint.measureText(&glyph, 2);
+
+ // Though WebKit supports non-integral advances, Skia only supports them
+ // for "subpixel" (distinct from LCD subpixel antialiasing) text, which
+ // we don't use.
+ return round(SkScalarToFloat(width));
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/TextureManager.cpp b/Source/WebCore/platform/graphics/chromium/TextureManager.cpp
new file mode 100644
index 0000000..9579ef9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/TextureManager.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "TextureManager.h"
+
+#include "LayerRendererChromium.h"
+
+namespace WebCore {
+
+static size_t memoryUseBytes(IntSize size, unsigned textureFormat)
+{
+ // FIXME: This assumes all textures are 4 bytes/pixel, like RGBA.
+ return size.width() * size.height() * 4;
+}
+
+TextureManager::TextureManager(GraphicsContext3D* context, size_t memoryLimitBytes, int maxTextureSize)
+ : m_context(context)
+ , m_memoryLimitBytes(memoryLimitBytes)
+ , m_memoryUseBytes(0)
+ , m_maxTextureSize(maxTextureSize)
+ , m_nextToken(1)
+{
+}
+
+TextureToken TextureManager::getToken()
+{
+ return m_nextToken++;
+}
+
+void TextureManager::releaseToken(TextureToken token)
+{
+ TextureMap::iterator it = m_textures.find(token);
+ if (it != m_textures.end())
+ removeTexture(token, it->second);
+}
+
+bool TextureManager::hasTexture(TextureToken token)
+{
+ if (m_textures.contains(token)) {
+ // If someone asks about a texture put it at the end of the LRU list.
+ m_textureLRUSet.remove(token);
+ m_textureLRUSet.add(token);
+ return true;
+ }
+ return false;
+}
+
+void TextureManager::protectTexture(TextureToken token)
+{
+ ASSERT(hasTexture(token));
+ ASSERT(!m_textures.get(token).isProtected);
+ TextureInfo info = m_textures.take(token);
+ info.isProtected = true;
+ m_textures.add(token, info);
+}
+
+void TextureManager::unprotectTexture(TextureToken token)
+{
+ TextureMap::iterator it = m_textures.find(token);
+ if (it != m_textures.end()) {
+ TextureInfo info = it->second;
+ if (info.isProtected) {
+ info.isProtected = false;
+ m_textures.remove(it);
+ m_textures.add(token, info);
+ }
+ }
+}
+
+bool TextureManager::reduceMemoryToLimit(size_t limit)
+{
+ while (m_memoryUseBytes > limit) {
+ ASSERT(!m_textureLRUSet.isEmpty());
+ bool foundCandidate = false;
+ for (ListHashSet<TextureToken>::iterator lruIt = m_textureLRUSet.begin(); lruIt != m_textureLRUSet.end(); ++lruIt) {
+ TextureToken token = *lruIt;
+ TextureInfo info = m_textures.get(token);
+ if (info.isProtected)
+ continue;
+ removeTexture(token, info);
+ foundCandidate = true;
+ break;
+ }
+ if (!foundCandidate)
+ return false;
+ }
+ return true;
+}
+
+void TextureManager::addTexture(TextureToken token, TextureInfo info)
+{
+ ASSERT(!m_textureLRUSet.contains(token));
+ ASSERT(!m_textures.contains(token));
+ m_memoryUseBytes += memoryUseBytes(info.size, info.format);
+ m_textures.set(token, info);
+ m_textureLRUSet.add(token);
+}
+
+void TextureManager::removeTexture(TextureToken token, TextureInfo info)
+{
+ ASSERT(m_textureLRUSet.contains(token));
+ ASSERT(m_textures.contains(token));
+ m_memoryUseBytes -= memoryUseBytes(info.size, info.format);
+ m_textures.remove(token);
+ ASSERT(m_textureLRUSet.contains(token));
+ m_textureLRUSet.remove(token);
+ GLC(m_context.get(), m_context->deleteTexture(info.textureId));
+}
+
+unsigned TextureManager::requestTexture(TextureToken token, IntSize size, unsigned format, bool* newTexture)
+{
+ if (size.width() > m_maxTextureSize || size.height() > m_maxTextureSize)
+ return 0;
+
+ TextureMap::iterator it = m_textures.find(token);
+ if (it != m_textures.end()) {
+ ASSERT(it->second.size != size || it->second.format != format);
+ removeTexture(token, it->second);
+ }
+
+ size_t memoryRequiredBytes = memoryUseBytes(size, format);
+ if (memoryRequiredBytes > m_memoryLimitBytes || !reduceMemoryToLimit(m_memoryLimitBytes - memoryRequiredBytes))
+ return 0;
+
+ unsigned textureId = m_context->createTexture();
+ GLC(m_context.get(), textureId = m_context->createTexture());
+ GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
+ // Do basic linear filtering on resize.
+ GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
+ GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
+ // NPOT textures in GL ES only work when the wrap mode is set to GraphicsContext3D::CLAMP_TO_EDGE.
+ GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
+ GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));
+ GLC(m_context.get(), m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GraphicsContext3D::UNSIGNED_BYTE));
+ TextureInfo info;
+ info.size = size;
+ info.format = format;
+ info.textureId = textureId;
+ info.isProtected = true;
+ addTexture(token, info);
+ return textureId;
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/TextureManager.h b/Source/WebCore/platform/graphics/chromium/TextureManager.h
new file mode 100644
index 0000000..1e850cd
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/TextureManager.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 TextureManager_h
+#define TextureManager_h
+
+#include "GraphicsContext3D.h"
+#include "IntRect.h"
+#include "IntSize.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/ListHashSet.h>
+
+namespace WebCore {
+
+typedef int TextureToken;
+
+class TextureManager : public Noncopyable {
+public:
+ static PassOwnPtr<TextureManager> create(GraphicsContext3D* context, size_t memoryLimitBytes, int maxTextureSize)
+ {
+ return adoptPtr(new TextureManager(context, memoryLimitBytes, maxTextureSize));
+ }
+
+ TextureToken getToken();
+ void releaseToken(TextureToken);
+ bool hasTexture(TextureToken);
+
+ unsigned requestTexture(TextureToken, IntSize, unsigned textureFormat, bool* newTexture = 0);
+
+ void protectTexture(TextureToken);
+ void unprotectTexture(TextureToken);
+
+private:
+ TextureManager(GraphicsContext3D*, size_t memoryLimitBytes, int maxTextureSize);
+
+ struct TextureInfo {
+ IntSize size;
+ unsigned format;
+ unsigned textureId;
+ bool isProtected;
+ };
+
+ bool reduceMemoryToLimit(size_t);
+ void addTexture(TextureToken, TextureInfo);
+ void removeTexture(TextureToken, TextureInfo);
+
+ RefPtr<GraphicsContext3D> m_context;
+
+ typedef HashMap<TextureToken, TextureInfo> TextureMap;
+ TextureMap m_textures;
+ ListHashSet<TextureToken> m_textureLRUSet;
+
+ size_t m_memoryLimitBytes;
+ size_t m_memoryUseBytes;
+ int m_maxTextureSize;
+ TextureToken m_nextToken;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp
new file mode 100644
index 0000000..4dc2157
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#include "config.h"
+#include <windows.h>
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "PlatformContextSkia.h"
+#include "SimpleFontData.h"
+#include "TransparencyWin.h"
+
+#include "SkColorPriv.h"
+#include "skia/ext/platform_canvas.h"
+
+namespace WebCore {
+
+namespace {
+
+// The maximum size in pixels of the buffer we'll keep around for drawing text
+// into. Buffers larger than this will be destroyed when we're done with them.
+const int maxCachedBufferPixelSize = 65536;
+
+inline skia::PlatformCanvas* canvasForContext(const GraphicsContext& context)
+{
+ return context.platformContext()->canvas();
+}
+
+inline const SkBitmap& bitmapForContext(const GraphicsContext& context)
+{
+ return canvasForContext(context)->getTopPlatformDevice().accessBitmap(false);
+}
+
+void compositeToCopy(const GraphicsContext& sourceLayers,
+ GraphicsContext& destContext,
+ const AffineTransform& matrix)
+{
+ // Make a list of all devices. The iterator goes top-down, and we want
+ // bottom-up. Note that each layer can also have an offset in canvas
+ // coordinates, which is the (x, y) position.
+ struct DeviceInfo {
+ DeviceInfo(SkDevice* d, int lx, int ly)
+ : device(d)
+ , x(lx)
+ , y(ly) {}
+ SkDevice* device;
+ int x;
+ int y;
+ };
+ Vector<DeviceInfo> devices;
+ SkCanvas* sourceCanvas = canvasForContext(sourceLayers);
+ SkCanvas::LayerIter iter(sourceCanvas, false);
+ while (!iter.done()) {
+ devices.append(DeviceInfo(iter.device(), iter.x(), iter.y()));
+ iter.next();
+ }
+
+ // Create a temporary canvas for the compositing into the destination.
+ SkBitmap* destBmp = const_cast<SkBitmap*>(&bitmapForContext(destContext));
+ SkCanvas destCanvas(*destBmp);
+ destCanvas.setMatrix(matrix);
+
+ for (int i = devices.size() - 1; i >= 0; i--) {
+ const SkBitmap& srcBmp = devices[i].device->accessBitmap(false);
+
+ SkRect destRect;
+ destRect.fLeft = devices[i].x;
+ destRect.fTop = devices[i].y;
+ destRect.fRight = destRect.fLeft + srcBmp.width();
+ destRect.fBottom = destRect.fTop + srcBmp.height();
+
+ destCanvas.drawBitmapRect(srcBmp, 0, destRect);
+ }
+}
+
+} // namespace
+
+// If either of these pointers is non-null, both must be valid and point to
+// bitmaps of the same size.
+class TransparencyWin::OwnedBuffers {
+public:
+ OwnedBuffers(const IntSize& size, bool needReferenceBuffer)
+ {
+ m_destBitmap = ImageBuffer::create(size);
+
+ if (needReferenceBuffer) {
+ m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
+ m_referenceBitmap.allocPixels();
+ m_referenceBitmap.eraseARGB(0, 0, 0, 0);
+ }
+ }
+
+ ImageBuffer* destBitmap() { return m_destBitmap.get(); }
+
+ // This bitmap will be empty if you don't specify needReferenceBuffer to the
+ // constructor.
+ SkBitmap* referenceBitmap() { return &m_referenceBitmap; }
+
+ // Returns whether the current layer will fix a buffer of the given size.
+ bool canHandleSize(const IntSize& size) const
+ {
+ return m_destBitmap->size().width() >= size.width() && m_destBitmap->size().height() >= size.height();
+ }
+
+private:
+ // The destination bitmap we're drawing into.
+ OwnPtr<ImageBuffer> m_destBitmap;
+
+ // This could be an ImageBuffer but this is an optimization. Since this is
+ // only ever used as a reference, we don't need to make a full
+ // PlatformCanvas using Skia on Windows. Just allocating a regular SkBitmap
+ // is much faster since it's just a Malloc rather than a GDI call.
+ SkBitmap m_referenceBitmap;
+};
+
+TransparencyWin::OwnedBuffers* TransparencyWin::m_cachedBuffers = 0;
+
+TransparencyWin::TransparencyWin()
+ : m_destContext(0)
+ , m_orgTransform()
+ , m_layerMode(NoLayer)
+ , m_transformMode(KeepTransform)
+ , m_drawContext(0)
+ , m_savedOnDrawContext(false)
+ , m_layerBuffer(0)
+ , m_referenceBitmap(0)
+ , m_validLayer(false)
+{
+}
+
+TransparencyWin::~TransparencyWin()
+{
+ // This should be false, since calling composite() is mandatory.
+ ASSERT(!m_savedOnDrawContext);
+}
+
+void TransparencyWin::composite()
+{
+ // Matches the save() in initializeNewTextContext (or the constructor for
+ // SCALE) to put the context back into the same state we found it.
+ if (m_savedOnDrawContext) {
+ m_drawContext->restore();
+ m_savedOnDrawContext = false;
+ }
+
+ switch (m_layerMode) {
+ case NoLayer:
+ break;
+ case OpaqueCompositeLayer:
+ case WhiteLayer:
+ compositeOpaqueComposite();
+ break;
+ case TextComposite:
+ compositeTextComposite();
+ break;
+ }
+}
+
+void TransparencyWin::init(GraphicsContext* dest,
+ LayerMode layerMode,
+ TransformMode transformMode,
+ const IntRect& region)
+{
+ m_destContext = dest;
+ m_orgTransform = dest->getCTM();
+ m_layerMode = layerMode;
+ m_transformMode = transformMode;
+ m_sourceRect = region;
+
+ computeLayerSize();
+ setupLayer();
+ setupTransform(region);
+}
+
+void TransparencyWin::computeLayerSize()
+{
+ if (m_transformMode == Untransform) {
+ // The meaning of the "transformed" source rect is a little ambigous
+ // here. The rest of the code doesn't care about it in the Untransform
+ // case since we're using our own happy coordinate system. So we set it
+ // to be the source rect since that matches how the code below actually
+ // uses the variable: to determine how to translate things to account
+ // for the offset of the layer.
+ m_transformedSourceRect = m_sourceRect;
+ m_layerSize = IntSize(m_sourceRect.width(), m_sourceRect.height());
+ } else {
+ m_transformedSourceRect = m_orgTransform.mapRect(m_sourceRect);
+ m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSourceRect.height());
+ }
+}
+
+void TransparencyWin::setupLayer()
+{
+ switch (m_layerMode) {
+ case NoLayer:
+ setupLayerForNoLayer();
+ break;
+ case OpaqueCompositeLayer:
+ setupLayerForOpaqueCompositeLayer();
+ break;
+ case TextComposite:
+ setupLayerForTextComposite();
+ break;
+ case WhiteLayer:
+ setupLayerForWhiteLayer();
+ break;
+ }
+}
+
+void TransparencyWin::setupLayerForNoLayer()
+{
+ m_drawContext = m_destContext; // Draw to the source context.
+ m_validLayer = true;
+}
+
+void TransparencyWin::setupLayerForOpaqueCompositeLayer()
+{
+ initializeNewContext();
+ if (!m_validLayer)
+ return;
+
+ AffineTransform mapping;
+ mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
+ if (m_transformMode == Untransform){
+ // Compute the inverse mapping from the canvas space to the
+ // coordinate space of our bitmap.
+ mapping = m_orgTransform.inverse() * mapping;
+ }
+ compositeToCopy(*m_destContext, *m_drawContext, mapping);
+
+ // Save the reference layer so we can tell what changed.
+ SkCanvas referenceCanvas(*m_referenceBitmap);
+ referenceCanvas.drawBitmap(bitmapForContext(*m_drawContext), 0, 0);
+ // Layer rect represents the part of the original layer.
+}
+
+void TransparencyWin::setupLayerForTextComposite()
+{
+ ASSERT(m_transformMode == KeepTransform);
+ // Fall through to filling with white.
+ setupLayerForWhiteLayer();
+}
+
+void TransparencyWin::setupLayerForWhiteLayer()
+{
+ initializeNewContext();
+ if (!m_validLayer)
+ return;
+
+ m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white, ColorSpaceDeviceRGB);
+ // Layer rect represents the part of the original layer.
+}
+
+void TransparencyWin::setupTransform(const IntRect& region)
+{
+ switch (m_transformMode) {
+ case KeepTransform:
+ setupTransformForKeepTransform(region);
+ break;
+ case Untransform:
+ setupTransformForUntransform();
+ break;
+ case ScaleTransform:
+ setupTransformForScaleTransform();
+ break;
+ }
+}
+
+void TransparencyWin::setupTransformForKeepTransform(const IntRect& region)
+{
+ if (!m_validLayer)
+ return;
+
+ if (m_layerMode != NoLayer) {
+ // Need to save things since we're modifying the transform.
+ m_drawContext->save();
+ m_savedOnDrawContext = true;
+
+ // Account for the fact that the layer may be offset from the
+ // original. This only happens when we create a layer that has the
+ // same coordinate space as the parent.
+ AffineTransform xform;
+ xform.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
+
+ // We're making a layer, so apply the old transform to the new one
+ // so it's maintained. We know the new layer has the identity
+ // transform now, we we can just multiply it.
+ xform = m_orgTransform * xform;
+ m_drawContext->concatCTM(xform);
+ }
+ m_drawRect = m_sourceRect;
+}
+
+void TransparencyWin::setupTransformForUntransform()
+{
+ ASSERT(m_layerMode != NoLayer);
+ // We now have a new layer with the identity transform, which is the
+ // Untransformed space we'll use for drawing.
+ m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
+}
+
+void TransparencyWin::setupTransformForScaleTransform()
+{
+ if (!m_validLayer)
+ return;
+
+ if (m_layerMode == NoLayer) {
+ // Need to save things since we're modifying the layer.
+ m_drawContext->save();
+ m_savedOnDrawContext = true;
+
+ // Undo the transform on the current layer when we're re-using the
+ // current one.
+ m_drawContext->concatCTM(m_drawContext->getCTM().inverse());
+
+ // We're drawing to the original layer with just a different size.
+ m_drawRect = m_transformedSourceRect;
+ } else {
+ // Just go ahead and use the layer's coordinate space to draw into.
+ // It will have the scaled size, and an identity transform loaded.
+ m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
+ }
+}
+
+void TransparencyWin::setTextCompositeColor(Color color)
+{
+ m_textCompositeColor = color;
+}
+
+void TransparencyWin::initializeNewContext()
+{
+ int pixelSize = m_layerSize.width() * m_layerSize.height();
+ if (pixelSize <= 0)
+ return;
+
+ if (pixelSize > maxCachedBufferPixelSize) {
+ // Create a 1-off buffer for drawing into. We only need the reference
+ // buffer if we're making an OpaqueCompositeLayer.
+ bool needReferenceBitmap = m_layerMode == OpaqueCompositeLayer;
+ m_ownedBuffers.set(new OwnedBuffers(m_layerSize, needReferenceBitmap));
+ m_layerBuffer = m_ownedBuffers->destBitmap();
+ if (!m_layerBuffer)
+ return;
+
+ m_drawContext = m_layerBuffer->context();
+ if (needReferenceBitmap) {
+ m_referenceBitmap = m_ownedBuffers->referenceBitmap();
+ if (!m_referenceBitmap || !m_referenceBitmap->getPixels())
+ return;
+ }
+ m_validLayer = true;
+ return;
+ }
+
+ if (m_cachedBuffers && m_cachedBuffers->canHandleSize(m_layerSize)) {
+ // We can re-use the existing buffer. We don't need to clear it since
+ // all layer modes will clear it in their initialization.
+ m_layerBuffer = m_cachedBuffers->destBitmap();
+ m_drawContext = m_cachedBuffers->destBitmap()->context();
+ bitmapForContext(*m_drawContext).eraseARGB(0, 0, 0, 0);
+ m_referenceBitmap = m_cachedBuffers->referenceBitmap();
+ m_referenceBitmap->eraseARGB(0, 0, 0, 0);
+ m_validLayer = true;
+ return;
+ }
+
+ // Create a new cached buffer.
+ if (m_cachedBuffers)
+ delete m_cachedBuffers;
+ m_cachedBuffers = new OwnedBuffers(m_layerSize, true);
+
+ m_layerBuffer = m_cachedBuffers->destBitmap();
+ m_drawContext = m_cachedBuffers->destBitmap()->context();
+ m_referenceBitmap = m_cachedBuffers->referenceBitmap();
+ m_validLayer = true;
+}
+
+void TransparencyWin::compositeOpaqueComposite()
+{
+ if (!m_validLayer)
+ return;
+
+ SkCanvas* destCanvas = canvasForContext(*m_destContext);
+ destCanvas->save();
+
+ SkBitmap* bitmap = const_cast<SkBitmap*>(
+ &bitmapForContext(*m_layerBuffer->context()));
+
+ // This function will be called for WhiteLayer as well, which we don't want
+ // to change.
+ if (m_layerMode == OpaqueCompositeLayer) {
+ // Fix up our bitmap, making it contain only the pixels which changed
+ // and transparent everywhere else.
+ SkAutoLockPixels sourceLock(*m_referenceBitmap);
+ SkAutoLockPixels lock(*bitmap);
+ for (int y = 0; y < bitmap->height(); y++) {
+ uint32_t* source = m_referenceBitmap->getAddr32(0, y);
+ uint32_t* dest = bitmap->getAddr32(0, y);
+ for (int x = 0; x < bitmap->width(); x++) {
+ // Clear out any pixels that were untouched.
+ if (dest[x] == source[x])
+ dest[x] = 0;
+ else
+ dest[x] |= (0xFF << SK_A32_SHIFT);
+ }
+ }
+ } else
+ makeLayerOpaque();
+
+ SkRect destRect;
+ if (m_transformMode != Untransform) {
+ // We want to use Untransformed space.
+ //
+ // Note that we DON'T call m_layerBuffer->image() here. This actually
+ // makes a copy of the image, which is unnecessary and slow. Instead, we
+ // just draw the image from inside the destination context.
+ SkMatrix identity;
+ identity.reset();
+ destCanvas->setMatrix(identity);
+
+ destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom());
+ } else
+ destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.right(), m_sourceRect.bottom());
+
+ SkPaint paint;
+ paint.setFilterBitmap(true);
+ paint.setAntiAlias(true);
+
+ // Note that we need to specify the source layer subset, since the bitmap
+ // may have been cached and it could be larger than what we're using.
+ SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
+ destCanvas->drawBitmapRect(*bitmap, &sourceRect, destRect, &paint);
+ destCanvas->restore();
+}
+
+void TransparencyWin::compositeTextComposite()
+{
+ if (!m_validLayer)
+ return;
+
+ const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopPlatformDevice().accessBitmap(true);
+ SkColor textColor = m_textCompositeColor.rgb();
+ for (int y = 0; y < m_layerSize.height(); y++) {
+ uint32_t* row = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_layerSize.width(); x++) {
+ // The alpha is the average of the R, G, and B channels.
+ int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) + SkGetPackedB32(row[x])) / 3;
+
+ // Apply that alpha to the text color and write the result.
+ row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha));
+ }
+ }
+
+ // Now the layer has text with the proper color and opacity.
+ SkCanvas* destCanvas = canvasForContext(*m_destContext);
+ destCanvas->save();
+
+ // We want to use Untransformed space (see above)
+ SkMatrix identity;
+ identity.reset();
+ destCanvas->setMatrix(identity);
+ SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom() };
+
+ // Note that we need to specify the source layer subset, since the bitmap
+ // may have been cached and it could be larger than what we're using.
+ SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
+ destCanvas->drawBitmapRect(bitmap, &sourceRect, destRect, 0);
+ destCanvas->restore();
+}
+
+void TransparencyWin::makeLayerOpaque()
+{
+ if (!m_validLayer)
+ return;
+
+ SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->platformContext()->
+ canvas()->getTopPlatformDevice().accessBitmap(true));
+ for (int y = 0; y < m_layerSize.height(); y++) {
+ uint32_t* row = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_layerSize.width(); x++)
+ row[x] |= 0xFF000000;
+ }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/TransparencyWin.h b/Source/WebCore/platform/graphics/chromium/TransparencyWin.h
new file mode 100644
index 0000000..b6bef91
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/TransparencyWin.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2009 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 TransparencyWin_h
+#define TransparencyWin_h
+
+#include <windows.h>
+
+#include "AffineTransform.h"
+#include "ImageBuffer.h"
+#include "Noncopyable.h"
+#include "wtf/OwnPtr.h"
+
+class SkBitmap;
+class SkCanvas;
+
+namespace WebCore {
+
+class GraphicsContext;
+class TransparencyWin_NoLayer_Test;
+class TransparencyWin_WhiteLayer_Test;
+class TransparencyWin_TextComposite_Test;
+class TransparencyWin_OpaqueCompositeLayer_Test;
+
+// Helper class that abstracts away drawing ClearType text and Windows form
+// controls either to the original context directly, or to an offscreen context
+// that is composited later manually. This is to get around Windows' inability
+// to handle the alpha channel, semitransparent text, and transformed form
+// controls.
+class TransparencyWin : public Noncopyable {
+public:
+ enum LayerMode {
+ // No extra layer is created. Drawing will happen to the source.
+ // Valid only with KeepTransform and ScaleTransform. The region being
+ // drawn onto must be opaque, since the modified region will be forced
+ // to opaque when drawing is complete.
+ NoLayer,
+
+ // Makes a temporary layer consisting of the composited layers below
+ // it. This result must be opaque. When complete, the result will be
+ // compared to the original, and the difference will be added to a thee
+ // destination layer.
+ //
+ // This mode only works if the lower layers are opque (normally the
+ // case for a web page) and layers are only drawn in the stack order,
+ // meaning you can never draw underneath a layer.
+ //
+ // This doesn't technically produce the correct answer in all cases. If
+ // you have an opaque base, a transparency layer, than a semitransparent
+ // drawing on top, the result will actually be blended in twice. But
+ // this isn't a very important case. This mode is used for form
+ // controls which are always opaque except for occationally some
+ // antialiasing. It means form control antialiasing will be too light in
+ // some cases, but only if you have extra layers.
+ OpaqueCompositeLayer,
+
+ // Allows semitransparent text to be drawn on any background (even if it
+ // is itself semitransparent), but disables ClearType.
+ //
+ // It makes a trmporary layer filled with white. This is composited with
+ // the lower layer with a custom color applied to produce the result.
+ // The caller must draw the text in black, and set the desired final
+ // text color by calling setTextCompositeColor().
+ //
+ // Only valid with KeepTransform, which is the only mode where drawing
+ // text in this fashion makes sense.
+ TextComposite,
+
+ // Makes a temporary layer filled with white. When complete, the layer
+ // will be forced to be opqaue (since Windows may have messed up the
+ // alpha channel) and composited down. Any areas not drawn into will
+ // remain white.
+ //
+ // This is the mode of last resort. If the opacity of the final image
+ // is unknown and we can't do the text trick (since we know its color),
+ // then we have to live with potential white halos. This is used for
+ // form control drawing, for example.
+ WhiteLayer,
+ };
+
+ enum TransformMode {
+ // There are no changes to the transform. Use this when drawing
+ // horizontal text. The current transform must not have rotation.
+ KeepTransform,
+
+ // Drawing happens in an Untransformed space, and then that bitmap is
+ // transformed according to the current context when it is copied down.
+ // Requires that a layer be created (layer mode is not NoLayer).
+ Untransform,
+
+ // When the current transform only has a scaling factor applied and
+ // you're drawing form elements, use this parameter. This will unscale
+ // the coordinate space, so the OS will just draw the form controls
+ // larger or smaller depending on the destination size.
+ ScaleTransform,
+ };
+
+ // You MUST call init() below.
+ // |region| is expressed relative to the current transformation.
+ TransparencyWin();
+ ~TransparencyWin();
+
+ // Initializes the members if you use the 0-argument constructor. Don't call
+ // this if you use the multiple-argument constructor.
+ void init(GraphicsContext* dest,
+ LayerMode layerMode,
+ TransformMode transformMode,
+ const IntRect& region);
+
+ // Combines the source and destination bitmaps using the given mode.
+ // Calling this function before the destructor runs is mandatory in most
+ // cases, and harmless otherwise. The mandatory cases are:
+ // (m_layerMode != NoLayer) || (m_transformMode == ScaleTransform)
+ void composite();
+
+ // Returns the context for drawing into, which may be the destination
+ // context, or a temporary one.
+ GraphicsContext* context() const { return m_drawContext; }
+
+ PlatformGraphicsContext* platformContext() const { return m_drawContext ? m_drawContext->platformContext() : 0; }
+
+ // When the mode is TextComposite, this sets the color that the text will
+ // get. See the enum above for more.
+ void setTextCompositeColor(Color color);
+
+ // Returns the input bounds translated into the destination space. This is
+ // not necessary for KeepTransform since the rectangle will be unchanged.
+ const IntRect& drawRect() { return m_drawRect; }
+
+private:
+ friend TransparencyWin_NoLayer_Test;
+ friend TransparencyWin_WhiteLayer_Test;
+ friend TransparencyWin_TextComposite_Test;
+ friend TransparencyWin_OpaqueCompositeLayer_Test;
+
+ class OwnedBuffers;
+
+ void computeLayerSize();
+
+ // Sets up a new layer, if any. setupLayer() will call the appopriate layer-
+ // specific helper. Must be called after computeLayerSize();
+ void setupLayer();
+ void setupLayerForNoLayer();
+ void setupLayerForOpaqueCompositeLayer();
+ void setupLayerForTextComposite();
+ void setupLayerForWhiteLayer();
+
+ // Sets up the transformation on the newly created layer. setupTransform()
+ // will call the appropriate transform-specific helper. Must be called after
+ // setupLayer().
+ void setupTransform(const IntRect& region);
+ void setupTransformForKeepTransform(const IntRect& region);
+ void setupTransformForUntransform();
+ void setupTransformForScaleTransform();
+
+ void initializeNewContext();
+
+ void compositeOpaqueComposite();
+ void compositeTextComposite();
+
+ // Fixes the alpha channel to make the region inside m_transformedRect
+ // opaque.
+ void makeLayerOpaque();
+
+ // The context our drawing will eventually end up in.
+ GraphicsContext* m_destContext;
+
+ // The original transform from the destination context.
+ AffineTransform m_orgTransform;
+
+ LayerMode m_layerMode;
+ TransformMode m_transformMode;
+
+ // The rectangle we're drawing in the destination's coordinate space
+ IntRect m_sourceRect;
+
+ // The source rectangle transformed into pixels in the final image. For
+ // Untransform this has no meaning, since the destination might not be a
+ // rectangle.
+ IntRect m_transformedSourceRect;
+
+ // The size of the layer we created. If there's no layer, this is the size
+ // of the region we're using in the source.
+ IntSize m_layerSize;
+
+ // The rectangle we're drawing to in the draw context's coordinate space.
+ // This will be the same as the source rectangle except for ScaleTransform
+ // where we create a new virtual coordinate space for the layer.
+ IntRect m_drawRect;
+
+ // Points to the graphics context to draw text to, which will either be
+ // the original context or the copy, depending on our mode.
+ GraphicsContext* m_drawContext;
+
+ // This flag is set when we call save() on the draw context during
+ // initialization. It allows us to avoid doing an extra save()/restore()
+ // when one is unnecessary.
+ bool m_savedOnDrawContext;
+
+ // Used only when m_mode = TextComposite, this is the color that the text
+ // will end up being once we figure out the transparency.
+ Color m_textCompositeColor;
+
+ // Layer we're drawing to.
+ ImageBuffer* m_layerBuffer;
+
+ // When the layer type is OpaqueCompositeLayer, this will contain a copy
+ // of the original contents of the m_layerBuffer before Windows drew on it.
+ // It allows us to re-create what Windows did to the layer. It is an
+ // SkBitmap instead of an ImageBuffer because an SkBitmap is lighter-weight
+ // (ImageBuffers are also GDI surfaces, which we don't need here).
+ SkBitmap* m_referenceBitmap;
+
+ // If the given size of bitmap can be cached, they will be stored here. Both
+ // the bitmap and the reference are guaranteed to be allocated if this
+ // member is non-null.
+ static OwnedBuffers* m_cachedBuffers;
+
+ // If a buffer was too big to be cached, it will be created temporarily, and
+ // this member tracks its scope to make sure it gets deleted. Always use
+ // m_layerBuffer, which will either point to this object, or the statically
+ // cached one. Don't access directly.
+ OwnPtr<OwnedBuffers> m_ownedBuffers;
+
+ // Sometimes we're asked to create layers that have negative dimensions.
+ // This API is not designed to fail to initialize, so we hide the fact
+ // that they are illegal and can't be rendered (failing silently, drawing
+ // nothing).
+ bool m_validLayer;
+};
+
+} // namespace WebCore
+
+#endif // TransaprencyWin_h
diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
new file mode 100644
index 0000000..dda84a9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 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.
+ */
+
+#include "config.h"
+#include "UniscribeHelper.h"
+
+#include <windows.h>
+
+#include "FontUtilsChromiumWin.h"
+#include "PlatformContextSkia.h"
+#include "SkiaFontWin.h"
+#include "SkPoint.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+// This function is used to see where word spacing should be applied inside
+// runs. Note that this must match Font::treatAsSpace so we all agree where
+// and how much space this is, so we don't want to do more general Unicode
+// "is this a word break" thing.
+static bool treatAsSpace(UChar c)
+{
+ return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0;
+}
+
+// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid
+// and blank glyphs. Just because ScriptShape succeeds does not mean
+// that a text run is rendered correctly. Some characters may be rendered
+// with default/invalid/blank glyphs. Therefore, we need to check if the glyph
+// array returned by ScriptShape contains any of those glyphs to make
+// sure that the text run is rendered successfully.
+static bool containsMissingGlyphs(WORD *glyphs,
+ int length,
+ SCRIPT_FONTPROPERTIES* properties)
+{
+ for (int i = 0; i < length; ++i) {
+ if (glyphs[i] == properties->wgDefault
+ || (glyphs[i] == properties->wgInvalid
+ && glyphs[i] != properties->wgBlank))
+ return true;
+ }
+
+ return false;
+}
+
+// HFONT is the 'incarnation' of 'everything' about font, but it's an opaque
+// handle and we can't directly query it to make a new HFONT sharing
+// its characteristics (height, style, etc) except for family name.
+// This function uses GetObject to convert HFONT back to LOGFONT,
+// resets the fields of LOGFONT and calculates style to use later
+// for the creation of a font identical to HFONT other than family name.
+static void setLogFontAndStyle(HFONT hfont, LOGFONT *logfont, int *style)
+{
+ ASSERT(hfont && logfont);
+ if (!hfont || !logfont)
+ return;
+
+ GetObject(hfont, sizeof(LOGFONT), logfont);
+ // We reset these fields to values appropriate for CreateFontIndirect.
+ // while keeping lfHeight, which is the most important value in creating
+ // a new font similar to hfont.
+ logfont->lfWidth = 0;
+ logfont->lfEscapement = 0;
+ logfont->lfOrientation = 0;
+ logfont->lfCharSet = DEFAULT_CHARSET;
+ logfont->lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ logfont->lfQuality = DEFAULT_QUALITY; // Honor user's desktop settings.
+ logfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ if (style)
+ *style = getStyleFromLogfont(logfont);
+}
+
+UniscribeHelper::UniscribeHelper(const UChar* input,
+ int inputLength,
+ bool isRtl,
+ HFONT hfont,
+ SCRIPT_CACHE* scriptCache,
+ SCRIPT_FONTPROPERTIES* fontProperties)
+ : m_input(input)
+ , m_inputLength(inputLength)
+ , m_isRtl(isRtl)
+ , m_hfont(hfont)
+ , m_scriptCache(scriptCache)
+ , m_fontProperties(fontProperties)
+ , m_directionalOverride(false)
+ , m_inhibitLigate(false)
+ , m_letterSpacing(0)
+ , m_spaceWidth(0)
+ , m_wordSpacing(0)
+ , m_ascent(0)
+ , m_disableFontFallback(false)
+
+{
+ m_logfont.lfFaceName[0] = 0;
+}
+
+UniscribeHelper::~UniscribeHelper()
+{
+}
+
+void UniscribeHelper::initWithOptionalLengthProtection(bool lengthProtection)
+{
+ // We cap the input length and just don't do anything. We'll allocate a lot
+ // of things of the size of the number of characters, so the allocated
+ // memory will be several times the input length. Plus shaping such a large
+ // buffer may be a form of denial of service. No legitimate text should be
+ // this long. It also appears that Uniscribe flatly rejects very long
+ // strings, so we don't lose anything by doing this.
+ //
+ // The input length protection may be disabled by the unit tests to cause
+ // an error condition.
+ static const int kMaxInputLength = 65535;
+ if (m_inputLength == 0 || (lengthProtection && m_inputLength > kMaxInputLength))
+ return;
+
+ fillRuns();
+ fillShapes();
+ fillScreenOrder();
+}
+
+int UniscribeHelper::width() const
+{
+ int width = 0;
+ for (int itemIndex = 0; itemIndex < static_cast<int>(m_runs.size()); itemIndex++)
+ width += advanceForItem(itemIndex);
+ return width;
+}
+
+void UniscribeHelper::justify(int additionalSpace)
+{
+ // Count the total number of glyphs we have so we know how big to make the
+ // buffers below.
+ int totalGlyphs = 0;
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ int runIndex = m_screenOrder[run];
+ totalGlyphs += static_cast<int>(m_shapes[runIndex].glyphLength());
+ }
+ if (totalGlyphs == 0)
+ return; // Nothing to do.
+
+ // We make one big buffer in screen order of all the glyphs we are drawing
+ // across runs so that the justification function will adjust evenly across
+ // all glyphs.
+ Vector<SCRIPT_VISATTR, 64> visualAttributes;
+ visualAttributes.resize(totalGlyphs);
+ Vector<int, 64> advances;
+ advances.resize(totalGlyphs);
+ Vector<int, 64> justify;
+ justify.resize(totalGlyphs);
+
+ // Build the packed input.
+ int destIndex = 0;
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ int runIndex = m_screenOrder[run];
+ const Shaping& shaping = m_shapes[runIndex];
+
+ for (int i = 0; i < shaping.glyphLength(); i++, destIndex++) {
+ memcpy(&visualAttributes[destIndex], &shaping.m_visualAttributes[i],
+ sizeof(SCRIPT_VISATTR));
+ advances[destIndex] = shaping.m_advance[i];
+ }
+ }
+
+ // The documentation for Scriptjustify is wrong, the parameter is the space
+ // to add and not the width of the column you want.
+ const int minKashida = 1; // How do we decide what this should be?
+ ScriptJustify(&visualAttributes[0], &advances[0], totalGlyphs,
+ additionalSpace, minKashida, &justify[0]);
+
+ // Now we have to unpack the justification amounts back into the runs so
+ // the glyph indices match.
+ int globalGlyphIndex = 0;
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ int runIndex = m_screenOrder[run];
+ Shaping& shaping = m_shapes[runIndex];
+
+ shaping.m_justify.resize(shaping.glyphLength());
+ for (int i = 0; i < shaping.glyphLength(); i++, globalGlyphIndex++)
+ shaping.m_justify[i] = justify[globalGlyphIndex];
+ }
+}
+
+int UniscribeHelper::characterToX(int offset) const
+{
+ HRESULT hr;
+ ASSERT(offset <= m_inputLength);
+
+ // Our algorithm is to traverse the items in screen order from left to
+ // right, adding in each item's screen width until we find the item with
+ // the requested character in it.
+ int width = 0;
+ for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
+ // Compute the length of this run.
+ int itemIndex = m_screenOrder[screenIndex];
+ const SCRIPT_ITEM& item = m_runs[itemIndex];
+ const Shaping& shaping = m_shapes[itemIndex];
+ int itemLength = shaping.charLength();
+
+ if (offset >= item.iCharPos && offset <= item.iCharPos + itemLength) {
+ // Character offset is in this run.
+ int charLength = offset - item.iCharPos;
+
+ int curX = 0;
+ hr = ScriptCPtoX(charLength, FALSE, itemLength,
+ shaping.glyphLength(),
+ &shaping.m_logs[0], &shaping.m_visualAttributes[0],
+ shaping.effectiveAdvances(), &item.a, &curX);
+ if (FAILED(hr))
+ return 0;
+
+ width += curX + shaping.m_prePadding;
+ ASSERT(width >= 0);
+ return width;
+ }
+
+ // Move to the next item.
+ width += advanceForItem(itemIndex);
+ }
+ ASSERT(width >= 0);
+ return width;
+}
+
+int UniscribeHelper::xToCharacter(int x) const
+{
+ // We iterate in screen order until we find the item with the given pixel
+ // position in it. When we find that guy, we ask Uniscribe for the
+ // character index.
+ HRESULT hr;
+ for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
+ int itemIndex = m_screenOrder[screenIndex];
+ int itemAdvance = advanceForItem(itemIndex);
+
+ // Note that the run may be empty if shaping failed, so we want to skip
+ // over it.
+ const Shaping& shaping = m_shapes[itemIndex];
+ int itemLength = shaping.charLength();
+ if (x <= itemAdvance && itemLength > 0) {
+ // The requested offset is within this item.
+ const SCRIPT_ITEM& item = m_runs[itemIndex];
+
+ // Account for the leading space we've added to this run that
+ // Uniscribe doesn't know about.
+ x -= shaping.m_prePadding;
+
+ int charX = 0;
+ int trailing;
+ hr = ScriptXtoCP(x, itemLength, shaping.glyphLength(),
+ &shaping.m_logs[0], &shaping.m_visualAttributes[0],
+ shaping.effectiveAdvances(), &item.a, &charX,
+ &trailing);
+
+ // The character offset is within the item. We need to add the
+ // item's offset to transform it into the space of the TextRun
+ return charX + item.iCharPos;
+ }
+
+ // The offset is beyond this item, account for its length and move on.
+ x -= itemAdvance;
+ }
+
+ // Error condition, we don't know what to do if we don't have that X
+ // position in any of our items.
+ return 0;
+}
+
+void UniscribeHelper::draw(GraphicsContext* graphicsContext,
+ HDC dc, int x, int y, int from, int to)
+{
+ HGDIOBJ oldFont = 0;
+ int curX = x;
+ bool firstRun = true;
+ bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext);
+
+ for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
+ int itemIndex = m_screenOrder[screenIndex];
+ const SCRIPT_ITEM& item = m_runs[itemIndex];
+ const Shaping& shaping = m_shapes[itemIndex];
+
+ // Character offsets within this run. THESE MAY NOT BE IN RANGE and may
+ // be negative, etc. The code below handles this.
+ int fromChar = from - item.iCharPos;
+ int toChar = to - item.iCharPos;
+
+ // See if we need to draw any characters in this item.
+ if (shaping.charLength() == 0 ||
+ fromChar >= shaping.charLength() || toChar <= 0) {
+ // No chars in this item to display.
+ curX += advanceForItem(itemIndex);
+ continue;
+ }
+
+ // Compute the starting glyph within this span. |from| and |to| are
+ // global offsets that may intersect arbitrarily with our local run.
+ int fromGlyph, afterGlyph;
+ if (item.a.fRTL) {
+ // To compute the first glyph when going RTL, we use |to|.
+ if (toChar >= shaping.charLength())
+ // The end of the text is after (to the left) of us.
+ fromGlyph = 0;
+ else {
+ // Since |to| is exclusive, the first character we draw on the
+ // left is actually the one right before (to the right) of
+ // |to|.
+ fromGlyph = shaping.m_logs[toChar - 1];
+ }
+
+ // The last glyph is actually the first character in the range.
+ if (fromChar <= 0) {
+ // The first character to draw is before (to the right) of this
+ // span, so draw all the way to the end.
+ afterGlyph = shaping.glyphLength();
+ } else {
+ // We want to draw everything up until the character to the
+ // right of |from|. To the right is - 1, so we look that up
+ // (remember our character could be more than one glyph, so we
+ // can't look up our glyph and add one).
+ afterGlyph = shaping.m_logs[fromChar - 1];
+ }
+ } else {
+ // Easy case, everybody agrees about directions. We only need to
+ // handle boundary conditions to get a range inclusive at the
+ // beginning, and exclusive at the ending. We have to do some
+ // computation to see the glyph one past the end.
+ fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar];
+ if (toChar >= shaping.charLength())
+ afterGlyph = shaping.glyphLength();
+ else
+ afterGlyph = shaping.m_logs[toChar];
+ }
+
+ // Account for the characters that were skipped in this run. When
+ // WebKit asks us to draw a subset of the run, it actually tells us
+ // to draw at the X offset of the beginning of the run, since it
+ // doesn't know the internal position of any of our characters.
+ const int* effectiveAdvances = shaping.effectiveAdvances();
+ int innerOffset = 0;
+ for (int i = 0; i < fromGlyph; i++)
+ innerOffset += effectiveAdvances[i];
+
+ // Actually draw the glyphs we found.
+ int glyphCount = afterGlyph - fromGlyph;
+ if (fromGlyph >= 0 && glyphCount > 0) {
+ // Account for the preceding space we need to add to this run. We
+ // don't need to count for the following space because that will be
+ // counted in advanceForItem below when we move to the next run.
+ innerOffset += shaping.m_prePadding;
+
+ // Pass 0 in when there is no justification.
+ const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph];
+
+ if (useWindowsDrawing) {
+ if (firstRun) {
+ oldFont = SelectObject(dc, shaping.m_hfont);
+ firstRun = false;
+ } else
+ SelectObject(dc, shaping.m_hfont);
+ }
+
+ // Fonts with different ascents can be used to render different
+ // runs. 'Across-runs' y-coordinate correction needs to be
+ // adjusted for each font.
+ bool textOutOk = false;
+ for (int executions = 0; executions < 2; ++executions) {
+ if (useWindowsDrawing) {
+ HRESULT hr = ScriptTextOut(dc, shaping.m_scriptCache,
+ curX + innerOffset,
+ y - shaping.m_ascentOffset,
+ 0, 0, &item.a, 0, 0,
+ &shaping.m_glyphs[fromGlyph],
+ glyphCount,
+ &shaping.m_advance[fromGlyph],
+ justify,
+ &shaping.m_offsets[fromGlyph]);
+ textOutOk = (hr == S_OK);
+ } else {
+ SkPoint origin;
+ origin.fX = curX + + innerOffset;
+ origin.fY = y + m_ascent;
+ textOutOk = paintSkiaText(graphicsContext,
+ shaping.m_hfont,
+ glyphCount,
+ &shaping.m_glyphs[fromGlyph],
+ &shaping.m_advance[fromGlyph],
+ &shaping.m_offsets[fromGlyph],
+ &origin);
+ }
+
+ if (!textOutOk && 0 == executions) {
+ // If TextOut is called from the renderer it might fail
+ // because the sandbox is preventing it from opening the
+ // font files. If we are running in the renderer,
+ // TryToPreloadFont is overridden to ask the browser to
+ // preload the font for us so we can access it.
+ tryToPreloadFont(shaping.m_hfont);
+ continue;
+ }
+ break;
+ }
+ }
+
+ curX += advanceForItem(itemIndex);
+ }
+
+ if (oldFont)
+ SelectObject(dc, oldFont);
+}
+
+WORD UniscribeHelper::firstGlyphForCharacter(int charOffset) const
+{
+ // Find the run for the given character.
+ for (int i = 0; i < static_cast<int>(m_runs.size()); i++) {
+ int firstChar = m_runs[i].iCharPos;
+ const Shaping& shaping = m_shapes[i];
+ int localOffset = charOffset - firstChar;
+ if (localOffset >= 0 && localOffset < shaping.charLength()) {
+ // The character is in this run, return the first glyph for it
+ // (should generally be the only glyph). It seems Uniscribe gives
+ // glyph 0 for empty, which is what we want to return in the
+ // "missing" case.
+ size_t glyphIndex = shaping.m_logs[localOffset];
+ if (glyphIndex >= shaping.m_glyphs.size()) {
+ // The glyph should be in this run, but the run has too few
+ // actual characters. This can happen when shaping the run
+ // fails, in which case, we should have no data in the logs at
+ // all.
+ ASSERT(shaping.m_glyphs.size() == 0);
+ return 0;
+ }
+ return shaping.m_glyphs[glyphIndex];
+ }
+ }
+
+ return 0;
+}
+
+void UniscribeHelper::fillRuns()
+{
+ HRESULT hr;
+ m_runs.resize(UNISCRIBE_HELPER_STACK_RUNS);
+
+ SCRIPT_STATE inputState;
+ inputState.uBidiLevel = m_isRtl;
+ inputState.fOverrideDirection = m_directionalOverride;
+ inputState.fInhibitSymSwap = false;
+ inputState.fCharShape = false; // Not implemented in Uniscribe
+ inputState.fDigitSubstitute = false; // Do we want this for Arabic?
+ inputState.fInhibitLigate = m_inhibitLigate;
+ inputState.fDisplayZWG = false; // Don't draw control characters.
+ inputState.fArabicNumContext = m_isRtl; // Do we want this for Arabic?
+ inputState.fGcpClusters = false;
+ inputState.fReserved = 0;
+ inputState.fEngineReserved = 0;
+ // The psControl argument to ScriptItemize should be non-0 for RTL text,
+ // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a
+ // SCRIPT_CONTROL that is set to all zeros. Zero as a locale ID means the
+ // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx
+ static SCRIPT_CONTROL inputControl = {0, // uDefaultLanguage :16;
+ 0, // fContextDigits :1;
+ 0, // fInvertPreBoundDir :1;
+ 0, // fInvertPostBoundDir :1;
+ 0, // fLinkStringBefore :1;
+ 0, // fLinkStringAfter :1;
+ 0, // fNeutralOverride :1;
+ 0, // fNumericOverride :1;
+ 0, // fLegacyBidiClass :1;
+ 0, // fMergeNeutralItems :1;
+ 0};// fReserved :7;
+ // Calling ScriptApplyDigitSubstitution( 0, &inputControl, &inputState)
+ // here would be appropriate if we wanted to set the language ID, and get
+ // local digit substitution behavior. For now, don't do it.
+
+ while (true) {
+ int numberOfItems = 0;
+
+ // Ideally, we would have a way to know the runs before and after this
+ // one, and put them into the control parameter of ScriptItemize. This
+ // would allow us to shape characters properly that cross style
+ // boundaries (WebKit bug 6148).
+ //
+ // We tell ScriptItemize that the output list of items is one smaller
+ // than it actually is. According to Mozilla bug 366643, if there is
+ // not enough room in the array on pre-SP2 systems, ScriptItemize will
+ // write one past the end of the buffer.
+ //
+ // ScriptItemize is very strange. It will often require a much larger
+ // ITEM buffer internally than it will give us as output. For example,
+ // it will say a 16-item buffer is not big enough, and will write
+ // interesting numbers into all those items. But when we give it a 32
+ // item buffer and it succeeds, it only has one item output.
+ //
+ // It seems to be doing at least two passes, the first where it puts a
+ // lot of intermediate data into our items, and the second where it
+ // collates them.
+ hr = ScriptItemize(m_input, m_inputLength,
+ static_cast<int>(m_runs.size()) - 1, &inputControl,
+ &inputState,
+ &m_runs[0], &numberOfItems);
+ if (SUCCEEDED(hr)) {
+ m_runs.resize(numberOfItems);
+ break;
+ }
+ if (hr != E_OUTOFMEMORY) {
+ // Some kind of unexpected error.
+ m_runs.resize(0);
+ break;
+ }
+ // There was not enough items for it to write into, expand.
+ m_runs.resize(m_runs.size() * 2);
+ }
+}
+
+bool UniscribeHelper::shape(const UChar* input,
+ int itemLength,
+ int numGlyphs,
+ SCRIPT_ITEM& run,
+ Shaping& shaping)
+{
+ HFONT hfont = m_hfont;
+ SCRIPT_CACHE* scriptCache = m_scriptCache;
+ SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties;
+ int ascent = m_ascent;
+ HDC tempDC = 0;
+ HGDIOBJ oldFont = 0;
+ HRESULT hr;
+ // When used to fill up glyph pages for simple scripts in non-BMP,
+ // we don't want any font fallback in this class. The simple script
+ // font path can take care of font fallback.
+ bool lastFallbackTried = m_disableFontFallback;
+ bool result;
+
+ int generatedGlyphs = 0;
+
+ // In case HFONT passed in ctor cannot render this run, we have to scan
+ // other fonts from the beginning of the font list.
+ resetFontIndex();
+
+ // Compute shapes.
+ while (true) {
+ shaping.m_logs.resize(itemLength);
+ shaping.m_glyphs.resize(numGlyphs);
+ shaping.m_visualAttributes.resize(numGlyphs);
+
+#ifdef PURIFY
+ // http://code.google.com/p/chromium/issues/detail?id=5309
+ // Purify isn't able to track the assignments that ScriptShape makes to
+ // shaping.m_glyphs. Consequently, any bytes with value 0xCD that it
+ // writes, will be considered un-initialized data.
+ //
+ // This hack avoid the false-positive UMRs by marking the buffer as
+ // initialized.
+ //
+ // FIXME: A better solution would be to use Purify's API and mark only
+ // the populated range as initialized:
+ //
+ // PurifyMarkAsInitialized(
+ // &shaping.m_glyphs[0],
+ // sizeof(shaping.m_glyphs[0] * generatedGlyphs);
+
+ ZeroMemory(&shaping.m_glyphs[0],
+ sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size());
+#endif
+
+ // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true
+ // here. Is that what we want? It will display control characters.
+ hr = ScriptShape(tempDC, scriptCache, input, itemLength,
+ numGlyphs, &run.a,
+ &shaping.m_glyphs[0], &shaping.m_logs[0],
+ &shaping.m_visualAttributes[0], &generatedGlyphs);
+ if (hr == E_PENDING) {
+ // Allocate the DC.
+ tempDC = GetDC(0);
+ oldFont = SelectObject(tempDC, hfont);
+ continue;
+ } else if (hr == E_OUTOFMEMORY) {
+ numGlyphs *= 2;
+ continue;
+ } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(&shaping.m_glyphs[0], generatedGlyphs, fontProperties)))
+ break;
+
+ // The current font can't render this run. clear DC and try
+ // next font.
+ if (tempDC) {
+ SelectObject(tempDC, oldFont);
+ ReleaseDC(0, tempDC);
+ tempDC = 0;
+ }
+
+ if (!m_disableFontFallback &&
+ nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) {
+ // The primary font does not support this run. Try next font.
+ // In case of web page rendering, they come from fonts specified in
+ // CSS stylesheets.
+ continue;
+ } else if (!lastFallbackTried) {
+ lastFallbackTried = true;
+
+ // Generate a last fallback font based on the script of
+ // a character to draw while inheriting size and styles
+ // from the primary font
+ if (!m_logfont.lfFaceName[0])
+ setLogFontAndStyle(m_hfont, &m_logfont, &m_style);
+
+ // TODO(jungshik): generic type should come from webkit for
+ // UniscribeHelperTextRun (a derived class used in webkit).
+ const UChar *family = getFallbackFamily(input, itemLength,
+ FontDescription::StandardFamily, 0, 0);
+ bool fontOk = getDerivedFontData(family, m_style, &m_logfont,
+ &ascent, &hfont, &scriptCache);
+
+ if (!fontOk) {
+ // If this GetDerivedFontData is called from the renderer it
+ // might fail because the sandbox is preventing it from opening
+ // the font files. If we are running in the renderer,
+ // TryToPreloadFont is overridden to ask the browser to preload
+ // the font for us so we can access it.
+ tryToPreloadFont(hfont);
+
+ // Try again.
+ fontOk = getDerivedFontData(family, m_style, &m_logfont,
+ &ascent, &hfont, &scriptCache);
+ ASSERT(fontOk);
+ }
+
+ // TODO(jungshik) : Currently GetDerivedHFont always returns a
+ // a valid HFONT, but in the future, I may change it to return 0.
+ ASSERT(hfont);
+
+ // We don't need a font_properties for the last resort fallback font
+ // because we don't have anything more to try and are forced to
+ // accept empty glyph boxes. If we tried a series of fonts as
+ // 'last-resort fallback', we'd need it, but currently, we don't.
+ continue;
+ } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
+ run.a.eScript = SCRIPT_UNDEFINED;
+ continue;
+ } else if (FAILED(hr)) {
+ // Error shaping.
+ generatedGlyphs = 0;
+ result = false;
+ goto cleanup;
+ }
+ }
+
+ // Sets Windows font data for this run to those corresponding to
+ // a font supporting this run. we don't need to store font_properties
+ // because it's not used elsewhere.
+ shaping.m_hfont = hfont;
+ shaping.m_scriptCache = scriptCache;
+
+ // The ascent of a font for this run can be different from
+ // that of the primary font so that we need to keep track of
+ // the difference per run and take that into account when calling
+ // ScriptTextOut in |draw|. Otherwise, different runs rendered by
+ // different fonts would not be aligned vertically.
+ shaping.m_ascentOffset = m_ascent ? ascent - m_ascent : 0;
+ result = true;
+
+ cleanup:
+ shaping.m_glyphs.resize(generatedGlyphs);
+ shaping.m_visualAttributes.resize(generatedGlyphs);
+ shaping.m_advance.resize(generatedGlyphs);
+ shaping.m_offsets.resize(generatedGlyphs);
+ if (tempDC) {
+ SelectObject(tempDC, oldFont);
+ ReleaseDC(0, tempDC);
+ }
+ // On failure, our logs don't mean anything, so zero those out.
+ if (!result)
+ shaping.m_logs.clear();
+
+ return result;
+}
+
+void UniscribeHelper::fillShapes()
+{
+ m_shapes.resize(m_runs.size());
+ for (size_t i = 0; i < m_runs.size(); i++) {
+ int startItem = m_runs[i].iCharPos;
+ int itemLength = m_inputLength - startItem;
+ if (i < m_runs.size() - 1)
+ itemLength = m_runs[i + 1].iCharPos - startItem;
+
+ int numGlyphs;
+ if (itemLength < UNISCRIBE_HELPER_STACK_CHARS) {
+ // We'll start our buffer sizes with the current stack space
+ // available in our buffers if the current input fits. As long as
+ // it doesn't expand past that we'll save a lot of time mallocing.
+ numGlyphs = UNISCRIBE_HELPER_STACK_CHARS;
+ } else {
+ // When the input doesn't fit, give up with the stack since it will
+ // almost surely not be enough room (unless the input actually
+ // shrinks, which is unlikely) and just start with the length
+ // recommended by the Uniscribe documentation as a "usually fits"
+ // size.
+ numGlyphs = itemLength * 3 / 2 + 16;
+ }
+
+ // Convert a string to a glyph string trying the primary font, fonts in
+ // the fallback list and then script-specific last resort font.
+ Shaping& shaping = m_shapes[i];
+ if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping))
+ continue;
+
+ // At the moment, the only time m_disableFontFallback is set is
+ // when we look up glyph indices for non-BMP code ranges. So,
+ // we can skip the glyph placement. When that becomes not the case
+ // any more, we have to add a new flag to control glyph placement.
+ if (m_disableFontFallback)
+ continue;
+
+ // Compute placements. Note that offsets is documented incorrectly
+ // and is actually an array.
+
+ // DC that we lazily create if Uniscribe commands us to.
+ // (this does not happen often because scriptCache is already
+ // updated when calling ScriptShape).
+ HDC tempDC = 0;
+ HGDIOBJ oldFont = 0;
+ HRESULT hr;
+ while (true) {
+ shaping.m_prePadding = 0;
+ hr = ScriptPlace(tempDC, shaping.m_scriptCache,
+ &shaping.m_glyphs[0],
+ static_cast<int>(shaping.m_glyphs.size()),
+ &shaping.m_visualAttributes[0], &m_runs[i].a,
+ &shaping.m_advance[0], &shaping.m_offsets[0],
+ &shaping.m_abc);
+ if (hr != E_PENDING)
+ break;
+
+ // Allocate the DC and run the loop again.
+ tempDC = GetDC(0);
+ oldFont = SelectObject(tempDC, shaping.m_hfont);
+ }
+
+ if (FAILED(hr)) {
+ // Some error we don't know how to handle. Nuke all of our data
+ // since we can't deal with partially valid data later.
+ m_runs.clear();
+ m_shapes.clear();
+ m_screenOrder.clear();
+ }
+
+ if (tempDC) {
+ SelectObject(tempDC, oldFont);
+ ReleaseDC(0, tempDC);
+ }
+ }
+
+ adjustSpaceAdvances();
+
+ if (m_letterSpacing != 0 || m_wordSpacing != 0)
+ applySpacing();
+}
+
+void UniscribeHelper::fillScreenOrder()
+{
+ m_screenOrder.resize(m_runs.size());
+
+ // We assume that the input has only one text direction in it.
+ // TODO(brettw) are we sure we want to keep this restriction?
+ if (m_isRtl) {
+ for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
+ m_screenOrder[static_cast<int>(m_screenOrder.size()) - i - 1] = i;
+ } else {
+ for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
+ m_screenOrder[i] = i;
+ }
+}
+
+void UniscribeHelper::adjustSpaceAdvances()
+{
+ if (m_spaceWidth == 0)
+ return;
+
+ int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing;
+
+ // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem.
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ Shaping& shaping = m_shapes[run];
+
+ for (int i = 0; i < shaping.charLength(); i++) {
+ if (!treatAsSpace(m_input[m_runs[run].iCharPos + i]))
+ continue;
+
+ int glyphIndex = shaping.m_logs[i];
+ int currentAdvance = shaping.m_advance[glyphIndex];
+
+ // currentAdvance does not include additional letter-spacing, but
+ // space_width does. Here we find out how off we are from the
+ // correct width for the space not including letter-spacing, then
+ // just subtract that diff.
+ int diff = currentAdvance - spaceWidthWithoutLetterSpacing;
+ // The shaping can consist of a run of text, so only subtract the
+ // difference in the width of the glyph.
+ shaping.m_advance[glyphIndex] -= diff;
+ shaping.m_abc.abcB -= diff;
+ }
+ }
+}
+
+void UniscribeHelper::applySpacing()
+{
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ Shaping& shaping = m_shapes[run];
+ bool isRtl = m_runs[run].a.fRTL;
+
+ if (m_letterSpacing != 0) {
+ // RTL text gets padded to the left of each character. We increment
+ // the run's advance to make this happen. This will be balanced out
+ // by NOT adding additional advance to the last glyph in the run.
+ if (isRtl)
+ shaping.m_prePadding += m_letterSpacing;
+
+ // Go through all the glyphs in this run and increase the "advance"
+ // to account for letter spacing. We adjust letter spacing only on
+ // cluster boundaries.
+ //
+ // This works for most scripts, but may have problems with some
+ // indic scripts. This behavior is better than Firefox or IE for
+ // Hebrew.
+ for (int i = 0; i < shaping.glyphLength(); i++) {
+ if (shaping.m_visualAttributes[i].fClusterStart) {
+ // Ick, we need to assign the extra space so that the glyph
+ // comes first, then is followed by the space. This is
+ // opposite for RTL.
+ if (isRtl) {
+ if (i != shaping.glyphLength() - 1) {
+ // All but the last character just get the spacing
+ // applied to their advance. The last character
+ // doesn't get anything,
+ shaping.m_advance[i] += m_letterSpacing;
+ shaping.m_abc.abcB += m_letterSpacing;
+ }
+ } else {
+ // LTR case is easier, we just add to the advance.
+ shaping.m_advance[i] += m_letterSpacing;
+ shaping.m_abc.abcB += m_letterSpacing;
+ }
+ }
+ }
+ }
+
+ // Go through all the characters to find whitespace and insert the
+ // extra wordspacing amount for the glyphs they correspond to.
+ if (m_wordSpacing != 0) {
+ for (int i = 0; i < shaping.charLength(); i++) {
+ if (!treatAsSpace(m_input[m_runs[run].iCharPos + i]))
+ continue;
+
+ // The char in question is a word separator...
+ int glyphIndex = shaping.m_logs[i];
+
+ // Spaces will not have a glyph in Uniscribe, it will just add
+ // additional advance to the character to the left of the
+ // space. The space's corresponding glyph will be the character
+ // following it in reading order.
+ if (isRtl) {
+ // In RTL, the glyph to the left of the space is the same
+ // as the first glyph of the following character, so we can
+ // just increment it.
+ shaping.m_advance[glyphIndex] += m_wordSpacing;
+ shaping.m_abc.abcB += m_wordSpacing;
+ } else {
+ // LTR is actually more complex here, we apply it to the
+ // previous character if there is one, otherwise we have to
+ // apply it to the leading space of the run.
+ if (glyphIndex == 0)
+ shaping.m_prePadding += m_wordSpacing;
+ else {
+ shaping.m_advance[glyphIndex - 1] += m_wordSpacing;
+ shaping.m_abc.abcB += m_wordSpacing;
+ }
+ }
+ }
+ } // m_wordSpacing != 0
+
+ // Loop for next run...
+ }
+}
+
+// The advance is the ABC width of the run
+int UniscribeHelper::advanceForItem(int itemIndex) const
+{
+ int accum = 0;
+ const Shaping& shaping = m_shapes[itemIndex];
+
+ if (shaping.m_justify.size() == 0) {
+ // Easy case with no justification, the width is just the ABC width of
+ // the run. (The ABC width is the sum of the advances).
+ return shaping.m_abc.abcA + shaping.m_abc.abcB +
+ shaping.m_abc.abcC + shaping.m_prePadding;
+ }
+
+ // With justification, we use the justified amounts instead. The
+ // justification array contains both the advance and the extra space
+ // added for justification, so is the width we want.
+ int justification = 0;
+ for (size_t i = 0; i < shaping.m_justify.size(); i++)
+ justification += shaping.m_justify[i];
+
+ return shaping.m_prePadding + justification;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h
new file mode 100644
index 0000000..ffd57db
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 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.
+ */
+
+// A wrapper around Uniscribe that provides a reasonable API.
+
+#ifndef UniscribeHelper_h
+#define UniscribeHelper_h
+
+#include <windows.h>
+#include <usp10.h>
+#include <map>
+
+#include <unicode/uchar.h>
+#include <wtf/Vector.h>
+
+class UniscribeTest_TooBig_Test; // A gunit test for UniscribeHelper.
+
+namespace WebCore {
+
+class GraphicsContext;
+
+#define UNISCRIBE_HELPER_STACK_RUNS 8
+#define UNISCRIBE_HELPER_STACK_CHARS 32
+
+// This object should be safe to create & destroy frequently, as long as the
+// caller preserves the script_cache when possible (this data may be slow to
+// compute).
+//
+// This object is "kind of large" (~1K) because it reserves a lot of space for
+// working with to avoid expensive heap operations. Therefore, not only should
+// you not worry about creating and destroying it, you should try to not keep
+// them around.
+class UniscribeHelper {
+public:
+ // Initializes this Uniscribe run with the text pointed to by |run| with
+ // |length|. The input is NOT null terminated.
+ //
+ // The is_rtl flag should be set if the input script is RTL. It is assumed
+ // that the caller has already divided up the input text (using ICU, for
+ // example) into runs of the same direction of script. This avoids
+ // disagreements between the caller and Uniscribe later (see FillItems).
+ //
+ // A script cache should be provided by the caller that is initialized to
+ // NULL. When the caller is done with the cache (it may be stored between
+ // runs as long as it is used consistently with the same HFONT), it should
+ // call ScriptFreeCache().
+ UniscribeHelper(const UChar* input,
+ int inputLength,
+ bool isRtl,
+ HFONT,
+ SCRIPT_CACHE*,
+ SCRIPT_FONTPROPERTIES*);
+
+ virtual ~UniscribeHelper();
+
+ // Sets Uniscribe's directional override flag. False by default.
+ bool directionalOverride() const
+ {
+ return m_directionalOverride;
+ }
+ void setDirectionalOverride(bool override)
+ {
+ m_directionalOverride = override;
+ }
+
+ // Set's Uniscribe's no-ligate override flag. False by default.
+ bool inhibitLigate() const
+ {
+ return m_inhibitLigate;
+ }
+ void setInhibitLigate(bool inhibit)
+ {
+ m_inhibitLigate = inhibit;
+ }
+
+ // Set letter spacing. We will try to insert this much space between
+ // graphemes (one or more glyphs perceived as a single unit by ordinary
+ // users of a script). Positive values increase letter spacing, negative
+ // values decrease it. 0 by default.
+ int letterSpacing() const
+ {
+ return m_letterSpacing;
+ }
+ void setLetterSpacing(int letterSpacing)
+ {
+ m_letterSpacing = letterSpacing;
+ }
+
+ // Set the width of a standard space character. We use this to normalize
+ // space widths. Windows will make spaces after Hindi characters larger than
+ // other spaces. A space_width of 0 means to use the default space width.
+ //
+ // Must be set before Init() is called.
+ int spaceWidth() const
+ {
+ return m_spaceWidth;
+ }
+ void setSpaceWidth(int spaceWidth)
+ {
+ m_spaceWidth = spaceWidth;
+ }
+
+ // Set word spacing. We will try to insert this much extra space between
+ // each word in the input (beyond whatever whitespace character separates
+ // words). Positive values lead to increased letter spacing, negative values
+ // decrease it. 0 by default.
+ //
+ // Must be set before Init() is called.
+ int wordSpacing() const
+ {
+ return m_wordSpacing;
+ }
+ void setWordSpacing(int wordSpacing)
+ {
+ m_wordSpacing = wordSpacing;
+ }
+
+ void setAscent(int ascent)
+ {
+ m_ascent = ascent;
+ }
+
+ // When set to true, this class is used only to look up glyph
+ // indices for a range of Unicode characters without glyph placement.
+ // By default, it's false. This should be set to true when this
+ // class is used for glyph index look-up for non-BMP characters
+ // in GlyphPageNodeChromiumWin.cpp.
+ void setDisableFontFallback(bool disableFontFallback)
+ {
+ m_disableFontFallback = true;
+ }
+
+ // You must call this after setting any options but before doing any
+ // other calls like asking for widths or drawing.
+ void init()
+ {
+ initWithOptionalLengthProtection(true);
+ }
+
+ // Returns the total width in pixels of the text run.
+ int width() const;
+
+ // Call to justify the text, with the amount of space that should be ADDED
+ // to get the desired width that the column should be justified to.
+ // Normally, spaces are inserted, but for Arabic there will be kashidas
+ // (extra strokes) inserted instead.
+ //
+ // This function MUST be called AFTER Init().
+ void justify(int additionalSpace);
+
+ // Computes the given character offset into a pixel offset of the beginning
+ // of that character.
+ int characterToX(int offset) const;
+
+ // Converts the given pixel X position into a logical character offset into
+ // the run. For positions appearing before the first character, this will
+ // return -1.
+ int xToCharacter(int x) const;
+
+ // Draws the given characters to (x, y) in the given DC. The font will be
+ // handled by this function, but the font color and other attributes should
+ // be pre-set.
+ //
+ // The y position is the upper left corner, NOT the baseline.
+ void draw(GraphicsContext* graphicsContext, HDC dc, int x, int y, int from,
+ int to);
+
+ // Returns the first glyph assigned to the character at the given offset.
+ // This function is used to retrieve glyph information when Uniscribe is
+ // being used to generate glyphs for non-complex, non-BMP (above U+FFFF)
+ // characters. These characters are not otherwise special and have no
+ // complex shaping rules, so we don't otherwise need Uniscribe, except
+ // Uniscribe is the only way to get glyphs for non-BMP characters.
+ //
+ // Returns 0 if there is no glyph for the given character.
+ WORD firstGlyphForCharacter(int charOffset) const;
+
+protected:
+ // Backend for init. The flag allows the unit test to specify whether we
+ // should fail early for very long strings like normal, or try to pass the
+ // long string to Uniscribe. The latter provides a way to force failure of
+ // shaping.
+ void initWithOptionalLengthProtection(bool lengthProtection);
+
+ // Tries to preload the font when the it is not accessible.
+ // This is the default implementation and it does not do anything.
+ virtual void tryToPreloadFont(HFONT) {}
+
+private:
+ friend class UniscribeTest_TooBig_Test;
+
+ // An array corresponding to each item in runs_ containing information
+ // on each of the glyphs that were generated. Like runs_, this is in
+ // reading order. However, for rtl text, the characters within each
+ // item will be reversed.
+ struct Shaping {
+ Shaping()
+ : m_prePadding(0)
+ , m_hfont(NULL)
+ , m_scriptCache(NULL)
+ , m_ascentOffset(0) {
+ m_abc.abcA = 0;
+ m_abc.abcB = 0;
+ m_abc.abcC = 0;
+ }
+
+ // Returns the number of glyphs (which will be drawn to the screen)
+ // in this run.
+ int glyphLength() const
+ {
+ return static_cast<int>(m_glyphs.size());
+ }
+
+ // Returns the number of characters (that we started with) in this run.
+ int charLength() const
+ {
+ return static_cast<int>(m_logs.size());
+ }
+
+ // Returns the advance array that should be used when measuring glyphs.
+ // The returned pointer will indicate an array with glyph_length()
+ // elements and the advance that should be used for each one. This is
+ // either the real advance, or the justified advances if there is one,
+ // and is the array we want to use for measurement.
+ const int* effectiveAdvances() const
+ {
+ if (m_advance.size() == 0)
+ return 0;
+ if (m_justify.size() == 0)
+ return &m_advance[0];
+ return &m_justify[0];
+ }
+
+ // This is the advance amount of space that we have added to the
+ // beginning of the run. It is like the ABC's |A| advance but one that
+ // we create and must handle internally whenever computing with pixel
+ // offsets.
+ int m_prePadding;
+
+ // Glyph indices in the font used to display this item. These indices
+ // are in screen order.
+ Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_glyphs;
+
+ // For each input character, this tells us the first glyph index it
+ // generated. This is the only array with size of the input chars.
+ //
+ // All offsets are from the beginning of this run. Multiple characters
+ // can generate one glyph, in which case there will be adjacent
+ // duplicates in this list. One character can also generate multiple
+ // glyphs, in which case there will be skipped indices in this list.
+ Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_logs;
+
+ // Flags and such for each glyph.
+ Vector<SCRIPT_VISATTR, UNISCRIBE_HELPER_STACK_CHARS> m_visualAttributes;
+
+ // Horizontal advances for each glyph listed above, this is basically
+ // how wide each glyph is.
+ Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_advance;
+
+ // This contains glyph offsets, from the nominal position of a glyph.
+ // It is used to adjust the positions of multiple combining characters
+ // around/above/below base characters in a context-sensitive manner so
+ // that they don't bump against each other and the base character.
+ Vector<GOFFSET, UNISCRIBE_HELPER_STACK_CHARS> m_offsets;
+
+ // Filled by a call to Justify, this is empty for nonjustified text.
+ // If nonempty, this contains the array of justify characters for each
+ // character as returned by ScriptJustify.
+ //
+ // This is the same as the advance array, but with extra space added
+ // for some characters. The difference between a glyph's |justify|
+ // width and it's |advance| width is the extra space added.
+ Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_justify;
+
+ // Sizing information for this run. This treats the entire run as a
+ // character with a preceeding advance, width, and ending advance. The
+ // B width is the sum of the |advance| array, and the A and C widths
+ // are any extra spacing applied to each end.
+ //
+ // It is unclear from the documentation what this actually means. From
+ // experimentation, it seems that the sum of the character advances is
+ // always the sum of the ABC values, and I'm not sure what you're
+ // supposed to do with the ABC values.
+ ABC m_abc;
+
+ // Pointers to windows font data used to render this run.
+ HFONT m_hfont;
+ SCRIPT_CACHE* m_scriptCache;
+
+ // Ascent offset between the ascent of the primary font
+ // and that of the fallback font. The offset needs to be applied,
+ // when drawing a string, to align multiple runs rendered with
+ // different fonts.
+ int m_ascentOffset;
+ };
+
+ // Computes the runs_ array from the text run.
+ void fillRuns();
+
+ // Computes the shapes_ array given an runs_ array already filled in.
+ void fillShapes();
+
+ // Fills in the screen_order_ array (see below).
+ void fillScreenOrder();
+
+ // Called to update the glyph positions based on the current spacing
+ // options that are set.
+ void applySpacing();
+
+ // Normalizes all advances for spaces to the same width. This keeps windows
+ // from making spaces after Hindi characters larger, which is then
+ // inconsistent with our meaure of the width since WebKit doesn't include
+ // spaces in text-runs sent to uniscribe unless white-space:pre.
+ void adjustSpaceAdvances();
+
+ // Returns the total width of a single item.
+ int advanceForItem(int) const;
+
+ // Shapes a run (pointed to by |input|) using |hfont| first.
+ // Tries a series of fonts specified retrieved with NextWinFontData
+ // and finally a font covering characters in |*input|. A string pointed
+ // by |input| comes from ScriptItemize and is supposed to contain
+ // characters belonging to a single script aside from characters common to
+ // all scripts (e.g. space).
+ bool shape(const UChar* input, int itemLength, int numGlyphs, SCRIPT_ITEM& run, Shaping&);
+
+ // Gets Windows font data for the next best font to try in the list
+ // of fonts. When there's no more font available, returns false
+ // without touching any of out params. Need to call ResetFontIndex
+ // to start scanning of the font list from the beginning.
+ virtual bool nextWinFontData(HFONT*, SCRIPT_CACHE**, SCRIPT_FONTPROPERTIES**, int* ascent)
+ {
+ return false;
+ }
+
+ // Resets the font index to the first in the list of fonts to try after the
+ // primaryFont turns out not to work. With fontIndex reset,
+ // NextWinFontData scans fallback fonts from the beginning.
+ virtual void resetFontIndex() {}
+
+ // The input data for this run of Uniscribe. See the constructor.
+ const UChar* m_input;
+ const int m_inputLength;
+ const bool m_isRtl;
+
+ // Windows font data for the primary font. In a sense, m_logfont and m_style
+ // are redundant because m_hfont contains all the information. However,
+ // invoking GetObject, everytime we need the height and the style, is rather
+ // expensive so that we cache them. Would it be better to add getter and
+ // (virtual) setter for the height and the style of the primary font,
+ // instead of m_logfont? Then, a derived class ctor can set m_ascent,
+ // m_height and m_style if they're known. Getters for them would have to
+ // 'infer' their values from m_hfont ONLY when they're not set.
+ HFONT m_hfont;
+ SCRIPT_CACHE* m_scriptCache;
+ SCRIPT_FONTPROPERTIES* m_fontProperties;
+ int m_ascent;
+ LOGFONT m_logfont;
+ int m_style;
+
+ // Options, see the getters/setters above.
+ bool m_directionalOverride;
+ bool m_inhibitLigate;
+ int m_letterSpacing;
+ int m_spaceWidth;
+ int m_wordSpacing;
+ bool m_disableFontFallback;
+
+ // Uniscribe breaks the text into Runs. These are one length of text that is
+ // in one script and one direction. This array is in reading order.
+ Vector<SCRIPT_ITEM, UNISCRIBE_HELPER_STACK_RUNS> m_runs;
+
+ Vector<Shaping, UNISCRIBE_HELPER_STACK_RUNS> m_shapes;
+
+ // This is a mapping between reading order and screen order for the items.
+ // Uniscribe's items array are in reading order. For right-to-left text,
+ // or mixed (although WebKit's |TextRun| should really be only one
+ // direction), this makes it very difficult to compute character offsets
+ // and positions. This list is in screen order from left to right, and
+ // gives the index into the |m_runs| and |m_shapes| arrays of each
+ // subsequent item.
+ Vector<int, UNISCRIBE_HELPER_STACK_RUNS> m_screenOrder;
+};
+
+} // namespace WebCore
+
+#endif // UniscribeHelper_h
diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp
new file mode 100644
index 0000000..f801c13
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 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.
+ */
+
+#include "config.h"
+#include "UniscribeHelperTextRun.h"
+
+#include "ChromiumBridge.h"
+#include "Font.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run,
+ const Font& font)
+ : UniscribeHelper(run.characters(), run.length(), run.rtl(),
+ font.primaryFont()->platformData().hfont(),
+ font.primaryFont()->platformData().scriptCache(),
+ font.primaryFont()->platformData().scriptFontProperties())
+ , m_font(&font)
+ , m_fontIndex(0)
+{
+ setDirectionalOverride(run.directionalOverride());
+ setLetterSpacing(font.letterSpacing());
+ setSpaceWidth(font.spaceWidth());
+ setWordSpacing(font.wordSpacing());
+ setAscent(font.primaryFont()->ascent());
+
+ init();
+
+ // Padding is the amount to add to make justification happen. This
+ // should be done after Init() so all the runs are already measured.
+ if (run.padding() > 0)
+ justify(run.padding());
+}
+
+UniscribeHelperTextRun::UniscribeHelperTextRun(
+ const wchar_t* input,
+ int inputLength,
+ bool isRtl,
+ HFONT hfont,
+ SCRIPT_CACHE* scriptCache,
+ SCRIPT_FONTPROPERTIES* fontProperties)
+ : UniscribeHelper(input, inputLength, isRtl, hfont,
+ scriptCache, fontProperties)
+ , m_font(0)
+ , m_fontIndex(-1)
+{
+}
+
+void UniscribeHelperTextRun::tryToPreloadFont(HFONT font)
+{
+ // Ask the browser to get the font metrics for this font.
+ // That will preload the font and it should now be accessible
+ // from the renderer.
+ ChromiumBridge::ensureFontLoaded(font);
+}
+
+bool UniscribeHelperTextRun::nextWinFontData(
+ HFONT* hfont,
+ SCRIPT_CACHE** scriptCache,
+ SCRIPT_FONTPROPERTIES** fontProperties,
+ int* ascent)
+{
+ // This check is necessary because NextWinFontData can be called again
+ // after we already ran out of fonts. fontDataAt behaves in a strange
+ // manner when the difference between param passed and # of fonts stored in
+ // WebKit::Font is larger than one. We can avoid this check by setting
+ // font_index_ to # of elements in hfonts_ when we run out of font. In that
+ // case, we'd have to go through a couple of more checks before returning
+ // false.
+ if (m_fontIndex == -1 || !m_font)
+ return false;
+
+ // If the font data for a fallback font requested is not yet retrieved, add
+ // them to our vectors. Note that '>' rather than '>=' is used to test that
+ // condition. primaryFont is not stored in hfonts_, and friends so that
+ // indices for fontDataAt and our vectors for font data are 1 off from each
+ // other. That is, when fully populated, hfonts_ and friends have one font
+ // fewer than what's contained in font_.
+ if (static_cast<size_t>(++m_fontIndex) > m_hfonts.size()) {
+ const FontData *fontData = m_font->fontDataAt(m_fontIndex);
+ if (!fontData) {
+ // Ran out of fonts.
+ m_fontIndex = -1;
+ return false;
+ }
+
+ // FIXME: this won't work for SegmentedFontData
+ // http://crbug.com/6425
+ const SimpleFontData* simpleFontData =
+ fontData->fontDataForCharacter(' ');
+
+ m_hfonts.append(simpleFontData->platformData().hfont());
+ m_scriptCaches.append(simpleFontData->platformData().scriptCache());
+ m_fontProperties.append(simpleFontData->platformData().scriptFontProperties());
+ m_ascents.append(simpleFontData->ascent());
+ }
+
+ *hfont = m_hfonts[m_fontIndex - 1];
+ *scriptCache = m_scriptCaches[m_fontIndex - 1];
+ *fontProperties = m_fontProperties[m_fontIndex - 1];
+ *ascent = m_ascents[m_fontIndex - 1];
+ return true;
+}
+
+void UniscribeHelperTextRun::resetFontIndex()
+{
+ m_fontIndex = 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h
new file mode 100644
index 0000000..b5c54a0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 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 UniscribeHelperTextRun_h
+#define UniscribeHelperTextRun_h
+
+#include "UniscribeHelper.h"
+
+namespace WebCore {
+
+class Font;
+class TextRun;
+
+// Wrapper around the Uniscribe helper that automatically sets it up with the
+// WebKit types we supply.
+class UniscribeHelperTextRun : public UniscribeHelper {
+public:
+ // Regular constructor used for WebCore text run processing.
+ UniscribeHelperTextRun(const TextRun&, const Font&);
+
+ // Constructor with the same interface as the gfx::UniscribeState. Using
+ // this constructor will not give you font fallback, but it will provide
+ // the ability to load fonts that may not be in the OS cache
+ // ("TryToPreloadFont") if the caller does not have a TextRun/Font.
+ UniscribeHelperTextRun(const wchar_t* input,
+ int inputLength,
+ bool isRtl,
+ HFONT hfont,
+ SCRIPT_CACHE*,
+ SCRIPT_FONTPROPERTIES*);
+
+protected:
+ virtual void tryToPreloadFont(HFONT);
+
+private:
+ // This function retrieves the Windows font data (HFONT, etc) for the next
+ // WebKit font in the list. If the font data corresponding to font_index_
+ // has been obtained before, returns the values stored in our internal
+ // vectors (hfonts_, etc). Otherwise, it gets next SimpleFontData from
+ // WebKit and adds them to in hfonts_ and friends so that font data can be
+ // returned quickly next time they're requested.
+ virtual bool nextWinFontData(HFONT*, SCRIPT_CACHE**, SCRIPT_FONTPROPERTIES**, int* ascent);
+ virtual void resetFontIndex();
+
+ // Reference to WebKit::Font that contains all the information about fonts
+ // we can use to render this input run of text. It is used in
+ // NextWinFontData to retrieve Windows font data for a series of
+ // non-primary fonts.
+ //
+ // This pointer can be NULL for no font fallback handling.
+ const Font* m_font;
+
+ // It's rare that many fonts are listed in stylesheets.
+ // Four would be large enough in most cases.
+ const static size_t kNumberOfFonts = 4;
+
+ // These vectors are used to store Windows font data for non-primary fonts.
+ Vector<HFONT, kNumberOfFonts> m_hfonts;
+ Vector<SCRIPT_CACHE*, kNumberOfFonts> m_scriptCaches;
+ Vector<SCRIPT_FONTPROPERTIES*, kNumberOfFonts> m_fontProperties;
+ Vector<int, kNumberOfFonts> m_ascents;
+
+ // Index of the fallback font we're currently using for NextWinFontData.
+ int m_fontIndex;
+};
+
+} // namespace WebCore
+
+#endif // UniscribeHelperTextRun_h
diff --git a/Source/WebCore/platform/graphics/chromium/VDMXParser.cpp b/Source/WebCore/platform/graphics/chromium/VDMXParser.cpp
new file mode 100644
index 0000000..bd30a97
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/VDMXParser.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2008, 2009, 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.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+// For htons/ntohs
+#include <arpa/inet.h>
+
+// Buffer helper class
+//
+// This class perform some trival buffer operations while checking for
+// out-of-bounds errors. As a family they return false if anything is amiss,
+// updating the current offset otherwise.
+class Buffer {
+public:
+ Buffer(const uint8_t* buffer, size_t length)
+ : m_buffer(buffer)
+ , m_length(length)
+ , m_offset(0) { }
+
+ bool skip(size_t numBytes)
+ {
+ if (m_offset + numBytes > m_length)
+ return false;
+ m_offset += numBytes;
+ return true;
+ }
+
+ bool readU8(uint8_t* value)
+ {
+ if (m_offset + sizeof(uint8_t) > m_length)
+ return false;
+ *value = m_buffer[m_offset];
+ m_offset += sizeof(uint8_t);
+ return true;
+ }
+
+ bool readU16(uint16_t* value)
+ {
+ if (m_offset + sizeof(uint16_t) > m_length)
+ return false;
+ memcpy(value, m_buffer + m_offset, sizeof(uint16_t));
+ *value = ntohs(*value);
+ m_offset += sizeof(uint16_t);
+ return true;
+ }
+
+ bool readS16(int16_t* value)
+ {
+ return readU16(reinterpret_cast<uint16_t*>(value));
+ }
+
+ size_t offset() const
+ {
+ return m_offset;
+ }
+
+ void setOffset(size_t newoffset)
+ {
+ m_offset = newoffset;
+ }
+
+private:
+ const uint8_t *const m_buffer;
+ const size_t m_length;
+ size_t m_offset;
+};
+
+// VDMX parsing code.
+//
+// VDMX tables are found in some TrueType/OpenType fonts and contain
+// ascender/descender overrides for certain (usually small) sizes. This is
+// needed in order to match font metrics on Windows.
+//
+// Freetype does not parse these tables so we do so here.
+
+namespace WebCore {
+
+// Parse a TrueType VDMX table.
+// yMax: (output) the ascender value from the table
+// yMin: (output) the descender value from the table (negative!)
+// vdmx: the table bytes
+// vdmxLength: length of @vdmx, in bytes
+// targetPixelSize: the pixel size of the font (e.g. 16)
+//
+// Returns true iff a suitable match are found. Otherwise, *yMax and *yMin are
+// untouched. size_t must be 32-bits to avoid overflow.
+//
+// See http://www.microsoft.com/opentype/otspec/vdmx.htm
+bool parseVDMX(int* yMax, int* yMin,
+ const uint8_t* vdmx, size_t vdmxLength,
+ unsigned targetPixelSize)
+{
+ Buffer buf(vdmx, vdmxLength);
+
+ // We ignore the version. Future tables should be backwards compatible with
+ // this layout.
+ uint16_t numRatios;
+ if (!buf.skip(4) || !buf.readU16(&numRatios))
+ return false;
+
+ // Now we have two tables. Firstly we have @numRatios Ratio records, then a
+ // matching array of @numRatios offsets. We save the offset of the beginning
+ // of this second table.
+ //
+ // Range 6 <= x <= 262146
+ unsigned long offsetTableOffset =
+ buf.offset() + 4 /* sizeof struct ratio */ * numRatios;
+
+ unsigned desiredRatio = 0xffffffff;
+ // We read 4 bytes per record, so the offset range is
+ // 6 <= x <= 524286
+ for (unsigned i = 0; i < numRatios; ++i) {
+ uint8_t xRatio, yRatio1, yRatio2;
+
+ if (!buf.skip(1)
+ || !buf.readU8(&xRatio)
+ || !buf.readU8(&yRatio1)
+ || !buf.readU8(&yRatio2))
+ return false;
+
+ // This either covers 1:1, or this is the default entry (0, 0, 0)
+ if ((xRatio == 1 && yRatio1 <= 1 && yRatio2 >= 1)
+ || (xRatio == 0 && yRatio1 == 0 && yRatio2 == 0)) {
+ desiredRatio = i;
+ break;
+ }
+ }
+
+ if (desiredRatio == 0xffffffff) // no ratio found
+ return false;
+
+ // Range 10 <= x <= 393216
+ buf.setOffset(offsetTableOffset + sizeof(uint16_t) * desiredRatio);
+
+ // Now we read from the offset table to get the offset of another array
+ uint16_t groupOffset;
+ if (!buf.readU16(&groupOffset))
+ return false;
+ // Range 0 <= x <= 65535
+ buf.setOffset(groupOffset);
+
+ uint16_t numRecords;
+ if (!buf.readU16(&numRecords) || !buf.skip(sizeof(uint16_t)))
+ return false;
+
+ // We read 6 bytes per record, so the offset range is
+ // 4 <= x <= 458749
+ for (unsigned i = 0; i < numRecords; ++i) {
+ uint16_t pixelSize;
+ if (!buf.readU16(&pixelSize))
+ return false;
+ // the entries are sorted, so we can abort early if need be
+ if (pixelSize > targetPixelSize)
+ return false;
+
+ if (pixelSize == targetPixelSize) {
+ int16_t tempYMax, tempYMin;
+ if (!buf.readS16(&tempYMax)
+ || !buf.readS16(&tempYMin))
+ return false;
+ *yMin = tempYMin;
+ *yMax = tempYMax;
+ return true;
+ }
+ if (!buf.skip(2 * sizeof(int16_t)))
+ return false;
+ }
+
+ return false;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/VDMXParser.h b/Source/WebCore/platform/graphics/chromium/VDMXParser.h
new file mode 100644
index 0000000..ef625b7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/VDMXParser.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2009, 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 VDMXParser_h
+#define VDMXParser_h
+
+namespace WebCore {
+ bool parseVDMX(int* ymax, int* ymin,
+ const uint8_t* vdmx, size_t vdmxLength,
+ unsigned targetPixelSize);
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/VideoFrameChromium.cpp b/Source/WebCore/platform/graphics/chromium/VideoFrameChromium.cpp
new file mode 100644
index 0000000..43b40e2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/VideoFrameChromium.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+
+#include "VideoFrameChromium.h"
+
+namespace WebCore {
+
+const unsigned VideoFrameChromium::maxPlanes = 3;
+const unsigned VideoFrameChromium::numRGBPlanes = 1;
+const unsigned VideoFrameChromium::rgbPlane = 0;
+const unsigned VideoFrameChromium::numYUVPlanes = 3;
+const unsigned VideoFrameChromium::yPlane = 0;
+const unsigned VideoFrameChromium::uPlane = 1;
+const unsigned VideoFrameChromium::vPlane = 2;
+
+} // namespace WebCore
+
+
diff --git a/Source/WebCore/platform/graphics/chromium/VideoFrameChromium.h b/Source/WebCore/platform/graphics/chromium/VideoFrameChromium.h
new file mode 100644
index 0000000..e176b0c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/VideoFrameChromium.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 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 VideoFrameChromium_h
+#define VideoFrameChromium_h
+
+#include "IntSize.h"
+
+namespace WebCore {
+
+// A class that represents a video frame in chromium.
+class VideoFrameChromium {
+public:
+ static const unsigned maxPlanes;
+ static const unsigned numRGBPlanes;
+ static const unsigned rgbPlane;
+ static const unsigned numYUVPlanes;
+ static const unsigned yPlane;
+ static const unsigned uPlane;
+ static const unsigned vPlane;
+
+ // These enums must be kept in sync with WebKit::WebVideoFrame.
+ enum Format {
+ Invalid,
+ RGB555,
+ RGB565,
+ RGB24,
+ RGB32,
+ RGBA,
+ YV12,
+ YV16,
+ NV12,
+ Empty,
+ ASCII,
+ };
+
+ enum SurfaceType {
+ TypeSystemMemory,
+ TypeTexture,
+ };
+
+ virtual SurfaceType surfaceType() const = 0;
+ virtual Format format() const = 0;
+ virtual unsigned width() const = 0;
+ virtual unsigned height() const = 0;
+ virtual unsigned planes() const = 0;
+ virtual int stride(unsigned plane) const = 0;
+ virtual const void* data(unsigned plane) const = 0;
+ virtual unsigned texture(unsigned plane) const = 0;
+ virtual const IntSize requiredTextureSize(unsigned plane) const = 0;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/VideoFrameProvider.h b/Source/WebCore/platform/graphics/chromium/VideoFrameProvider.h
new file mode 100644
index 0000000..c596f87
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/VideoFrameProvider.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 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 VideoFrameProvider_h
+#define VideoFrameProvider_h
+
+#include "VideoFrameChromium.h"
+
+namespace WebCore {
+
+class VideoFrameProvider {
+public:
+ virtual ~VideoFrameProvider() { }
+
+ // This function returns a pointer to a VideoFrameChromium, which is
+ // the WebCore wrapper for a video frame in Chromium. getCurrentFrame()
+ // places a lock on the frame in Chromium. Calls to this method should
+ // always be followed with a call to putCurrentFrame().
+ // The ownership of the object is not transferred to the caller and
+ // the caller should not free the returned object.
+ virtual VideoFrameChromium* getCurrentFrame() = 0;
+ // This function releases the lock on the video frame in chromium. It should
+ // always be called after getCurrentFrame(). Frames passed into this method
+ // should no longer be referenced after the call is made.
+ virtual void putCurrentFrame(VideoFrameChromium*) = 0;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp
new file mode 100644
index 0000000..81264b3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "VideoLayerChromium.h"
+
+#include "Extensions3DChromium.h"
+#include "GraphicsContext3D.h"
+#include "LayerRendererChromium.h"
+#include "NotImplemented.h"
+#include "RenderLayerBacking.h"
+#include "VideoFrameChromium.h"
+#include "VideoFrameProvider.h"
+
+namespace WebCore {
+
+// These values are magic numbers that are used in the transformation
+// from YUV to RGB color values.
+const float VideoLayerChromium::yuv2RGB[9] = {
+ 1.f, 1.f, 1.f,
+ 0.f, -.344f, 1.772f,
+ 1.403f, -.714f, 0.f,
+};
+
+VideoLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context)
+ : m_context(context)
+ , m_yuvShaderProgram(0)
+ , m_rgbaShaderProgram(0)
+ , m_yuvShaderMatrixLocation(0)
+ , m_yuvWidthScaleFactorLocation(0)
+ , m_rgbaShaderMatrixLocation(0)
+ , m_rgbaWidthScaleFactorLocation(0)
+ , m_ccMatrixLocation(0)
+ , m_yTextureLocation(0)
+ , m_uTextureLocation(0)
+ , m_vTextureLocation(0)
+ , m_rgbaTextureLocation(0)
+ , m_yuvAlphaLocation(0)
+ , m_rgbaAlphaLocation(0)
+ , m_initialized(false)
+{
+ // Frame textures are allocated based on stride width, not visible frame
+ // width, such that there is a guarantee that the frame rows line up
+ // properly and are not shifted by (stride - width) pixels. To hide the
+ // "padding" pixels between the edge of the visible frame width and the end
+ // of the stride, we give the shader a widthScaleFactor (<=1.0) of how much
+ // of the width of the texture should be shown when drawing the texture onto
+ // the vertices.
+ char vertexShaderString[] =
+ "precision mediump float; \n"
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "uniform mat4 matrix; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform float widthScaleFactor; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = matrix * a_position; \n"
+ " v_texCoord = vec2(widthScaleFactor * a_texCoord.x, a_texCoord.y); \n"
+ "} \n";
+
+ char yuvFragmentShaderString[] =
+ "precision mediump float; \n"
+ "precision mediump int; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D y_texture; \n"
+ "uniform sampler2D u_texture; \n"
+ "uniform sampler2D v_texture; \n"
+ "uniform float alpha; \n"
+ "uniform mat3 cc_matrix; \n"
+ "void main() \n"
+ "{ \n"
+ " float y = texture2D(y_texture, v_texCoord).x; \n"
+ " float u = texture2D(u_texture, v_texCoord).r - .5; \n"
+ " float v = texture2D(v_texture, v_texCoord).r - .5; \n"
+ " vec3 rgb = cc_matrix * vec3(y, u, v); \n"
+ " gl_FragColor = vec4(rgb.x, rgb.y, rgb.z, 1.0) * alpha; \n"
+ "} \n";
+
+ char rgbaFragmentShaderString[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D rgba_texture; \n"
+ "uniform float alpha; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 texColor = texture2D(rgba_texture, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n"
+ " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n"
+ "} \n";
+
+ m_rgbaShaderProgram = createShaderProgram(m_context, vertexShaderString, rgbaFragmentShaderString);
+ if (!m_rgbaShaderProgram) {
+ LOG_ERROR("VideoLayerChromium: Failed to create rgba shader program");
+ return;
+ }
+
+ m_yuvShaderProgram = createShaderProgram(m_context, vertexShaderString, yuvFragmentShaderString);
+ if (!m_yuvShaderProgram) {
+ LOG_ERROR("VideoLayerChromium: Failed to create yuv shader program");
+ return;
+ }
+
+ m_yuvShaderMatrixLocation = m_context->getUniformLocation(m_yuvShaderProgram, "matrix");
+ m_yuvWidthScaleFactorLocation = m_context->getUniformLocation(m_yuvShaderProgram, "widthScaleFactor");
+ m_yTextureLocation = m_context->getUniformLocation(m_yuvShaderProgram, "y_texture");
+ m_uTextureLocation = m_context->getUniformLocation(m_yuvShaderProgram, "u_texture");
+ m_vTextureLocation = m_context->getUniformLocation(m_yuvShaderProgram, "v_texture");
+ m_ccMatrixLocation = m_context->getUniformLocation(m_yuvShaderProgram, "cc_matrix");
+ m_yuvAlphaLocation = m_context->getUniformLocation(m_yuvShaderProgram, "alpha");
+
+ ASSERT(m_yuvShaderMatrixLocation != -1);
+ ASSERT(m_yuvWidthScaleFactorLocation != -1);
+ ASSERT(m_yTextureLocation != -1);
+ ASSERT(m_uTextureLocation != -1);
+ ASSERT(m_vTextureLocation != -1);
+ ASSERT(m_ccMatrixLocation != -1);
+ ASSERT(m_yuvAlphaLocation != -1);
+
+ m_rgbaShaderMatrixLocation = m_context->getUniformLocation(m_rgbaShaderProgram, "matrix");
+ m_rgbaTextureLocation = m_context->getUniformLocation(m_rgbaShaderProgram, "rgba_texture");
+ m_rgbaWidthScaleFactorLocation = m_context->getUniformLocation(m_rgbaShaderProgram, "widthScaleFactor");
+ m_rgbaAlphaLocation = m_context->getUniformLocation(m_rgbaShaderProgram, "alpha");
+
+ ASSERT(m_rgbaShaderMatrixLocation != -1);
+ ASSERT(m_rgbaTextureLocation != -1);
+ ASSERT(m_rgbaWidthScaleFactorLocation != -1);
+ ASSERT(m_rgbaAlphaLocation != -1);
+
+ m_initialized = true;
+}
+
+VideoLayerChromium::SharedValues::~SharedValues()
+{
+ if (m_yuvShaderProgram)
+ GLC(m_context, m_context->deleteProgram(m_yuvShaderProgram));
+ if (m_rgbaShaderProgram)
+ GLC(m_context, m_context->deleteProgram(m_rgbaShaderProgram));
+}
+
+PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(GraphicsLayerChromium* owner,
+ VideoFrameProvider* provider)
+{
+ return adoptRef(new VideoLayerChromium(owner, provider));
+}
+
+VideoLayerChromium::VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameProvider* provider)
+ : LayerChromium(owner)
+ , m_skipsDraw(true)
+ , m_frameFormat(VideoFrameChromium::Invalid)
+ , m_provider(provider)
+ , m_currentFrame(0)
+{
+ resetFrameParameters();
+}
+
+VideoLayerChromium::~VideoLayerChromium()
+{
+ cleanupResources();
+}
+
+void VideoLayerChromium::cleanupResources()
+{
+ LayerChromium::cleanupResources();
+ releaseCurrentFrame();
+ if (!layerRenderer())
+ return;
+
+ GraphicsContext3D* context = layerRendererContext();
+ for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) {
+ if (m_textures[plane])
+ GLC(context, context->deleteTexture(m_textures[plane]));
+ }
+}
+
+void VideoLayerChromium::updateContentsIfDirty()
+{
+ if (!m_contentsDirty)
+ return;
+
+ RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client());
+ if (!backing || backing->paintingGoesToWindow())
+ return;
+
+ ASSERT(drawsContent());
+
+ m_skipsDraw = false;
+ VideoFrameChromium* frame = m_provider->getCurrentFrame();
+ if (!frame) {
+ m_skipsDraw = true;
+ m_provider->putCurrentFrame(frame);
+ return;
+ }
+
+ m_frameFormat = frame->format();
+ unsigned textureFormat = determineTextureFormat(frame);
+ if (textureFormat == GraphicsContext3D::INVALID_VALUE) {
+ // FIXME: Implement other paths.
+ notImplemented();
+ m_skipsDraw = true;
+ m_provider->putCurrentFrame(frame);
+ return;
+ }
+
+ if (frame->surfaceType() == VideoFrameChromium::TypeTexture) {
+ releaseCurrentFrame();
+ saveCurrentFrame(frame);
+ m_dirtyRect.setSize(FloatSize());
+ m_contentsDirty = false;
+ return;
+ }
+
+ // Allocate textures for planes if they are not allocated already, or
+ // reallocate textures that are the wrong size for the frame.
+ GraphicsContext3D* context = layerRendererContext();
+ bool texturesAllocated = allocateTexturesIfNeeded(context, frame, textureFormat);
+ if (!texturesAllocated) {
+ m_skipsDraw = true;
+ m_provider->putCurrentFrame(frame);
+ return;
+ }
+
+ // Update texture planes.
+ for (unsigned plane = 0; plane < frame->planes(); plane++) {
+ ASSERT(frame->requiredTextureSize(plane) == m_textureSizes[plane]);
+ updateTexture(context, m_textures[plane], frame->requiredTextureSize(plane), textureFormat, frame->data(plane));
+ }
+
+ m_dirtyRect.setSize(FloatSize());
+ m_contentsDirty = false;
+
+ m_provider->putCurrentFrame(frame);
+}
+
+unsigned VideoLayerChromium::determineTextureFormat(VideoFrameChromium* frame)
+{
+ switch (frame->format()) {
+ case VideoFrameChromium::YV12:
+ return GraphicsContext3D::LUMINANCE;
+ case VideoFrameChromium::RGBA:
+ return GraphicsContext3D::RGBA;
+ default:
+ break;
+ }
+ return GraphicsContext3D::INVALID_VALUE;
+}
+
+bool VideoLayerChromium::allocateTexturesIfNeeded(GraphicsContext3D* context, VideoFrameChromium* frame, unsigned textureFormat)
+{
+ ASSERT(context);
+ ASSERT(frame);
+
+ for (unsigned plane = 0; plane < frame->planes(); plane++) {
+ IntSize planeTextureSize = frame->requiredTextureSize(plane);
+
+ // If the renderer cannot handle this large of a texture, return false.
+ // FIXME: Remove this test when tiled layers are implemented.
+ if (!layerRenderer()->checkTextureSize(planeTextureSize))
+ return false;
+
+ if (!m_textures[plane])
+ m_textures[plane] = layerRenderer()->createLayerTexture();
+
+ if (!planeTextureSize.isZero() && planeTextureSize != m_textureSizes[plane]) {
+ allocateTexture(context, m_textures[plane], planeTextureSize, textureFormat);
+ m_textureSizes[plane] = planeTextureSize;
+ m_frameSizes[plane] = IntSize(frame->width(), frame->height());
+ }
+ }
+ return true;
+}
+
+void VideoLayerChromium::allocateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned textureFormat)
+{
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
+ GLC(context, context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, textureFormat, dimensions.width(), dimensions.height(), 0, textureFormat, GraphicsContext3D::UNSIGNED_BYTE));
+}
+
+void VideoLayerChromium::updateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned format, const void* data)
+{
+ ASSERT(context);
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
+ void* mem = static_cast<Extensions3DChromium*>(context->getExtensions())->mapTexSubImage2DCHROMIUM(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, dimensions.width(), dimensions.height(), format, GraphicsContext3D::UNSIGNED_BYTE, Extensions3DChromium::WRITE_ONLY);
+ if (mem) {
+ memcpy(mem, data, dimensions.width() * dimensions.height());
+ GLC(context, static_cast<Extensions3DChromium*>(context->getExtensions())->unmapTexSubImage2DCHROMIUM(mem));
+ } else {
+ // FIXME: We should have some sort of code to handle the case when
+ // mapTexSubImage2D fails.
+ m_skipsDraw = true;
+ }
+}
+
+void VideoLayerChromium::draw()
+{
+ if (m_skipsDraw)
+ return;
+
+ ASSERT(layerRenderer());
+ const VideoLayerChromium::SharedValues* sv = layerRenderer()->videoLayerSharedValues();
+ ASSERT(sv && sv->initialized());
+
+ switch (m_frameFormat) {
+ case VideoFrameChromium::YV12:
+ drawYUV(sv);
+ break;
+ case VideoFrameChromium::RGBA:
+ drawRGBA(sv);
+ break;
+ default:
+ // FIXME: Implement other paths.
+ notImplemented();
+ break;
+ }
+ releaseCurrentFrame();
+}
+
+void VideoLayerChromium::releaseCurrentFrame()
+{
+ if (!m_currentFrame)
+ return;
+
+ m_provider->putCurrentFrame(m_currentFrame);
+ m_currentFrame = 0;
+ resetFrameParameters();
+}
+
+void VideoLayerChromium::drawYUV(const SharedValues* sv)
+{
+ GraphicsContext3D* context = layerRendererContext();
+ GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE1));
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::yPlane]));
+ GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE2));
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::uPlane]));
+ GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE3));
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::vPlane]));
+
+ layerRenderer()->useShader(sv->yuvShaderProgram());
+ unsigned frameWidth = m_frameSizes[VideoFrameChromium::yPlane].width();
+ unsigned textureWidth = m_textureSizes[VideoFrameChromium::yPlane].width();
+ float widthScaleFactor = static_cast<float>(frameWidth) / textureWidth;
+ GLC(context, context->uniform1f(sv->yuvWidthScaleFactorLocation(), widthScaleFactor));
+
+ GLC(context, context->uniform1i(sv->yTextureLocation(), 1));
+ GLC(context, context->uniform1i(sv->uTextureLocation(), 2));
+ GLC(context, context->uniform1i(sv->vTextureLocation(), 3));
+
+ GLC(context, context->uniformMatrix3fv(sv->ccMatrixLocation(), 0, const_cast<float*>(yuv2RGB), 1));
+
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(),
+ bounds().width(), bounds().height(), drawOpacity(),
+ sv->yuvShaderMatrixLocation(), sv->yuvAlphaLocation());
+
+ // Reset active texture back to texture 0.
+ GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0));
+}
+
+void VideoLayerChromium::drawRGBA(const SharedValues* sv)
+{
+ GraphicsContext3D* context = layerRendererContext();
+ GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0));
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::rgbPlane]));
+
+ layerRenderer()->useShader(sv->rgbaShaderProgram());
+ unsigned frameWidth = m_frameSizes[VideoFrameChromium::rgbPlane].width();
+ unsigned textureWidth = m_textureSizes[VideoFrameChromium::rgbPlane].width();
+ float widthScaleFactor = static_cast<float>(frameWidth) / textureWidth;
+ GLC(context, context->uniform1f(sv->rgbaWidthScaleFactorLocation(), widthScaleFactor));
+
+ GLC(context, context->uniform1i(sv->rgbaTextureLocation(), 0));
+
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(),
+ bounds().width(), bounds().height(), drawOpacity(),
+ sv->rgbaShaderMatrixLocation(), sv->rgbaAlphaLocation());
+}
+
+void VideoLayerChromium::resetFrameParameters()
+{
+ for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) {
+ m_textures[plane] = 0;
+ m_textureSizes[plane] = IntSize();
+ m_frameSizes[plane] = IntSize();
+ }
+}
+
+void VideoLayerChromium::saveCurrentFrame(VideoFrameChromium* frame)
+{
+ ASSERT(!m_currentFrame);
+ m_currentFrame = frame;
+ for (unsigned plane = 0; plane < frame->planes(); plane++) {
+ m_textures[plane] = frame->texture(plane);
+ m_textureSizes[plane] = frame->requiredTextureSize(plane);
+ m_frameSizes[plane] = m_textureSizes[plane];
+ }
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h
new file mode 100644
index 0000000..0992ab7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 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 VideoLayerChromium_h
+#define VideoLayerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "LayerChromium.h"
+#include "VideoFrameProvider.h"
+
+namespace WebCore {
+
+// A Layer that contains a Video element.
+class VideoLayerChromium : public LayerChromium {
+public:
+ static PassRefPtr<VideoLayerChromium> create(GraphicsLayerChromium* owner = 0,
+ VideoFrameProvider* = 0);
+ virtual ~VideoLayerChromium();
+ virtual void updateContentsIfDirty();
+ virtual bool drawsContent() { return true; }
+ virtual void draw();
+
+ // This function is called by VideoFrameProvider. When this method is called
+ // putCurrentFrame() must be called to return the frame currently held.
+ void releaseCurrentFrame();
+
+ class SharedValues {
+ public:
+ explicit SharedValues(GraphicsContext3D*);
+ ~SharedValues();
+ unsigned yuvShaderProgram() const { return m_yuvShaderProgram; }
+ unsigned rgbaShaderProgram() const { return m_rgbaShaderProgram; }
+ int yuvShaderMatrixLocation() const { return m_yuvShaderMatrixLocation; }
+ int rgbaShaderMatrixLocation() const { return m_rgbaShaderMatrixLocation; }
+ int yuvWidthScaleFactorLocation() const { return m_yuvWidthScaleFactorLocation; }
+ int rgbaWidthScaleFactorLocation() const { return m_rgbaWidthScaleFactorLocation; }
+ int yTextureLocation() const { return m_yTextureLocation; }
+ int uTextureLocation() const { return m_uTextureLocation; }
+ int vTextureLocation() const { return m_vTextureLocation; }
+ int yuvAlphaLocation() const { return m_yuvAlphaLocation; }
+ int rgbaAlphaLocation() const { return m_rgbaAlphaLocation; }
+ int rgbaTextureLocation() const { return m_rgbaTextureLocation; }
+ int ccMatrixLocation() const { return m_ccMatrixLocation; }
+ bool initialized() const { return m_initialized; }
+ private:
+ GraphicsContext3D* m_context;
+ unsigned m_yuvShaderProgram;
+ unsigned m_rgbaShaderProgram;
+ int m_yuvShaderMatrixLocation;
+ int m_yuvWidthScaleFactorLocation;
+ int m_rgbaShaderMatrixLocation;
+ int m_rgbaWidthScaleFactorLocation;
+ int m_ccMatrixLocation;
+ int m_yTextureLocation;
+ int m_uTextureLocation;
+ int m_vTextureLocation;
+ int m_rgbaTextureLocation;
+ int m_yuvAlphaLocation;
+ int m_rgbaAlphaLocation;
+ bool m_initialized;
+ };
+
+protected:
+ virtual void cleanupResources();
+
+private:
+ VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameProvider*);
+
+ static unsigned determineTextureFormat(VideoFrameChromium*);
+ bool allocateTexturesIfNeeded(GraphicsContext3D*, VideoFrameChromium*, unsigned textureFormat);
+ void updateYUVContents(GraphicsContext3D*, const VideoFrameChromium*);
+ void updateRGBAContents(GraphicsContext3D*, const VideoFrameChromium*);
+ void allocateTexture(GraphicsContext3D*, unsigned textureId, const IntSize& dimensions, unsigned textureFormat);
+ void updateTexture(GraphicsContext3D*, unsigned textureId, const IntSize& dimensions, unsigned textureFormat, const void* data);
+ void drawYUV(const SharedValues*);
+ void drawRGBA(const SharedValues*);
+ void resetFrameParameters();
+ void saveCurrentFrame(VideoFrameChromium*);
+
+ static const float yuv2RGB[9];
+
+ bool m_skipsDraw;
+ VideoFrameChromium::Format m_frameFormat;
+ VideoFrameProvider* m_provider;
+ VideoFrameChromium* m_currentFrame;
+
+ unsigned m_textures[3];
+ IntSize m_textureSizes[3];
+ IntSize m_frameSizes[3];
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp
new file mode 100644
index 0000000..5b34bb9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WebGLLayerChromium.h"
+
+#include "GraphicsContext3D.h"
+#include "LayerRendererChromium.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLLayerChromium> WebGLLayerChromium::create(GraphicsLayerChromium* owner)
+{
+ return adoptRef(new WebGLLayerChromium(owner));
+}
+
+WebGLLayerChromium::WebGLLayerChromium(GraphicsLayerChromium* owner)
+ : CanvasLayerChromium(owner)
+ , m_context(0)
+{
+}
+
+void WebGLLayerChromium::updateContentsIfDirty()
+{
+ if (!m_contentsDirty)
+ return;
+
+ GraphicsContext3D* rendererContext = layerRendererContext();
+ ASSERT(m_context);
+ if (m_textureChanged) {
+ rendererContext->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId);
+ // Set the min-mag filters to linear and wrap modes to GL_CLAMP_TO_EDGE
+ // to get around NPOT texture limitations of GLES.
+ rendererContext->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
+ rendererContext->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
+ rendererContext->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
+ rendererContext->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
+ m_textureChanged = false;
+ }
+ // Update the contents of the texture used by the compositor.
+ if (m_contentsDirty) {
+ m_context->prepareTexture();
+ m_contentsDirty = false;
+ }
+}
+
+void WebGLLayerChromium::setContext(const GraphicsContext3D* context)
+{
+ m_context = const_cast<GraphicsContext3D*>(context);
+
+ unsigned int textureId = m_context->platformTexture();
+ if (textureId != m_textureId)
+ m_textureChanged = true;
+ m_textureId = textureId;
+}
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h
new file mode 100644
index 0000000..c67cc2c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 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 WebGLLayerChromium_h
+#define WebGLLayerChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "CanvasLayerChromium.h"
+
+namespace WebCore {
+
+class GraphicsContext3D;
+
+// A Layer containing a WebGL canvas
+class WebGLLayerChromium : public CanvasLayerChromium {
+public:
+ static PassRefPtr<WebGLLayerChromium> create(GraphicsLayerChromium* owner = 0);
+ virtual bool drawsContent() { return m_context; }
+ virtual void updateContentsIfDirty();
+
+ void setContext(const GraphicsContext3D* context);
+
+private:
+ explicit WebGLLayerChromium(GraphicsLayerChromium* owner);
+ GraphicsContext3D* m_context;
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h b/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h
new file mode 100644
index 0000000..8cf08fb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h
@@ -0,0 +1,170 @@
+/*
+ * This file is part of the internal font implementation.
+ * It should not be included by source files outside of it.
+ *
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+#include "FontOrientation.h"
+#include <wtf/text/StringImpl.h>
+
+#ifdef __OBJC__
+@class NSFont;
+#else
+class NSFont;
+#endif
+
+typedef struct CGFont* CGFontRef;
+#ifndef BUILDING_ON_TIGER
+typedef const struct __CTFont* CTFontRef;
+#endif
+
+#include <CoreFoundation/CFBase.h>
+#include <objc/objc-auto.h>
+#include <wtf/Forward.h>
+#include <wtf/RetainPtr.h>
+
+#if PLATFORM(CHROMIUM) && OS(DARWIN)
+#include "CrossProcessFontLoading.h"
+#endif
+
+
+typedef UInt32 ATSUFontID;
+typedef UInt32 ATSFontRef;
+
+namespace WebCore {
+
+#ifndef BUILDING_ON_TIGER
+inline CTFontRef toCTFontRef(NSFont *nsFont) { return reinterpret_cast<CTFontRef>(nsFont); }
+#endif
+
+class FontPlatformData {
+ public:
+ FontPlatformData(float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation = Horizontal)
+ : m_syntheticBold(syntheticBold)
+ , m_syntheticOblique(syntheticOblique)
+ , m_orientation(orientation)
+ , m_size(size)
+ , m_font(0)
+#ifdef BUILDING_ON_TIGER
+ , m_cgFont(0)
+#endif
+ , m_isColorBitmapFont(false)
+ {
+ }
+
+ FontPlatformData(NSFont *nsFont, float size, bool syntheticBold = false, bool syntheticOblique = false, FontOrientation = Horizontal);
+
+ FontPlatformData(CGFontRef cgFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation)
+ : m_syntheticBold(syntheticBold)
+ , m_syntheticOblique(syntheticOblique)
+ , m_orientation(orientation)
+ , m_size(size)
+ , m_font(0)
+ , m_cgFont(cgFont)
+ , m_isColorBitmapFont(false)
+ {
+ }
+
+ FontPlatformData(const FontPlatformData&);
+
+ ~FontPlatformData();
+
+ FontPlatformData(WTF::HashTableDeletedValueType) : m_font(hashTableDeletedFontValue()) { }
+ bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); }
+
+ float size() const { return m_size; }
+ bool syntheticBold() const { return m_syntheticBold; }
+ bool syntheticOblique() const { return m_syntheticOblique; }
+ FontOrientation orientation() const { return m_orientation; }
+
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+ FontOrientation m_orientation;
+
+ float m_size;
+
+ unsigned hash() const
+ {
+ ASSERT(m_font != 0 || m_cgFont == 0);
+ uintptr_t hashCodes[2] = { (uintptr_t)m_font, m_orientation << 2 | m_syntheticBold << 1 | m_syntheticOblique };
+ return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+ }
+
+ const FontPlatformData& operator=(const FontPlatformData& f);
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ return m_font == other.m_font && m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique &&
+ m_cgFont == other.m_cgFont && m_size == other.m_size && m_orientation == other.m_orientation;
+ }
+
+ NSFont *font() const { return m_font; }
+ void setFont(NSFont *font);
+
+ CTFontRef ctFont() const;
+
+ bool roundsGlyphAdvances() const;
+ bool allowsLigatures() const;
+ bool isColorBitmapFont() const { return m_isColorBitmapFont; }
+
+#ifndef BUILDING_ON_TIGER
+ CGFontRef cgFont() const { return m_cgFont.get(); }
+#else
+ CGFontRef cgFont() const { return m_cgFont; }
+#endif
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+private:
+ static NSFont *hashTableDeletedFontValue() { return reinterpret_cast<NSFont *>(-1); }
+
+ // Load various data about the font specified by |nsFont| with the size fontSize into the following output paramters:
+ // Note: Callers should always take into account that for the Chromium port, |outNSFont| isn't necessarily the same
+ // font as |nsFont|. This because the sandbox may block loading of the original font.
+ // * outNSFont - The font that was actually loaded, for the Chromium port this may be different than nsFont.
+ // The caller is responsible for calling CFRelease() on this parameter when done with it.
+ // * cgFont - CGFontRef representing the input font at the specified point size.
+ void loadFont(NSFont* nsFont, float fontSize, NSFont*& outNSFont, CGFontRef& cgFont);
+
+ NSFont *m_font;
+
+#ifndef BUILDING_ON_TIGER
+ RetainPtr<CGFontRef> m_cgFont;
+#else
+ CGFontRef m_cgFont; // It is not necessary to refcount this, since either an NSFont owns it or some CachedFont has it referenced.
+#endif
+
+ mutable RetainPtr<CTFontRef> m_CTFont;
+
+ bool m_isColorBitmapFont;
+
+#if PLATFORM(CHROMIUM) && OS(DARWIN)
+ RefPtr<MemoryActivatedFont> m_inMemoryFont;
+#endif
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm b/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm
new file mode 100644
index 0000000..8dacbe3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm
@@ -0,0 +1,186 @@
+/*
+ * This file is part of the internal font implementation.
+ *
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2010 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#import "config.h"
+#import "FontPlatformData.h"
+
+#import "PlatformString.h"
+#import "WebCoreSystemInterface.h"
+#import <AppKit/NSFont.h>
+
+namespace WebCore {
+
+#if PLATFORM(MAC)
+void FontPlatformData::loadFont(NSFont* nsFont, float, NSFont*& outNSFont, CGFontRef& cgFont)
+{
+ outNSFont = nsFont;
+#ifndef BUILDING_ON_TIGER
+ cgFont = CTFontCopyGraphicsFont(toCTFontRef(nsFont), 0);
+#else
+ cgFont = wkGetCGFontFromNSFont(nsFont);
+#endif
+}
+#endif // PLATFORM(MAC)
+
+FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation)
+ : m_syntheticBold(syntheticBold)
+ , m_syntheticOblique(syntheticOblique)
+ , m_size(size)
+ , m_font(nsFont)
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ // FIXME: Chromium: The following code isn't correct for the Chromium port since the sandbox might
+ // have blocked font loading, in which case we'll only have the real loaded font file after the call to loadFont().
+ , m_isColorBitmapFont(CTFontGetSymbolicTraits(toCTFontRef(nsFont)) & kCTFontColorGlyphsTrait)
+#else
+ , m_isColorBitmapFont(false)
+#endif
+{
+ ASSERT_ARG(nsFont, nsFont);
+
+ CGFontRef cgFont = 0;
+ loadFont(nsFont, size, m_font, cgFont);
+
+ m_orientation = orientation;
+
+ if (m_font)
+ CFRetain(m_font);
+
+#ifndef BUILDING_ON_TIGER
+ m_cgFont.adoptCF(cgFont);
+#else
+ m_cgFont = cgFont;
+#endif
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& f)
+{
+ m_font = f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1) ? const_cast<NSFont *>(static_cast<const NSFont *>(CFRetain(f.m_font))) : f.m_font;
+
+ m_syntheticBold = f.m_syntheticBold;
+ m_syntheticOblique = f.m_syntheticOblique;
+ m_size = f.m_size;
+ m_cgFont = f.m_cgFont;
+ m_isColorBitmapFont = f.m_isColorBitmapFont;
+ m_orientation = f.m_orientation;
+ m_CTFont = f.m_CTFont;
+#if PLATFORM(CHROMIUM) && OS(DARWIN)
+ m_inMemoryFont = f.m_inMemoryFont;
+#endif
+}
+
+FontPlatformData:: ~FontPlatformData()
+{
+ if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
+ CFRelease(m_font);
+}
+
+const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& f)
+{
+ m_syntheticBold = f.m_syntheticBold;
+ m_syntheticOblique = f.m_syntheticOblique;
+ m_size = f.m_size;
+ m_cgFont = f.m_cgFont;
+ if (m_font == f.m_font)
+ return *this;
+ if (f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1))
+ CFRetain(f.m_font);
+ if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
+ CFRelease(m_font);
+ m_font = f.m_font;
+ m_isColorBitmapFont = f.m_isColorBitmapFont;
+ m_orientation = f.m_orientation;
+ m_CTFont = f.m_CTFont;
+#if PLATFORM(CHROMIUM) && OS(DARWIN)
+ m_inMemoryFont = f.m_inMemoryFont;
+#endif
+ return *this;
+}
+
+void FontPlatformData::setFont(NSFont *font)
+{
+ ASSERT_ARG(font, font);
+ ASSERT(m_font != reinterpret_cast<NSFont *>(-1));
+
+ if (m_font == font)
+ return;
+
+ CFRetain(font);
+ if (m_font)
+ CFRelease(m_font);
+ m_font = font;
+ m_size = [font pointSize];
+
+ CGFontRef cgFont = 0;
+ NSFont* loadedFont = 0;
+ loadFont(m_font, m_size, loadedFont, cgFont);
+
+#if PLATFORM(CHROMIUM) && OS(DARWIN)
+ // If loadFont replaced m_font with a fallback font, then release the
+ // previous font to counter the retain above. Then retain the new font.
+ if (loadedFont != m_font) {
+ CFRelease(m_font);
+ CFRetain(loadedFont);
+ m_font = loadedFont;
+ }
+#endif
+
+#ifndef BUILDING_ON_TIGER
+ m_cgFont.adoptCF(cgFont);
+#else
+ m_cgFont = cgFont;
+#endif
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ m_isColorBitmapFont = CTFontGetSymbolicTraits(toCTFontRef(m_font)) & kCTFontColorGlyphsTrait;
+#endif
+ m_CTFont = 0;
+}
+
+bool FontPlatformData::roundsGlyphAdvances() const
+{
+ return [m_font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode;
+}
+
+bool FontPlatformData::allowsLigatures() const
+{
+ return ![[m_font coveredCharacterSet] characterIsMember:'a'];
+}
+
+CTFontRef FontPlatformData::ctFont() const
+{
+ if (m_font)
+ return toCTFontRef(m_font);
+ if (!m_CTFont)
+ m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, 0));
+ return m_CTFont.get();
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ RetainPtr<CFStringRef> cgFontDescription(AdoptCF, CFCopyDescription(cgFont()));
+ return String(cgFontDescription.get()) + " " + String::number(m_size)
+ + (m_syntheticBold ? " synthetic bold" : "") + (m_syntheticOblique ? " synthetic oblique" : "") + (m_orientation ? " vertical orientation" : "");
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/efl/FontEfl.cpp b/Source/WebCore/platform/graphics/efl/FontEfl.cpp
new file mode 100644
index 0000000..d3ca183
--- /dev/null
+++ b/Source/WebCore/platform/graphics/efl/FontEfl.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
+ * Copyright (C) 2009-2010 ProFUSION embedded systems
+ * Copyright (C) 2009-2010 Samsung Electronics
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+void Font::drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const
+{
+ notImplemented();
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+float Font::floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>*, GlyphOverflow*) const
+{
+ notImplemented();
+ return 0.0f;
+}
+
+int Font::offsetForPositionForComplexText(const TextRun&, float, bool) const
+{
+ notImplemented();
+ return 0;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun&, const FloatPoint&, int, int, int) const
+{
+ notImplemented();
+ return FloatRect();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/efl/IconEfl.cpp b/Source/WebCore/platform/graphics/efl/IconEfl.cpp
new file mode 100644
index 0000000..6b3de04
--- /dev/null
+++ b/Source/WebCore/platform/graphics/efl/IconEfl.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
+ * Copyright (C) 2009-2010 ProFUSION embedded systems
+ * Copyright (C) 2009-2010 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "PassRefPtr.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+Icon::Icon()
+ : m_icon(0)
+{
+ notImplemented();
+}
+
+Icon::~Icon()
+{
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ notImplemented();
+ return 0;
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& rect)
+{
+ notImplemented();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/efl/ImageEfl.cpp b/Source/WebCore/platform/graphics/efl/ImageEfl.cpp
new file mode 100644
index 0000000..a86ba4e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/efl/ImageEfl.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 Kenneth Rohde Christiansen. All rights reserved.
+ * Copyright (C) 2009-2010 ProFUSION embedded systems
+ * Copyright (C) 2009-2010 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "BitmapImage.h"
+#include "SharedBuffer.h"
+
+#include <wtf/text/StringConcatenate.h>
+#include <cairo.h>
+
+namespace WebCore {
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+static PassRefPtr<SharedBuffer> loadResourceSharedBufferFallback()
+{
+ return SharedBuffer::create(); // TODO: fallback image?
+}
+
+static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(const char* name)
+{
+ RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(makeString(DATA_DIR "/webkit-1.0/images/", name, ".png"));
+ if (buffer)
+ return buffer.release();
+ return loadResourceSharedBufferFallback();
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+{
+ RefPtr<BitmapImage> img = BitmapImage::create();
+ RefPtr<SharedBuffer> buffer = loadResourceSharedBuffer(name);
+ img->setData(buffer.release(), true);
+ return img.release();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/efl/IntPointEfl.cpp b/Source/WebCore/platform/graphics/efl/IntPointEfl.cpp
new file mode 100644
index 0000000..76a25e1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/efl/IntPointEfl.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
+ * Copyright (C) 2009-2010 ProFUSION embedded systems
+ * Copyright (C) 2009-2010 Samsung Electronics
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include <Evas.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const Evas_Point& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator Evas_Point() const // NOLINT
+{
+ Evas_Point p = { x(), y() };
+ return p;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/efl/IntRectEfl.cpp b/Source/WebCore/platform/graphics/efl/IntRectEfl.cpp
new file mode 100644
index 0000000..0c92f63
--- /dev/null
+++ b/Source/WebCore/platform/graphics/efl/IntRectEfl.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include <Eina.h>
+
+namespace WebCore {
+
+IntRect::IntRect(const Eina_Rectangle& r)
+ : m_location(IntPoint(r.x, r.y))
+ , m_size(r.w, r.h)
+{
+}
+
+IntRect::operator Eina_Rectangle() const
+{
+ Eina_Rectangle r = {x(), y(), width(), height()};
+ return r;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/filters/DistantLightSource.h b/Source/WebCore/platform/graphics/filters/DistantLightSource.h
new file mode 100644
index 0000000..d5d474f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/DistantLightSource.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef DistantLightSource_h
+#define DistantLightSource_h
+
+#if ENABLE(FILTERS)
+#include "LightSource.h"
+
+namespace WebCore {
+
+class DistantLightSource : public LightSource {
+public:
+ static PassRefPtr<DistantLightSource> create(float azimuth, float elevation)
+ {
+ return adoptRef(new DistantLightSource(azimuth, elevation));
+ }
+
+ float azimuth() const { return m_azimuth; }
+ float elevation() const { return m_elevation; }
+
+ virtual void initPaintingData(PaintingData&);
+ virtual void updatePaintingData(PaintingData&, int x, int y, float z);
+
+ virtual TextStream& externalRepresentation(TextStream&) const;
+
+private:
+ DistantLightSource(float azimuth, float elevation)
+ : LightSource(LS_DISTANT)
+ , m_azimuth(azimuth)
+ , m_elevation(elevation)
+ {
+ }
+
+ float m_azimuth;
+ float m_elevation;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // DistantLightSource_h
diff --git a/Source/WebCore/platform/graphics/filters/FEBlend.cpp b/Source/WebCore/platform/graphics/filters/FEBlend.cpp
new file mode 100644
index 0000000..7eeb128
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEBlend.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEBlend.h"
+
+#include "Filter.h"
+#include "FloatPoint.h"
+#include "GraphicsContext.h"
+
+#include <wtf/ByteArray.h>
+
+typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB);
+
+namespace WebCore {
+
+FEBlend::FEBlend(Filter* filter, BlendModeType mode)
+ : FilterEffect(filter)
+ , m_mode(mode)
+{
+}
+
+PassRefPtr<FEBlend> FEBlend::create(Filter* filter, BlendModeType mode)
+{
+ return adoptRef(new FEBlend(filter, mode));
+}
+
+BlendModeType FEBlend::blendMode() const
+{
+ return m_mode;
+}
+
+void FEBlend::setBlendMode(BlendModeType mode)
+{
+ m_mode = mode;
+}
+
+static unsigned char unknown(unsigned char, unsigned char, unsigned char, unsigned char)
+{
+ return 0;
+}
+
+static unsigned char normal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char)
+{
+ return (((255 - alphaA) * colorB + colorA * 255) / 255);
+}
+
+static unsigned char multiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
+{
+ return (((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA) / 255);
+}
+
+static unsigned char screen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char)
+{
+ return (((colorB + colorA) * 255 - colorA * colorB) / 255);
+}
+
+static unsigned char darken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
+{
+ return ((std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255);
+}
+
+static unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
+{
+ return ((std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255);
+}
+
+void FEBlend::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ FilterEffect* in2 = inputEffect(1);
+ in->apply();
+ in2->apply();
+ if (!in->hasResult() || !in2->hasResult())
+ return;
+
+ if (m_mode <= FEBLEND_MODE_UNKNOWN || m_mode > FEBLEND_MODE_LIGHTEN)
+ return;
+
+ ByteArray* dstPixelArray = createPremultipliedImageResult();
+ if (!dstPixelArray)
+ return;
+
+ IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
+ RefPtr<ByteArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect);
+
+ IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
+ RefPtr<ByteArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect);
+
+ // Keep synchronized with BlendModeType
+ static const BlendType callEffect[] = {unknown, normal, multiply, screen, darken, lighten};
+
+ unsigned pixelArrayLength = srcPixelArrayA->length();
+ ASSERT(pixelArrayLength == srcPixelArrayB->length());
+ for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
+ unsigned char alphaA = srcPixelArrayA->get(pixelOffset + 3);
+ unsigned char alphaB = srcPixelArrayB->get(pixelOffset + 3);
+ for (unsigned channel = 0; channel < 3; ++channel) {
+ unsigned char colorA = srcPixelArrayA->get(pixelOffset + channel);
+ unsigned char colorB = srcPixelArrayB->get(pixelOffset + channel);
+
+ unsigned char result = (*callEffect[m_mode])(colorA, colorB, alphaA, alphaB);
+ dstPixelArray->set(pixelOffset + channel, result);
+ }
+ unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255;
+ dstPixelArray->set(pixelOffset + 3, alphaR);
+ }
+}
+
+void FEBlend::dump()
+{
+}
+
+static TextStream& operator<<(TextStream& ts, const BlendModeType& type)
+{
+ switch (type) {
+ case FEBLEND_MODE_UNKNOWN:
+ ts << "UNKNOWN";
+ break;
+ case FEBLEND_MODE_NORMAL:
+ ts << "NORMAL";
+ break;
+ case FEBLEND_MODE_MULTIPLY:
+ ts << "MULTIPLY";
+ break;
+ case FEBLEND_MODE_SCREEN:
+ ts << "SCREEN";
+ break;
+ case FEBLEND_MODE_DARKEN:
+ ts << "DARKEN";
+ break;
+ case FEBLEND_MODE_LIGHTEN:
+ ts << "LIGHTEN";
+ break;
+ }
+ return ts;
+}
+
+TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feBlend";
+ FilterEffect::externalRepresentation(ts);
+ ts << " mode=\"" << m_mode << "\"]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ inputEffect(1)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEBlend.h b/Source/WebCore/platform/graphics/filters/FEBlend.h
new file mode 100644
index 0000000..4c59578
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEBlend.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEBlend_h
+#define FEBlend_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+
+#include "Filter.h"
+
+namespace WebCore {
+
+enum BlendModeType {
+ FEBLEND_MODE_UNKNOWN = 0,
+ FEBLEND_MODE_NORMAL = 1,
+ FEBLEND_MODE_MULTIPLY = 2,
+ FEBLEND_MODE_SCREEN = 3,
+ FEBLEND_MODE_DARKEN = 4,
+ FEBLEND_MODE_LIGHTEN = 5
+};
+
+class FEBlend : public FilterEffect {
+public:
+ static PassRefPtr<FEBlend> create(Filter*, BlendModeType);
+
+ BlendModeType blendMode() const;
+ void setBlendMode(BlendModeType);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEBlend(Filter*, BlendModeType);
+
+ BlendModeType m_mode;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEBlend_h
diff --git a/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp
new file mode 100644
index 0000000..e0b15d1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEColorMatrix.h"
+
+#include "Filter.h"
+#include "GraphicsContext.h"
+
+#include <wtf/ByteArray.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+FEColorMatrix::FEColorMatrix(Filter* filter, ColorMatrixType type, const Vector<float>& values)
+ : FilterEffect(filter)
+ , m_type(type)
+ , m_values(values)
+{
+}
+
+PassRefPtr<FEColorMatrix> FEColorMatrix::create(Filter* filter, ColorMatrixType type, const Vector<float>& values)
+{
+ return adoptRef(new FEColorMatrix(filter, type, values));
+}
+
+ColorMatrixType FEColorMatrix::type() const
+{
+ return m_type;
+}
+
+void FEColorMatrix::setType(ColorMatrixType type)
+{
+ m_type = type;
+}
+
+const Vector<float>& FEColorMatrix::values() const
+{
+ return m_values;
+}
+
+void FEColorMatrix::setValues(const Vector<float> &values)
+{
+ m_values = values;
+}
+
+inline void matrix(double& red, double& green, double& blue, double& alpha, const Vector<float>& values)
+{
+ double r = values[0] * red + values[1] * green + values[2] * blue + values[3] * alpha + values[4] * 255;
+ double g = values[5] * red + values[6] * green + values[7] * blue + values[8] * alpha + values[9] * 255;
+ double b = values[10] * red + values[11] * green + values[12] * blue + values[13] * alpha + values[14] * 255;
+ double a = values[15] * red + values[16] * green + values[17] * blue + values[18] * alpha + values[19] * 255;
+
+ red = r;
+ green = g;
+ blue = b;
+ alpha = a;
+}
+
+inline void saturate(double& red, double& green, double& blue, const float& s)
+{
+ double r = (0.213 + 0.787 * s) * red + (0.715 - 0.715 * s) * green + (0.072 - 0.072 * s) * blue;
+ double g = (0.213 - 0.213 * s) * red + (0.715 + 0.285 * s) * green + (0.072 - 0.072 * s) * blue;
+ double b = (0.213 - 0.213 * s) * red + (0.715 - 0.715 * s) * green + (0.072 + 0.928 * s) * blue;
+
+ red = r;
+ green = g;
+ blue = b;
+}
+
+inline void huerotate(double& red, double& green, double& blue, const float& hue)
+{
+ double cosHue = cos(hue * piDouble / 180);
+ double sinHue = sin(hue * piDouble / 180);
+ double r = red * (0.213 + cosHue * 0.787 - sinHue * 0.213) +
+ green * (0.715 - cosHue * 0.715 - sinHue * 0.715) +
+ blue * (0.072 - cosHue * 0.072 + sinHue * 0.928);
+ double g = red * (0.213 - cosHue * 0.213 + sinHue * 0.143) +
+ green * (0.715 + cosHue * 0.285 + sinHue * 0.140) +
+ blue * (0.072 - cosHue * 0.072 - sinHue * 0.283);
+ double b = red * (0.213 - cosHue * 0.213 - sinHue * 0.787) +
+ green * (0.715 - cosHue * 0.715 + sinHue * 0.715) +
+ blue * (0.072 + cosHue * 0.928 + sinHue * 0.072);
+
+ red = r;
+ green = g;
+ blue = b;
+}
+
+inline void luminance(double& red, double& green, double& blue, double& alpha)
+{
+ alpha = 0.2125 * red + 0.7154 * green + 0.0721 * blue;
+ red = 0;
+ green = 0;
+ blue = 0;
+}
+
+template<ColorMatrixType filterType>
+void effectType(ByteArray* pixelArray, const Vector<float>& values)
+{
+ unsigned pixelArrayLength = pixelArray->length();
+ for (unsigned pixelByteOffset = 0; pixelByteOffset < pixelArrayLength; pixelByteOffset += 4) {
+ double red = pixelArray->get(pixelByteOffset);
+ double green = pixelArray->get(pixelByteOffset + 1);
+ double blue = pixelArray->get(pixelByteOffset + 2);
+ double alpha = pixelArray->get(pixelByteOffset + 3);
+
+ switch (filterType) {
+ case FECOLORMATRIX_TYPE_MATRIX:
+ matrix(red, green, blue, alpha, values);
+ break;
+ case FECOLORMATRIX_TYPE_SATURATE:
+ saturate(red, green, blue, values[0]);
+ break;
+ case FECOLORMATRIX_TYPE_HUEROTATE:
+ huerotate(red, green, blue, values[0]);
+ break;
+ case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
+ luminance(red, green, blue, alpha);
+ break;
+ }
+
+ pixelArray->set(pixelByteOffset, red);
+ pixelArray->set(pixelByteOffset + 1, green);
+ pixelArray->set(pixelByteOffset + 2, blue);
+ pixelArray->set(pixelByteOffset + 3, alpha);
+ }
+}
+
+void FEColorMatrix::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ in->apply();
+ if (!in->hasResult())
+ return;
+
+ ImageBuffer* resultImage = createImageBufferResult();
+ if (!resultImage)
+ return;
+
+ resultImage->context()->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+
+ IntRect imageRect(IntPoint(), absolutePaintRect().size());
+ RefPtr<ByteArray> pixelArray = resultImage->getUnmultipliedImageData(imageRect);
+
+ switch (m_type) {
+ case FECOLORMATRIX_TYPE_UNKNOWN:
+ break;
+ case FECOLORMATRIX_TYPE_MATRIX:
+ effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), m_values);
+ break;
+ case FECOLORMATRIX_TYPE_SATURATE:
+ effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), m_values);
+ break;
+ case FECOLORMATRIX_TYPE_HUEROTATE:
+ effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), m_values);
+ break;
+ case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
+ effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), m_values);
+ setIsAlphaImage(true);
+ break;
+ }
+
+ resultImage->putUnmultipliedImageData(pixelArray.get(), imageRect.size(), imageRect, IntPoint());
+}
+
+void FEColorMatrix::dump()
+{
+}
+
+static TextStream& operator<<(TextStream& ts, const ColorMatrixType& type)
+{
+ switch (type) {
+ case FECOLORMATRIX_TYPE_UNKNOWN:
+ ts << "UNKNOWN";
+ break;
+ case FECOLORMATRIX_TYPE_MATRIX:
+ ts << "MATRIX";
+ break;
+ case FECOLORMATRIX_TYPE_SATURATE:
+ ts << "SATURATE";
+ break;
+ case FECOLORMATRIX_TYPE_HUEROTATE:
+ ts << "HUEROTATE";
+ break;
+ case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
+ ts << "LUMINANCETOALPHA";
+ break;
+ }
+ return ts;
+}
+
+TextStream& FEColorMatrix::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feColorMatrix";
+ FilterEffect::externalRepresentation(ts);
+ ts << " type=\"" << m_type << "\"";
+ if (!m_values.isEmpty()) {
+ ts << " values=\"";
+ Vector<float>::const_iterator ptr = m_values.begin();
+ const Vector<float>::const_iterator end = m_values.end();
+ while (ptr < end) {
+ ts << *ptr;
+ ++ptr;
+ if (ptr < end)
+ ts << " ";
+ }
+ ts << "\"";
+ }
+ ts << "]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEColorMatrix.h b/Source/WebCore/platform/graphics/filters/FEColorMatrix.h
new file mode 100644
index 0000000..a3ced7e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEColorMatrix.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEColorMatrix_h
+#define FEColorMatrix_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+
+#include "Filter.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+enum ColorMatrixType {
+ FECOLORMATRIX_TYPE_UNKNOWN = 0,
+ FECOLORMATRIX_TYPE_MATRIX = 1,
+ FECOLORMATRIX_TYPE_SATURATE = 2,
+ FECOLORMATRIX_TYPE_HUEROTATE = 3,
+ FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4
+};
+
+class FEColorMatrix : public FilterEffect {
+public:
+ static PassRefPtr<FEColorMatrix> create(Filter*, ColorMatrixType, const Vector<float>&);
+
+ ColorMatrixType type() const;
+ void setType(ColorMatrixType);
+
+ const Vector<float>& values() const;
+ void setValues(const Vector<float>&);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEColorMatrix(Filter*, ColorMatrixType, const Vector<float>&);
+
+ ColorMatrixType m_type;
+ Vector<float> m_values;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEColorMatrix_h
diff --git a/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
new file mode 100644
index 0000000..ca8e5d3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEComponentTransfer.h"
+
+#include "Filter.h"
+#include "GraphicsContext.h"
+
+#include <wtf/ByteArray.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+typedef void (*TransferType)(unsigned char*, const ComponentTransferFunction&);
+
+FEComponentTransfer::FEComponentTransfer(Filter* filter, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc,
+ const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc)
+ : FilterEffect(filter)
+ , m_redFunc(redFunc)
+ , m_greenFunc(greenFunc)
+ , m_blueFunc(blueFunc)
+ , m_alphaFunc(alphaFunc)
+{
+}
+
+PassRefPtr<FEComponentTransfer> FEComponentTransfer::create(Filter* filter, const ComponentTransferFunction& redFunc,
+ const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc)
+{
+ return adoptRef(new FEComponentTransfer(filter, redFunc, greenFunc, blueFunc, alphaFunc));
+}
+
+ComponentTransferFunction FEComponentTransfer::redFunction() const
+{
+ return m_redFunc;
+}
+
+void FEComponentTransfer::setRedFunction(const ComponentTransferFunction& func)
+{
+ m_redFunc = func;
+}
+
+ComponentTransferFunction FEComponentTransfer::greenFunction() const
+{
+ return m_greenFunc;
+}
+
+void FEComponentTransfer::setGreenFunction(const ComponentTransferFunction& func)
+{
+ m_greenFunc = func;
+}
+
+ComponentTransferFunction FEComponentTransfer::blueFunction() const
+{
+ return m_blueFunc;
+}
+
+void FEComponentTransfer::setBlueFunction(const ComponentTransferFunction& func)
+{
+ m_blueFunc = func;
+}
+
+ComponentTransferFunction FEComponentTransfer::alphaFunction() const
+{
+ return m_alphaFunc;
+}
+
+void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func)
+{
+ m_alphaFunc = func;
+}
+
+static void identity(unsigned char*, const ComponentTransferFunction&)
+{
+}
+
+static void table(unsigned char* values, const ComponentTransferFunction& transferFunction)
+{
+ const Vector<float>& tableValues = transferFunction.tableValues;
+ unsigned n = tableValues.size();
+ if (n < 1)
+ return;
+ for (unsigned i = 0; i < 256; ++i) {
+ double c = i / 255.0;
+ unsigned k = static_cast<unsigned>(c * (n - 1));
+ double v1 = tableValues[k];
+ double v2 = tableValues[std::min((k + 1), (n - 1))];
+ double val = 255.0 * (v1 + (c * (n - 1) - k) * (v2 - v1));
+ val = std::max(0.0, std::min(255.0, val));
+ values[i] = static_cast<unsigned char>(val);
+ }
+}
+
+static void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction)
+{
+ const Vector<float>& tableValues = transferFunction.tableValues;
+ unsigned n = tableValues.size();
+ if (n < 1)
+ return;
+ for (unsigned i = 0; i < 256; ++i) {
+ unsigned k = static_cast<unsigned>((i * n) / 255.0);
+ k = std::min(k, n - 1);
+ double val = 255 * tableValues[k];
+ val = std::max(0.0, std::min(255.0, val));
+ values[i] = static_cast<unsigned char>(val);
+ }
+}
+
+static void linear(unsigned char* values, const ComponentTransferFunction& transferFunction)
+{
+ for (unsigned i = 0; i < 256; ++i) {
+ double val = transferFunction.slope * i + 255 * transferFunction.intercept;
+ val = std::max(0.0, std::min(255.0, val));
+ values[i] = static_cast<unsigned char>(val);
+ }
+}
+
+static void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction)
+{
+ for (unsigned i = 0; i < 256; ++i) {
+ double exponent = transferFunction.exponent; // RCVT doesn't like passing a double and a float to pow, so promote this to double
+ double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), exponent) + transferFunction.offset);
+ val = std::max(0.0, std::min(255.0, val));
+ values[i] = static_cast<unsigned char>(val);
+ }
+}
+
+void FEComponentTransfer::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ in->apply();
+ if (!in->hasResult())
+ return;
+
+ ByteArray* pixelArray = createUnmultipliedImageResult();
+ if (!pixelArray)
+ return;
+
+ unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
+ for (unsigned i = 0; i < 256; ++i)
+ rValues[i] = gValues[i] = bValues[i] = aValues[i] = i;
+ unsigned char* tables[] = { rValues, gValues, bValues, aValues };
+ ComponentTransferFunction transferFunction[] = {m_redFunc, m_greenFunc, m_blueFunc, m_alphaFunc};
+ TransferType callEffect[] = {identity, identity, table, discrete, linear, gamma};
+
+ for (unsigned channel = 0; channel < 4; channel++)
+ (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]);
+
+ IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
+ in->copyUnmultipliedImage(pixelArray, drawingRect);
+
+ unsigned pixelArrayLength = pixelArray->length();
+ for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
+ for (unsigned channel = 0; channel < 4; ++channel) {
+ unsigned char c = pixelArray->get(pixelOffset + channel);
+ pixelArray->set(pixelOffset + channel, tables[channel][c]);
+ }
+ }
+}
+
+void FEComponentTransfer::dump()
+{
+}
+
+static TextStream& operator<<(TextStream& ts, const ComponentTransferType& type)
+{
+ switch (type) {
+ case FECOMPONENTTRANSFER_TYPE_UNKNOWN:
+ ts << "UNKNOWN";
+ break;
+ case FECOMPONENTTRANSFER_TYPE_IDENTITY:
+ ts << "IDENTITY";
+ break;
+ case FECOMPONENTTRANSFER_TYPE_TABLE:
+ ts << "TABLE";
+ break;
+ case FECOMPONENTTRANSFER_TYPE_DISCRETE:
+ ts << "DISCRETE";
+ break;
+ case FECOMPONENTTRANSFER_TYPE_LINEAR:
+ ts << "LINEAR";
+ break;
+ case FECOMPONENTTRANSFER_TYPE_GAMMA:
+ ts << "GAMMA";
+ break;
+ }
+ return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const ComponentTransferFunction& function)
+{
+ ts << "type=\"" << function.type
+ << "\" slope=\"" << function.slope
+ << "\" intercept=\"" << function.intercept
+ << "\" amplitude=\"" << function.amplitude
+ << "\" exponent=\"" << function.exponent
+ << "\" offset=\"" << function.offset << "\"";
+ return ts;
+}
+
+TextStream& FEComponentTransfer::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feComponentTransfer";
+ FilterEffect::externalRepresentation(ts);
+ ts << " \n";
+ writeIndent(ts, indent + 2);
+ ts << "{red: " << m_redFunc << "}\n";
+ writeIndent(ts, indent + 2);
+ ts << "{green: " << m_greenFunc << "}\n";
+ writeIndent(ts, indent + 2);
+ ts << "{blue: " << m_blueFunc << "}\n";
+ writeIndent(ts, indent + 2);
+ ts << "{alpha: " << m_alphaFunc << "}]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEComponentTransfer.h b/Source/WebCore/platform/graphics/filters/FEComponentTransfer.h
new file mode 100644
index 0000000..bbe3ebb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEComponentTransfer.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEComponentTransfer_h
+#define FEComponentTransfer_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+
+#include "Filter.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+enum ComponentTransferType {
+ FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0,
+ FECOMPONENTTRANSFER_TYPE_IDENTITY = 1,
+ FECOMPONENTTRANSFER_TYPE_TABLE = 2,
+ FECOMPONENTTRANSFER_TYPE_DISCRETE = 3,
+ FECOMPONENTTRANSFER_TYPE_LINEAR = 4,
+ FECOMPONENTTRANSFER_TYPE_GAMMA = 5
+};
+
+struct ComponentTransferFunction {
+ ComponentTransferFunction()
+ : type(FECOMPONENTTRANSFER_TYPE_UNKNOWN)
+ , slope(0)
+ , intercept(0)
+ , amplitude(0)
+ , exponent(0)
+ , offset(0)
+ {
+ }
+
+ ComponentTransferType type;
+
+ float slope;
+ float intercept;
+ float amplitude;
+ float exponent;
+ float offset;
+
+ Vector<float> tableValues;
+};
+
+class FEComponentTransfer : public FilterEffect {
+public:
+ static PassRefPtr<FEComponentTransfer> create(Filter*, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc,
+ const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc);
+
+ ComponentTransferFunction redFunction() const;
+ void setRedFunction(const ComponentTransferFunction&);
+
+ ComponentTransferFunction greenFunction() const;
+ void setGreenFunction(const ComponentTransferFunction&);
+
+ ComponentTransferFunction blueFunction() const;
+ void setBlueFunction(const ComponentTransferFunction&);
+
+ ComponentTransferFunction alphaFunction() const;
+ void setAlphaFunction(const ComponentTransferFunction&);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEComponentTransfer(Filter*, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc,
+ const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc);
+
+ ComponentTransferFunction m_redFunc;
+ ComponentTransferFunction m_greenFunc;
+ ComponentTransferFunction m_blueFunc;
+ ComponentTransferFunction m_alphaFunc;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEComponentTransfer_h
diff --git a/Source/WebCore/platform/graphics/filters/FEComposite.cpp b/Source/WebCore/platform/graphics/filters/FEComposite.cpp
new file mode 100644
index 0000000..80cb2b2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEComposite.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEComposite.h"
+
+#include "Filter.h"
+#include "GraphicsContext.h"
+
+#include <wtf/ByteArray.h>
+
+namespace WebCore {
+
+FEComposite::FEComposite(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
+ : FilterEffect(filter)
+ , m_type(type)
+ , m_k1(k1)
+ , m_k2(k2)
+ , m_k3(k3)
+ , m_k4(k4)
+{
+}
+
+PassRefPtr<FEComposite> FEComposite::create(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
+{
+ return adoptRef(new FEComposite(filter, type, k1, k2, k3, k4));
+}
+
+CompositeOperationType FEComposite::operation() const
+{
+ return m_type;
+}
+
+void FEComposite::setOperation(CompositeOperationType type)
+{
+ m_type = type;
+}
+
+float FEComposite::k1() const
+{
+ return m_k1;
+}
+
+void FEComposite::setK1(float k1)
+{
+ m_k1 = k1;
+}
+
+float FEComposite::k2() const
+{
+ return m_k2;
+}
+
+void FEComposite::setK2(float k2)
+{
+ m_k2 = k2;
+}
+
+float FEComposite::k3() const
+{
+ return m_k3;
+}
+
+void FEComposite::setK3(float k3)
+{
+ m_k3 = k3;
+}
+
+float FEComposite::k4() const
+{
+ return m_k4;
+}
+
+void FEComposite::setK4(float k4)
+{
+ m_k4 = k4;
+}
+
+template <int b1, int b2, int b3, int b4>
+inline void computeArithmeticPixels(unsigned char* source, unsigned char* destination, int pixelArrayLength,
+ float k1, float k2, float k3, float k4)
+{
+ float scaledK4;
+ float scaledK1;
+ if (b1)
+ scaledK1 = k1 / 255.f;
+ if (b4)
+ scaledK4 = k4 * 255.f;
+
+ while (--pixelArrayLength >= 0) {
+ unsigned char i1 = *source;
+ unsigned char i2 = *destination;
+ float result = 0;
+ if (b1)
+ result += scaledK1 * i1 * i2;
+ if (b2)
+ result += k2 * i1;
+ if (b3)
+ result += k3 * i2;
+ if (b4)
+ result += scaledK4;
+
+ if (result <= 0)
+ *destination = 0;
+ else if (result >= 255)
+ *destination = 255;
+ else
+ *destination = result;
+ ++source;
+ ++destination;
+ }
+}
+
+inline void arithmetic(ByteArray* srcPixelArrayA, ByteArray* srcPixelArrayB,
+ float k1, float k2, float k3, float k4)
+{
+ int pixelArrayLength = srcPixelArrayA->length();
+ ASSERT(pixelArrayLength == static_cast<int>(srcPixelArrayB->length()));
+ unsigned char* source = srcPixelArrayA->data();
+ unsigned char* destination = srcPixelArrayB->data();
+
+ if (!k4) {
+ if (!k1) {
+ computeArithmeticPixels<0, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
+ return;
+ }
+
+ computeArithmeticPixels<1, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
+ return;
+ }
+
+ if (!k1) {
+ computeArithmeticPixels<0, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
+ return;
+ }
+ computeArithmeticPixels<1, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
+}
+
+void FEComposite::determineAbsolutePaintRect()
+{
+ switch (m_type) {
+ case FECOMPOSITE_OPERATOR_IN:
+ case FECOMPOSITE_OPERATOR_ATOP:
+ // For In and Atop the first effect just influences the result of
+ // the second effect. So just use the absolute paint rect of the second effect here.
+ setAbsolutePaintRect(inputEffect(1)->absolutePaintRect());
+ return;
+ case FECOMPOSITE_OPERATOR_ARITHMETIC:
+ // Arithmetic may influnce the compele filter primitive region. So we can't
+ // optimize the paint region here.
+ setAbsolutePaintRect(maxEffectRect());
+ return;
+ default:
+ // Take the union of both input effects.
+ FilterEffect::determineAbsolutePaintRect();
+ return;
+ }
+}
+
+void FEComposite::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ FilterEffect* in2 = inputEffect(1);
+ in->apply();
+ in2->apply();
+ if (!in->hasResult() || !in2->hasResult())
+ return;
+
+ if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) {
+ ByteArray* dstPixelArray = createPremultipliedImageResult();
+ if (!dstPixelArray)
+ return;
+
+ IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
+ RefPtr<ByteArray> srcPixelArray = in->asPremultipliedImage(effectADrawingRect);
+
+ IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
+ in2->copyPremultipliedImage(dstPixelArray, effectBDrawingRect);
+
+ arithmetic(srcPixelArray.get(), dstPixelArray, m_k1, m_k2, m_k3, m_k4);
+ return;
+ }
+
+ ImageBuffer* resultImage = createImageBufferResult();
+ if (!resultImage)
+ return;
+ GraphicsContext* filterContext = resultImage->context();
+
+ FloatRect srcRect = FloatRect(0, 0, -1, -1);
+ switch (m_type) {
+ case FECOMPOSITE_OPERATOR_OVER:
+ filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
+ filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+ break;
+ case FECOMPOSITE_OPERATOR_IN:
+ filterContext->save();
+ filterContext->clipToImageBuffer(in2->asImageBuffer(), drawingRegionOfInputImage(in2->absolutePaintRect()));
+ filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+ filterContext->restore();
+ break;
+ case FECOMPOSITE_OPERATOR_OUT:
+ filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+ filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut);
+ break;
+ case FECOMPOSITE_OPERATOR_ATOP:
+ filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
+ filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop);
+ break;
+ case FECOMPOSITE_OPERATOR_XOR:
+ filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
+ filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR);
+ break;
+ default:
+ break;
+ }
+}
+
+void FEComposite::dump()
+{
+}
+
+static TextStream& operator<<(TextStream& ts, const CompositeOperationType& type)
+{
+ switch (type) {
+ case FECOMPOSITE_OPERATOR_UNKNOWN:
+ ts << "UNKNOWN";
+ break;
+ case FECOMPOSITE_OPERATOR_OVER:
+ ts << "OVER";
+ break;
+ case FECOMPOSITE_OPERATOR_IN:
+ ts << "IN";
+ break;
+ case FECOMPOSITE_OPERATOR_OUT:
+ ts << "OUT";
+ break;
+ case FECOMPOSITE_OPERATOR_ATOP:
+ ts << "ATOP";
+ break;
+ case FECOMPOSITE_OPERATOR_XOR:
+ ts << "XOR";
+ break;
+ case FECOMPOSITE_OPERATOR_ARITHMETIC:
+ ts << "ARITHMETIC";
+ break;
+ }
+ return ts;
+}
+
+TextStream& FEComposite::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feComposite";
+ FilterEffect::externalRepresentation(ts);
+ ts << " operation=\"" << m_type << "\"";
+ if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC)
+ ts << " k1=\"" << m_k1 << "\" k2=\"" << m_k2 << "\" k3=\"" << m_k3 << "\" k4=\"" << m_k4 << "\"";
+ ts << "]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ inputEffect(1)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEComposite.h b/Source/WebCore/platform/graphics/filters/FEComposite.h
new file mode 100644
index 0000000..b846902
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEComposite.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEComposite_h
+#define FEComposite_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+
+#include "PlatformString.h"
+#include "Filter.h"
+
+namespace WebCore {
+
+enum CompositeOperationType {
+ FECOMPOSITE_OPERATOR_UNKNOWN = 0,
+ FECOMPOSITE_OPERATOR_OVER = 1,
+ FECOMPOSITE_OPERATOR_IN = 2,
+ FECOMPOSITE_OPERATOR_OUT = 3,
+ FECOMPOSITE_OPERATOR_ATOP = 4,
+ FECOMPOSITE_OPERATOR_XOR = 5,
+ FECOMPOSITE_OPERATOR_ARITHMETIC = 6
+};
+
+class FEComposite : public FilterEffect {
+public:
+ static PassRefPtr<FEComposite> create(Filter*, const CompositeOperationType&, float, float, float, float);
+
+ CompositeOperationType operation() const;
+ void setOperation(CompositeOperationType);
+
+ float k1() const;
+ void setK1(float);
+
+ float k2() const;
+ void setK2(float);
+
+ float k3() const;
+ void setK3(float);
+
+ float k4() const;
+ void setK4(float);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEComposite(Filter*, const CompositeOperationType&, float, float, float, float);
+
+ CompositeOperationType m_type;
+ float m_k1;
+ float m_k2;
+ float m_k3;
+ float m_k4;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEComposite_h
diff --git a/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp b/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp
new file mode 100644
index 0000000..b8f8aea
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEConvolveMatrix.h"
+
+#include "Filter.h"
+
+#include <wtf/ByteArray.h>
+
+namespace WebCore {
+
+FEConvolveMatrix::FEConvolveMatrix(Filter* filter, const IntSize& kernelSize,
+ float divisor, float bias, const IntPoint& targetOffset, EdgeModeType edgeMode,
+ const FloatPoint& kernelUnitLength, bool preserveAlpha, const Vector<float>& kernelMatrix)
+ : FilterEffect(filter)
+ , m_kernelSize(kernelSize)
+ , m_divisor(divisor)
+ , m_bias(bias)
+ , m_targetOffset(targetOffset)
+ , m_edgeMode(edgeMode)
+ , m_kernelUnitLength(kernelUnitLength)
+ , m_preserveAlpha(preserveAlpha)
+ , m_kernelMatrix(kernelMatrix)
+{
+}
+
+PassRefPtr<FEConvolveMatrix> FEConvolveMatrix::create(Filter* filter, const IntSize& kernelSize,
+ float divisor, float bias, const IntPoint& targetOffset, EdgeModeType edgeMode,
+ const FloatPoint& kernelUnitLength, bool preserveAlpha, const Vector<float>& kernelMatrix)
+{
+ return adoptRef(new FEConvolveMatrix(filter, kernelSize, divisor, bias, targetOffset, edgeMode, kernelUnitLength,
+ preserveAlpha, kernelMatrix));
+}
+
+
+IntSize FEConvolveMatrix::kernelSize() const
+{
+ return m_kernelSize;
+}
+
+void FEConvolveMatrix::setKernelSize(IntSize kernelSize)
+{
+ m_kernelSize = kernelSize;
+}
+
+const Vector<float>& FEConvolveMatrix::kernel() const
+{
+ return m_kernelMatrix;
+}
+
+void FEConvolveMatrix::setKernel(const Vector<float>& kernel)
+{
+ m_kernelMatrix = kernel;
+}
+
+float FEConvolveMatrix::divisor() const
+{
+ return m_divisor;
+}
+
+void FEConvolveMatrix::setDivisor(float divisor)
+{
+ m_divisor = divisor;
+}
+
+float FEConvolveMatrix::bias() const
+{
+ return m_bias;
+}
+
+void FEConvolveMatrix::setBias(float bias)
+{
+ m_bias = bias;
+}
+
+IntPoint FEConvolveMatrix::targetOffset() const
+{
+ return m_targetOffset;
+}
+
+void FEConvolveMatrix::setTargetOffset(IntPoint targetOffset)
+{
+ m_targetOffset = targetOffset;
+}
+
+EdgeModeType FEConvolveMatrix::edgeMode() const
+{
+ return m_edgeMode;
+}
+
+void FEConvolveMatrix::setEdgeMode(EdgeModeType edgeMode)
+{
+ m_edgeMode = edgeMode;
+}
+
+FloatPoint FEConvolveMatrix::kernelUnitLength() const
+{
+ return m_kernelUnitLength;
+}
+
+void FEConvolveMatrix::setKernelUnitLength(FloatPoint kernelUnitLength)
+{
+ m_kernelUnitLength = kernelUnitLength;
+}
+
+bool FEConvolveMatrix::preserveAlpha() const
+{
+ return m_preserveAlpha;
+}
+
+void FEConvolveMatrix::setPreserveAlpha(bool preserveAlpha)
+{
+ m_preserveAlpha = preserveAlpha;
+}
+
+/*
+ -----------------------------------
+ ConvolveMatrix implementation
+ -----------------------------------
+
+ The image rectangle is split in the following way:
+
+ +---------------------+
+ | A |
+ +---------------------+
+ | | | |
+ | B | C | D |
+ | | | |
+ +---------------------+
+ | E |
+ +---------------------+
+
+ Where region C contains those pixels, whose values
+ can be calculated without crossing the edge of the rectangle.
+
+ Example:
+ Image size: width: 10, height: 10
+
+ Order (kernel matrix size): width: 3, height 4
+ Target: x:1, y:3
+
+ The following figure shows the target inside the kernel matrix:
+
+ ...
+ ...
+ ...
+ .X.
+
+ The regions in this case are the following:
+ Note: (x1, y1) top-left and (x2, y2) is the bottom-right corner
+ Note: row x2 and column y2 is not part of the region
+ only those (x, y) pixels, where x1 <= x < x2 and y1 <= y < y2
+
+ Region A: x1: 0, y1: 0, x2: 10, y2: 3
+ Region B: x1: 0, y1: 3, x2: 1, y2: 10
+ Region C: x1: 1, y1: 3, x2: 9, y2: 10
+ Region D: x1: 9, y1: 3, x2: 10, y2: 10
+ Region E: x1: 0, y1: 10, x2: 10, y2: 10 (empty region)
+
+ Since region C (often) contains most of the pixels, we implemented
+ a fast algoritm to calculate these values, called fastSetInteriorPixels.
+ For other regions, fastSetOuterPixels is used, which calls getPixelValue,
+ to handle pixels outside of the image. In a rare situations, when
+ kernel matrix is bigger than the image, all pixels are calculated by this
+ function.
+
+ Although these two functions have lot in common, I decided not to make
+ common a template for them, since there are key differences as well,
+ and would make it really hard to understand.
+*/
+
+static ALWAYS_INLINE unsigned char clampRGBAValue(float channel, unsigned char max = 255)
+{
+ if (channel <= 0)
+ return 0;
+ if (channel >= max)
+ return max;
+ return channel;
+}
+
+template<bool preserveAlphaValues>
+ALWAYS_INLINE void setDestinationPixels(ByteArray* image, int& pixel, float* totals, float divisor, float bias, ByteArray* src)
+{
+ unsigned char maxAlpha = preserveAlphaValues ? 255 : clampRGBAValue(totals[3] / divisor + bias);
+ for (int i = 0; i < 3; ++i)
+ image->set(pixel++, clampRGBAValue(totals[i] / divisor + bias, maxAlpha));
+
+ if (preserveAlphaValues) {
+ image->set(pixel, src->get(pixel));
+ ++pixel;
+ } else
+ image->set(pixel++, maxAlpha);
+}
+
+// Only for region C
+template<bool preserveAlphaValues>
+ALWAYS_INLINE void FEConvolveMatrix::fastSetInteriorPixels(PaintingData& paintingData, int clipRight, int clipBottom)
+{
+ // edge mode does not affect these pixels
+ int pixel = (m_targetOffset.y() * paintingData.width + m_targetOffset.x()) * 4;
+ int startKernelPixel = 0;
+ int kernelIncrease = clipRight * 4;
+ int xIncrease = (m_kernelSize.width() - 1) * 4;
+ // Contains the sum of rgb(a) components
+ float totals[3 + (preserveAlphaValues ? 0 : 1)];
+
+ // m_divisor cannot be 0, SVGFEConvolveMatrixElement ensures this
+ ASSERT(m_divisor);
+
+ for (int y = clipBottom + 1; y > 0; --y) {
+ for (int x = clipRight + 1; x > 0; --x) {
+ int kernelValue = m_kernelMatrix.size() - 1;
+ int kernelPixel = startKernelPixel;
+ int width = m_kernelSize.width();
+
+ totals[0] = 0;
+ totals[1] = 0;
+ totals[2] = 0;
+ if (!preserveAlphaValues)
+ totals[3] = 0;
+
+ while (kernelValue >= 0) {
+ totals[0] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel++));
+ totals[1] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel++));
+ totals[2] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel++));
+ if (!preserveAlphaValues)
+ totals[3] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel));
+ ++kernelPixel;
+ --kernelValue;
+ if (!--width) {
+ kernelPixel += kernelIncrease;
+ width = m_kernelSize.width();
+ }
+ }
+
+ setDestinationPixels<preserveAlphaValues>(paintingData.dstPixelArray, pixel, totals, m_divisor, paintingData.bias, paintingData.srcPixelArray);
+ startKernelPixel += 4;
+ }
+ pixel += xIncrease;
+ startKernelPixel += xIncrease;
+ }
+}
+
+ALWAYS_INLINE int FEConvolveMatrix::getPixelValue(PaintingData& paintingData, int x, int y)
+{
+ if (x >= 0 && x < paintingData.width && x >= 0 && y < paintingData.height)
+ return (y * paintingData.width + x) << 2;
+
+ switch (m_edgeMode) {
+ default: // EDGEMODE_NONE
+ return -1;
+ case EDGEMODE_DUPLICATE:
+ if (x < 0)
+ x = 0;
+ else if (x >= paintingData.width)
+ x = paintingData.width - 1;
+ if (y < 0)
+ y = 0;
+ else if (y >= paintingData.height)
+ y = paintingData.height - 1;
+ return (y * paintingData.width + x) << 2;
+ case EDGEMODE_WRAP:
+ while (x < 0)
+ x += paintingData.width;
+ x %= paintingData.width;
+ while (y < 0)
+ y += paintingData.height;
+ y %= paintingData.height;
+ return (y * paintingData.width + x) << 2;
+ }
+}
+
+// For other regions than C
+template<bool preserveAlphaValues>
+void FEConvolveMatrix::fastSetOuterPixels(PaintingData& paintingData, int x1, int y1, int x2, int y2)
+{
+ int pixel = (y1 * paintingData.width + x1) * 4;
+ int height = y2 - y1;
+ int width = x2 - x1;
+ int beginKernelPixelX = x1 - m_targetOffset.x();
+ int startKernelPixelX = beginKernelPixelX;
+ int startKernelPixelY = y1 - m_targetOffset.y();
+ int xIncrease = (paintingData.width - width) * 4;
+ // Contains the sum of rgb(a) components
+ float totals[3 + (preserveAlphaValues ? 0 : 1)];
+
+ // m_divisor cannot be 0, SVGFEConvolveMatrixElement ensures this
+ ASSERT(m_divisor);
+
+ for (int y = height; y > 0; --y) {
+ for (int x = width; x > 0; --x) {
+ int kernelValue = m_kernelMatrix.size() - 1;
+ int kernelPixelX = startKernelPixelX;
+ int kernelPixelY = startKernelPixelY;
+ int width = m_kernelSize.width();
+
+ totals[0] = 0;
+ totals[1] = 0;
+ totals[2] = 0;
+ if (!preserveAlphaValues)
+ totals[3] = 0;
+
+ while (kernelValue >= 0) {
+ int pixelIndex = getPixelValue(paintingData, kernelPixelX, kernelPixelY);
+ if (pixelIndex >= 0) {
+ totals[0] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex));
+ totals[1] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex + 1));
+ totals[2] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex + 2));
+ }
+ if (!preserveAlphaValues && pixelIndex >= 0)
+ totals[3] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex + 3));
+ ++kernelPixelX;
+ --kernelValue;
+ if (!--width) {
+ kernelPixelX = startKernelPixelX;
+ ++kernelPixelY;
+ width = m_kernelSize.width();
+ }
+ }
+
+ setDestinationPixels<preserveAlphaValues>(paintingData.dstPixelArray, pixel, totals, m_divisor, paintingData.bias, paintingData.srcPixelArray);
+ ++startKernelPixelX;
+ }
+ pixel += xIncrease;
+ startKernelPixelX = beginKernelPixelX;
+ ++startKernelPixelY;
+ }
+}
+
+ALWAYS_INLINE void FEConvolveMatrix::setInteriorPixels(PaintingData& paintingData, int clipRight, int clipBottom)
+{
+ // Must be implemented here, since it refers another ALWAYS_INLINE
+ // function, which defined in this C++ source file as well
+ if (m_preserveAlpha)
+ fastSetInteriorPixels<true>(paintingData, clipRight, clipBottom);
+ else
+ fastSetInteriorPixels<false>(paintingData, clipRight, clipBottom);
+}
+
+ALWAYS_INLINE void FEConvolveMatrix::setOuterPixels(PaintingData& paintingData, int x1, int y1, int x2, int y2)
+{
+ // Although this function can be moved to the header, it is implemented here
+ // because setInteriorPixels is also implemented here
+ if (m_preserveAlpha)
+ fastSetOuterPixels<true>(paintingData, x1, y1, x2, y2);
+ else
+ fastSetOuterPixels<false>(paintingData, x1, y1, x2, y2);
+}
+
+void FEConvolveMatrix::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ in->apply();
+ if (!in->hasResult())
+ return;
+
+ ByteArray* resultImage;
+ if (m_preserveAlpha)
+ resultImage = createUnmultipliedImageResult();
+ else
+ resultImage = createPremultipliedImageResult();
+ if (!resultImage)
+ return;
+
+ IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
+
+ RefPtr<ByteArray> srcPixelArray;
+ if (m_preserveAlpha)
+ srcPixelArray = in->asUnmultipliedImage(effectDrawingRect);
+ else
+ srcPixelArray = in->asPremultipliedImage(effectDrawingRect);
+
+ IntSize paintSize = absolutePaintRect().size();
+ PaintingData paintingData;
+ paintingData.srcPixelArray = srcPixelArray.get();
+ paintingData.dstPixelArray = resultImage;
+ paintingData.width = paintSize.width();
+ paintingData.height = paintSize.height();
+ paintingData.bias = m_bias * 255;
+
+ // Drawing fully covered pixels
+ int clipRight = paintSize.width() - m_kernelSize.width();
+ int clipBottom = paintSize.height() - m_kernelSize.height();
+
+ if (clipRight >= 0 && clipBottom >= 0) {
+ setInteriorPixels(paintingData, clipRight, clipBottom);
+
+ clipRight += m_targetOffset.x() + 1;
+ clipBottom += m_targetOffset.y() + 1;
+ if (m_targetOffset.y() > 0)
+ setOuterPixels(paintingData, 0, 0, paintSize.width(), m_targetOffset.y());
+ if (clipBottom < paintSize.height())
+ setOuterPixels(paintingData, 0, clipBottom, paintSize.width(), paintSize.height());
+ if (m_targetOffset.x() > 0)
+ setOuterPixels(paintingData, 0, m_targetOffset.y(), m_targetOffset.x(), clipBottom);
+ if (clipRight < paintSize.width())
+ setOuterPixels(paintingData, clipRight, m_targetOffset.y(), paintSize.width(), clipBottom);
+ } else {
+ // Rare situation, not optimizied for speed
+ setOuterPixels(paintingData, 0, 0, paintSize.width(), paintSize.height());
+ }
+}
+
+void FEConvolveMatrix::dump()
+{
+}
+
+static TextStream& operator<<(TextStream& ts, const EdgeModeType& type)
+{
+ switch (type) {
+ case EDGEMODE_UNKNOWN:
+ ts << "UNKNOWN";
+ break;
+ case EDGEMODE_DUPLICATE:
+ ts << "DUPLICATE";
+ break;
+ case EDGEMODE_WRAP:
+ ts << "WRAP";
+ break;
+ case EDGEMODE_NONE:
+ ts << "NONE";
+ break;
+ }
+ return ts;
+}
+
+TextStream& FEConvolveMatrix::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feConvolveMatrix";
+ FilterEffect::externalRepresentation(ts);
+ ts << " order=\"" << m_kernelSize << "\" "
+ << "kernelMatrix=\"" << m_kernelMatrix << "\" "
+ << "divisor=\"" << m_divisor << "\" "
+ << "bias=\"" << m_bias << "\" "
+ << "target=\"" << m_targetOffset << "\" "
+ << "edgeMode=\"" << m_edgeMode << "\" "
+ << "kernelUnitLength=\"" << m_kernelUnitLength << "\" "
+ << "preserveAlpha=\"" << m_preserveAlpha << "\"]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+}; // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h b/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h
new file mode 100644
index 0000000..05d1199
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEConvolveMatrix_h
+#define FEConvolveMatrix_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+#include "FloatPoint.h"
+#include "FloatSize.h"
+#include "Filter.h"
+#include <wtf/AlwaysInline.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+enum EdgeModeType {
+ EDGEMODE_UNKNOWN = 0,
+ EDGEMODE_DUPLICATE = 1,
+ EDGEMODE_WRAP = 2,
+ EDGEMODE_NONE = 3
+};
+
+class CanvasPixelArray;
+
+class FEConvolveMatrix : public FilterEffect {
+public:
+ static PassRefPtr<FEConvolveMatrix> create(Filter*, const IntSize&,
+ float, float, const IntPoint&, EdgeModeType, const FloatPoint&,
+ bool, const Vector<float>&);
+
+ IntSize kernelSize() const;
+ void setKernelSize(IntSize);
+
+ const Vector<float>& kernel() const;
+ void setKernel(const Vector<float>&);
+
+ float divisor() const;
+ void setDivisor(float);
+
+ float bias() const;
+ void setBias(float);
+
+ IntPoint targetOffset() const;
+ void setTargetOffset(IntPoint);
+
+ EdgeModeType edgeMode() const;
+ void setEdgeMode(EdgeModeType);
+
+ FloatPoint kernelUnitLength() const;
+ void setKernelUnitLength(FloatPoint);
+
+ bool preserveAlpha() const;
+ void setPreserveAlpha(bool);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(maxEffectRect()); }
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEConvolveMatrix(Filter*, const IntSize&, float, float,
+ const IntPoint&, EdgeModeType, const FloatPoint&, bool, const Vector<float>&);
+
+ struct PaintingData {
+ ByteArray* srcPixelArray;
+ ByteArray* dstPixelArray;
+ int width;
+ int height;
+ float bias;
+ };
+
+ template<bool preserveAlphaValues>
+ ALWAYS_INLINE void fastSetInteriorPixels(PaintingData&, int clipRight, int clipBottom);
+
+ ALWAYS_INLINE int getPixelValue(PaintingData&, int x, int y);
+
+ template<bool preserveAlphaValues>
+ void fastSetOuterPixels(PaintingData&, int x1, int y1, int x2, int y2);
+
+ // Wrapper functions
+ ALWAYS_INLINE void setInteriorPixels(PaintingData& paintingData, int clipRight, int clipBottom);
+ ALWAYS_INLINE void setOuterPixels(PaintingData& paintingData, int x1, int y1, int x2, int y2);
+
+ IntSize m_kernelSize;
+ float m_divisor;
+ float m_bias;
+ IntPoint m_targetOffset;
+ EdgeModeType m_edgeMode;
+ FloatPoint m_kernelUnitLength;
+ bool m_preserveAlpha;
+ Vector<float> m_kernelMatrix;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEConvolveMatrix_h
diff --git a/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp
new file mode 100644
index 0000000..14d57f4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEDiffuseLighting.h"
+
+#include "LightSource.h"
+
+namespace WebCore {
+
+FEDiffuseLighting::FEDiffuseLighting(Filter* filter, const Color& lightingColor, float surfaceScale,
+ float diffuseConstant, float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource)
+ : FELighting(filter, DiffuseLighting, lightingColor, surfaceScale, diffuseConstant, 0, 0, kernelUnitLengthX, kernelUnitLengthY, lightSource)
+{
+}
+
+PassRefPtr<FEDiffuseLighting> FEDiffuseLighting::create(Filter* filter, const Color& lightingColor,
+ float surfaceScale, float diffuseConstant, float kernelUnitLengthX,
+ float kernelUnitLengthY, PassRefPtr<LightSource> lightSource)
+{
+ return adoptRef(new FEDiffuseLighting(filter, lightingColor, surfaceScale, diffuseConstant, kernelUnitLengthX, kernelUnitLengthY, lightSource));
+}
+
+FEDiffuseLighting::~FEDiffuseLighting()
+{
+}
+
+Color FEDiffuseLighting::lightingColor() const
+{
+ return m_lightingColor;
+}
+
+void FEDiffuseLighting::setLightingColor(const Color& lightingColor)
+{
+ m_lightingColor = lightingColor;
+}
+
+float FEDiffuseLighting::surfaceScale() const
+{
+ return m_surfaceScale;
+}
+
+void FEDiffuseLighting::setSurfaceScale(float surfaceScale)
+{
+ m_surfaceScale = surfaceScale;
+}
+
+float FEDiffuseLighting::diffuseConstant() const
+{
+ return m_diffuseConstant;
+}
+
+void FEDiffuseLighting::setDiffuseConstant(float diffuseConstant)
+{
+ m_diffuseConstant = diffuseConstant;
+}
+
+float FEDiffuseLighting::kernelUnitLengthX() const
+{
+ return m_kernelUnitLengthX;
+}
+
+void FEDiffuseLighting::setKernelUnitLengthX(float kernelUnitLengthX)
+{
+ m_kernelUnitLengthX = kernelUnitLengthX;
+}
+
+float FEDiffuseLighting::kernelUnitLengthY() const
+{
+ return m_kernelUnitLengthY;
+}
+
+void FEDiffuseLighting::setKernelUnitLengthY(float kernelUnitLengthY)
+{
+ m_kernelUnitLengthY = kernelUnitLengthY;
+}
+
+const LightSource* FEDiffuseLighting::lightSource() const
+{
+ return m_lightSource.get();
+}
+
+void FEDiffuseLighting::setLightSource(PassRefPtr<LightSource> lightSource)
+{
+ m_lightSource = lightSource;
+}
+
+void FEDiffuseLighting::dump()
+{
+}
+
+TextStream& FEDiffuseLighting::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feDiffuseLighting";
+ FilterEffect::externalRepresentation(ts);
+ ts << " surfaceScale=\"" << m_surfaceScale << "\" "
+ << "diffuseConstant=\"" << m_diffuseConstant << "\" "
+ << "kernelUnitLength=\"" << m_kernelUnitLengthX << ", " << m_kernelUnitLengthY << "\"]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h
new file mode 100644
index 0000000..b58b47a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEDiffuseLighting_h
+#define FEDiffuseLighting_h
+
+#if ENABLE(FILTERS)
+#include "FELighting.h"
+
+namespace WebCore {
+
+class LightSource;
+
+class FEDiffuseLighting : public FELighting {
+public:
+ static PassRefPtr<FEDiffuseLighting> create(Filter*, const Color&, float, float,
+ float, float, PassRefPtr<LightSource>);
+ virtual ~FEDiffuseLighting();
+
+ Color lightingColor() const;
+ void setLightingColor(const Color&);
+
+ float surfaceScale() const;
+ void setSurfaceScale(float);
+
+ float diffuseConstant() const;
+ void setDiffuseConstant(float);
+
+ float kernelUnitLengthX() const;
+ void setKernelUnitLengthX(float);
+
+ float kernelUnitLengthY() const;
+ void setKernelUnitLengthY(float);
+
+ const LightSource* lightSource() const;
+ void setLightSource(PassRefPtr<LightSource>);
+
+ virtual void dump();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEDiffuseLighting(Filter*, const Color&, float, float, float, float, PassRefPtr<LightSource>);
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEDiffuseLighting_h
diff --git a/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp b/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp
new file mode 100644
index 0000000..b5151bf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEDisplacementMap.h"
+
+#include "Filter.h"
+#include "GraphicsContext.h"
+
+#include <wtf/ByteArray.h>
+
+namespace WebCore {
+
+FEDisplacementMap::FEDisplacementMap(Filter* filter, ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float scale)
+ : FilterEffect(filter)
+ , m_xChannelSelector(xChannelSelector)
+ , m_yChannelSelector(yChannelSelector)
+ , m_scale(scale)
+{
+}
+
+PassRefPtr<FEDisplacementMap> FEDisplacementMap::create(Filter* filter, ChannelSelectorType xChannelSelector,
+ ChannelSelectorType yChannelSelector, float scale)
+{
+ return adoptRef(new FEDisplacementMap(filter, xChannelSelector, yChannelSelector, scale));
+}
+
+ChannelSelectorType FEDisplacementMap::xChannelSelector() const
+{
+ return m_xChannelSelector;
+}
+
+void FEDisplacementMap::setXChannelSelector(const ChannelSelectorType xChannelSelector)
+{
+ m_xChannelSelector = xChannelSelector;
+}
+
+ChannelSelectorType FEDisplacementMap::yChannelSelector() const
+{
+ return m_yChannelSelector;
+}
+
+void FEDisplacementMap::setYChannelSelector(const ChannelSelectorType yChannelSelector)
+{
+ m_yChannelSelector = yChannelSelector;
+}
+
+float FEDisplacementMap::scale() const
+{
+ return m_scale;
+}
+
+void FEDisplacementMap::setScale(float scale)
+{
+ m_scale = scale;
+}
+
+void FEDisplacementMap::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ FilterEffect* in2 = inputEffect(1);
+ in->apply();
+ in2->apply();
+ if (!in->hasResult() || !in2->hasResult())
+ return;
+
+ if (m_xChannelSelector == CHANNEL_UNKNOWN || m_yChannelSelector == CHANNEL_UNKNOWN)
+ return;
+
+ ByteArray* dstPixelArray = createPremultipliedImageResult();
+ if (!dstPixelArray)
+ return;
+
+ IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
+ RefPtr<ByteArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect);
+
+ IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
+ RefPtr<ByteArray> srcPixelArrayB = in2->asUnmultipliedImage(effectBDrawingRect);
+
+ ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length());
+
+ Filter* filter = this->filter();
+ IntSize paintSize = absolutePaintRect().size();
+ float scaleX = filter->applyHorizontalScale(m_scale / 255);
+ float scaleY = filter->applyVerticalScale(m_scale / 255);
+ float scaleAdjustmentX = filter->applyHorizontalScale(0.5f - 0.5f * m_scale);
+ float scaleAdjustmentY = filter->applyVerticalScale(0.5f - 0.5f * m_scale);
+ int stride = paintSize.width() * 4;
+ for (int y = 0; y < paintSize.height(); ++y) {
+ int line = y * stride;
+ for (int x = 0; x < paintSize.width(); ++x) {
+ int dstIndex = line + x * 4;
+ int srcX = x + static_cast<int>(scaleX * srcPixelArrayB->get(dstIndex + m_xChannelSelector - 1) + scaleAdjustmentX);
+ int srcY = y + static_cast<int>(scaleY * srcPixelArrayB->get(dstIndex + m_yChannelSelector - 1) + scaleAdjustmentY);
+ for (unsigned channel = 0; channel < 4; ++channel) {
+ if (srcX < 0 || srcX >= paintSize.width() || srcY < 0 || srcY >= paintSize.height())
+ dstPixelArray->set(dstIndex + channel, static_cast<unsigned char>(0));
+ else {
+ unsigned char pixelValue = srcPixelArrayA->get(srcY * stride + srcX * 4 + channel);
+ dstPixelArray->set(dstIndex + channel, pixelValue);
+ }
+ }
+ }
+ }
+}
+
+void FEDisplacementMap::dump()
+{
+}
+
+static TextStream& operator<<(TextStream& ts, const ChannelSelectorType& type)
+{
+ switch (type) {
+ case CHANNEL_UNKNOWN:
+ ts << "UNKNOWN";
+ break;
+ case CHANNEL_R:
+ ts << "RED";
+ break;
+ case CHANNEL_G:
+ ts << "GREEN";
+ break;
+ case CHANNEL_B:
+ ts << "BLUE";
+ break;
+ case CHANNEL_A:
+ ts << "ALPHA";
+ break;
+ }
+ return ts;
+}
+
+TextStream& FEDisplacementMap::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feDisplacementMap";
+ FilterEffect::externalRepresentation(ts);
+ ts << " scale=\"" << m_scale << "\" "
+ << "xChannelSelector=\"" << m_xChannelSelector << "\" "
+ << "yChannelSelector=\"" << m_yChannelSelector << "\"]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ inputEffect(1)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h b/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h
new file mode 100644
index 0000000..ffb8f0e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEDisplacementMap_h
+#define FEDisplacementMap_h
+
+#if ENABLE(FILTERS)
+#include "PlatformString.h"
+#include "FilterEffect.h"
+#include "Filter.h"
+
+namespace WebCore {
+
+enum ChannelSelectorType {
+ CHANNEL_UNKNOWN = 0,
+ CHANNEL_R = 1,
+ CHANNEL_G = 2,
+ CHANNEL_B = 3,
+ CHANNEL_A = 4
+};
+
+class FEDisplacementMap : public FilterEffect {
+public:
+ static PassRefPtr<FEDisplacementMap> create(Filter*, ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float);
+
+ ChannelSelectorType xChannelSelector() const;
+ void setXChannelSelector(const ChannelSelectorType);
+
+ ChannelSelectorType yChannelSelector() const;
+ void setYChannelSelector(const ChannelSelectorType);
+
+ float scale() const;
+ void setScale(float scale);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(maxEffectRect()); }
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEDisplacementMap(Filter*, ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float);
+
+ ChannelSelectorType m_xChannelSelector;
+ ChannelSelectorType m_yChannelSelector;
+ float m_scale;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEDisplacementMap_h
diff --git a/Source/WebCore/platform/graphics/filters/FEFlood.cpp b/Source/WebCore/platform/graphics/filters/FEFlood.cpp
new file mode 100644
index 0000000..8bfdef8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEFlood.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEFlood.h"
+
+#include "Filter.h"
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+FEFlood::FEFlood(Filter* filter, const Color& floodColor, float floodOpacity)
+ : FilterEffect(filter)
+ , m_floodColor(floodColor)
+ , m_floodOpacity(floodOpacity)
+{
+}
+
+PassRefPtr<FEFlood> FEFlood::create(Filter* filter, const Color& floodColor, float floodOpacity)
+{
+ return adoptRef(new FEFlood(filter, floodColor, floodOpacity));
+}
+
+Color FEFlood::floodColor() const
+{
+ return m_floodColor;
+}
+
+void FEFlood::setFloodColor(const Color& color)
+{
+ m_floodColor = color;
+}
+
+float FEFlood::floodOpacity() const
+{
+ return m_floodOpacity;
+}
+
+void FEFlood::setFloodOpacity(float floodOpacity)
+{
+ m_floodOpacity = floodOpacity;
+}
+
+void FEFlood::apply()
+{
+ if (hasResult())
+ return;
+ ImageBuffer* resultImage = createImageBufferResult();
+ if (!resultImage)
+ return;
+
+ Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity());
+ resultImage->context()->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color, ColorSpaceDeviceRGB);
+}
+
+void FEFlood::dump()
+{
+}
+
+TextStream& FEFlood::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feFlood";
+ FilterEffect::externalRepresentation(ts);
+ ts << " flood-color=\"" << floodColor().name() << "\" "
+ << "flood-opacity=\"" << floodOpacity() << "\"]\n";
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEFlood.h b/Source/WebCore/platform/graphics/filters/FEFlood.h
new file mode 100644
index 0000000..2e8824f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEFlood.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEFlood_h
+#define FEFlood_h
+
+#if ENABLE(FILTERS)
+#include "Color.h"
+#include "Filter.h"
+#include "FilterEffect.h"
+
+namespace WebCore {
+
+class FEFlood : public FilterEffect {
+public:
+ static PassRefPtr<FEFlood> create(Filter* filter, const Color&, float);
+
+ Color floodColor() const;
+ void setFloodColor(const Color &);
+
+ float floodOpacity() const;
+ void setFloodOpacity(float);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(maxEffectRect()); }
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEFlood(Filter*, const Color&, float);
+
+ Color m_floodColor;
+ float m_floodOpacity;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEFlood_h
diff --git a/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
new file mode 100644
index 0000000..37b5992
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Igalia, S.L.
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEGaussianBlur.h"
+
+#include "Filter.h"
+#include "GraphicsContext.h"
+
+#include <wtf/ByteArray.h>
+#include <wtf/MathExtras.h>
+
+using std::max;
+
+static const float gGaussianKernelFactor = 3 / 4.f * sqrtf(2 * piFloat);
+static const unsigned gMaxKernelSize = 1000;
+
+namespace WebCore {
+
+FEGaussianBlur::FEGaussianBlur(Filter* filter, float x, float y)
+ : FilterEffect(filter)
+ , m_stdX(x)
+ , m_stdY(y)
+{
+}
+
+PassRefPtr<FEGaussianBlur> FEGaussianBlur::create(Filter* filter, float x, float y)
+{
+ return adoptRef(new FEGaussianBlur(filter, x, y));
+}
+
+float FEGaussianBlur::stdDeviationX() const
+{
+ return m_stdX;
+}
+
+void FEGaussianBlur::setStdDeviationX(float x)
+{
+ m_stdX = x;
+}
+
+float FEGaussianBlur::stdDeviationY() const
+{
+ return m_stdY;
+}
+
+void FEGaussianBlur::setStdDeviationY(float y)
+{
+ m_stdY = y;
+}
+
+inline void boxBlur(ByteArray* srcPixelArray, ByteArray* dstPixelArray,
+ unsigned dx, int dxLeft, int dxRight, int stride, int strideLine, int effectWidth, int effectHeight, bool alphaImage)
+{
+ for (int y = 0; y < effectHeight; ++y) {
+ int line = y * strideLine;
+ for (int channel = 3; channel >= 0; --channel) {
+ int sum = 0;
+ // Fill the kernel
+ int maxKernelSize = std::min(dxRight, effectWidth);
+ for (int i = 0; i < maxKernelSize; ++i)
+ sum += srcPixelArray->get(line + i * stride + channel);
+
+ // Blurring
+ for (int x = 0; x < effectWidth; ++x) {
+ int pixelByteOffset = line + x * stride + channel;
+ dstPixelArray->set(pixelByteOffset, static_cast<unsigned char>(sum / dx));
+ if (x >= dxLeft)
+ sum -= srcPixelArray->get(pixelByteOffset - dxLeft * stride);
+ if (x + dxRight < effectWidth)
+ sum += srcPixelArray->get(pixelByteOffset + dxRight * stride);
+ }
+ if (alphaImage) // Source image is black, it just has different alpha values
+ break;
+ }
+ }
+}
+
+inline void kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight)
+{
+ // check http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement for details
+ switch (boxBlur) {
+ case 0:
+ if (!(std % 2)) {
+ dLeft = std / 2 - 1;
+ dRight = std - dLeft;
+ } else {
+ dLeft = std / 2;
+ dRight = std - dLeft;
+ }
+ break;
+ case 1:
+ if (!(std % 2)) {
+ dLeft++;
+ dRight--;
+ }
+ break;
+ case 2:
+ if (!(std % 2)) {
+ dRight++;
+ std++;
+ }
+ break;
+ }
+}
+
+inline void calculateKernelSize(Filter* filter, unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY)
+{
+ stdX = filter->applyHorizontalScale(stdX);
+ stdY = filter->applyVerticalScale(stdY);
+
+ kernelSizeX = 0;
+ if (stdX)
+ kernelSizeX = max<unsigned>(2, static_cast<unsigned>(floorf(stdX * gGaussianKernelFactor + 0.5f)));
+ kernelSizeY = 0;
+ if (stdY)
+ kernelSizeY = max<unsigned>(2, static_cast<unsigned>(floorf(stdY * gGaussianKernelFactor + 0.5f)));
+
+ // Limit the kernel size to 1000. A bigger radius won't make a big difference for the result image but
+ // inflates the absolute paint rect to much. This is compatible with Firefox' behavior.
+ if (kernelSizeX > gMaxKernelSize)
+ kernelSizeX = gMaxKernelSize;
+ if (kernelSizeY > gMaxKernelSize)
+ kernelSizeY = gMaxKernelSize;
+}
+
+void FEGaussianBlur::determineAbsolutePaintRect()
+{
+ FloatRect absolutePaintRect = inputEffect(0)->absolutePaintRect();
+ absolutePaintRect.intersect(maxEffectRect());
+
+ unsigned kernelSizeX = 0;
+ unsigned kernelSizeY = 0;
+ calculateKernelSize(filter(), kernelSizeX, kernelSizeY, m_stdX, m_stdY);
+
+ // We take the half kernel size and multiply it with three, because we run box blur three times.
+ absolutePaintRect.inflateX(3 * kernelSizeX * 0.5f);
+ absolutePaintRect.inflateY(3 * kernelSizeY * 0.5f);
+ setAbsolutePaintRect(enclosingIntRect(absolutePaintRect));
+}
+
+void FEGaussianBlur::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ in->apply();
+ if (!in->hasResult())
+ return;
+
+ ByteArray* srcPixelArray = createPremultipliedImageResult();
+ if (!srcPixelArray)
+ return;
+
+ setIsAlphaImage(in->isAlphaImage());
+
+ IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
+ in->copyPremultipliedImage(srcPixelArray, effectDrawingRect);
+
+ if (!m_stdX && !m_stdY)
+ return;
+
+ unsigned kernelSizeX = 0;
+ unsigned kernelSizeY = 0;
+ calculateKernelSize(filter(), kernelSizeX, kernelSizeY, m_stdX, m_stdY);
+
+ IntSize paintSize = absolutePaintRect().size();
+ RefPtr<ByteArray> tmpImageData = ByteArray::create(paintSize.width() * paintSize.height() * 4);
+ ByteArray* tmpPixelArray = tmpImageData.get();
+
+ int stride = 4 * paintSize.width();
+ int dxLeft = 0;
+ int dxRight = 0;
+ int dyLeft = 0;
+ int dyRight = 0;
+ for (int i = 0; i < 3; ++i) {
+ if (kernelSizeX) {
+ kernelPosition(i, kernelSizeX, dxLeft, dxRight);
+ boxBlur(srcPixelArray, tmpPixelArray, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), isAlphaImage());
+ } else {
+ ByteArray* auxPixelArray = tmpPixelArray;
+ tmpPixelArray = srcPixelArray;
+ srcPixelArray = auxPixelArray;
+ }
+
+ if (kernelSizeY) {
+ kernelPosition(i, kernelSizeY, dyLeft, dyRight);
+ boxBlur(tmpPixelArray, srcPixelArray, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), isAlphaImage());
+ } else {
+ ByteArray* auxPixelArray = tmpPixelArray;
+ tmpPixelArray = srcPixelArray;
+ srcPixelArray = auxPixelArray;
+ }
+ }
+}
+
+void FEGaussianBlur::dump()
+{
+}
+
+TextStream& FEGaussianBlur::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feGaussianBlur";
+ FilterEffect::externalRepresentation(ts);
+ ts << " stdDeviation=\"" << m_stdX << ", " << m_stdY << "\"]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+float FEGaussianBlur::calculateStdDeviation(float radius)
+{
+ // Blur radius represents 2/3 times the kernel size, the dest pixel is half of the radius applied 3 times
+ return max((radius * 2 / 3.f - 0.5f) / gGaussianKernelFactor, 0.f);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEGaussianBlur.h b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.h
new file mode 100644
index 0000000..79f9a45
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEGaussianBlur_h
+#define FEGaussianBlur_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+#include "Filter.h"
+
+namespace WebCore {
+
+class FEGaussianBlur : public FilterEffect {
+public:
+ static PassRefPtr<FEGaussianBlur> create(Filter*, float, float);
+
+ float stdDeviationX() const;
+ void setStdDeviationX(float);
+
+ float stdDeviationY() const;
+ void setStdDeviationY(float);
+
+ static float calculateStdDeviation(float);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEGaussianBlur(Filter*, float, float);
+
+ float m_stdX;
+ float m_stdY;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEGaussianBlur_h
diff --git a/Source/WebCore/platform/graphics/filters/FELighting.cpp b/Source/WebCore/platform/graphics/filters/FELighting.cpp
new file mode 100644
index 0000000..ec1ca88
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FELighting.cpp
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Zoltan Herczeg
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FELighting.h"
+
+#include "LightSource.h"
+
+namespace WebCore {
+
+FELighting::FELighting(Filter* filter, LightingType lightingType, const Color& lightingColor, float surfaceScale,
+ float diffuseConstant, float specularConstant, float specularExponent,
+ float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource)
+ : FilterEffect(filter)
+ , m_lightingType(lightingType)
+ , m_lightSource(lightSource)
+ , m_lightingColor(lightingColor)
+ , m_surfaceScale(surfaceScale)
+ , m_diffuseConstant(diffuseConstant)
+ , m_specularConstant(specularConstant)
+ , m_specularExponent(specularExponent)
+ , m_kernelUnitLengthX(kernelUnitLengthX)
+ , m_kernelUnitLengthY(kernelUnitLengthY)
+{
+}
+
+const static int cPixelSize = 4;
+const static int cAlphaChannelOffset = 3;
+const static unsigned char cOpaqueAlpha = static_cast<unsigned char>(0xff);
+const static float cFactor1div2 = -1 / 2.f;
+const static float cFactor1div3 = -1 / 3.f;
+const static float cFactor1div4 = -1 / 4.f;
+const static float cFactor2div3 = -2 / 3.f;
+
+// << 1 is signed multiply by 2
+inline void FELighting::LightingData::topLeft(int offset, IntPoint& normalVector)
+{
+ int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ offset += widthMultipliedByPixelSize;
+ int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ normalVector.setX(-(center << 1) + (right << 1) - bottom + bottomRight);
+ normalVector.setY(-(center << 1) - right + (bottom << 1) + bottomRight);
+}
+
+inline void FELighting::LightingData::topRow(int offset, IntPoint& normalVector)
+{
+ int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ offset += widthMultipliedByPixelSize;
+ int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ normalVector.setX(-(left << 1) + (right << 1) - bottomLeft + bottomRight);
+ normalVector.setY(-left - (center << 1) - right + bottomLeft + (bottom << 1) + bottomRight);
+}
+
+inline void FELighting::LightingData::topRight(int offset, IntPoint& normalVector)
+{
+ int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ offset += widthMultipliedByPixelSize;
+ int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ normalVector.setX(-(left << 1) + (center << 1) - bottomLeft + bottom);
+ normalVector.setY(-left - (center << 1) + bottomLeft + (bottom << 1));
+}
+
+inline void FELighting::LightingData::leftColumn(int offset, IntPoint& normalVector)
+{
+ int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ offset -= widthMultipliedByPixelSize;
+ int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ offset += widthMultipliedByPixelSize << 1;
+ int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ normalVector.setX(-top + topRight - (center << 1) + (right << 1) - bottom + bottomRight);
+ normalVector.setY(-(top << 1) - topRight + (bottom << 1) + bottomRight);
+}
+
+inline void FELighting::LightingData::interior(int offset, IntPoint& normalVector)
+{
+ int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ offset -= widthMultipliedByPixelSize;
+ int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ offset += widthMultipliedByPixelSize << 1;
+ int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1) - bottomLeft + bottomRight);
+ normalVector.setY(-topLeft - (top << 1) - topRight + bottomLeft + (bottom << 1) + bottomRight);
+}
+
+inline void FELighting::LightingData::rightColumn(int offset, IntPoint& normalVector)
+{
+ int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ offset -= widthMultipliedByPixelSize;
+ int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ offset += widthMultipliedByPixelSize << 1;
+ int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ normalVector.setX(-topLeft + top - (left << 1) + (center << 1) - bottomLeft + bottom);
+ normalVector.setY(-topLeft - (top << 1) + bottomLeft + (bottom << 1));
+}
+
+inline void FELighting::LightingData::bottomLeft(int offset, IntPoint& normalVector)
+{
+ int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ offset -= widthMultipliedByPixelSize;
+ int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ normalVector.setX(-top + topRight - (center << 1) + (right << 1));
+ normalVector.setY(-(top << 1) - topRight + (center << 1) + right);
+}
+
+inline void FELighting::LightingData::bottomRow(int offset, IntPoint& normalVector)
+{
+ int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ offset -= widthMultipliedByPixelSize;
+ int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
+ normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1));
+ normalVector.setY(-topLeft - (top << 1) - topRight + left + (center << 1) + right);
+}
+
+inline void FELighting::LightingData::bottomRight(int offset, IntPoint& normalVector)
+{
+ int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ offset -= widthMultipliedByPixelSize;
+ int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
+ int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
+ normalVector.setX(-topLeft + top - (left << 1) + (center << 1));
+ normalVector.setY(-topLeft - (top << 1) + left + (center << 1));
+}
+
+inline void FELighting::inlineSetPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData,
+ int lightX, int lightY, float factorX, float factorY, IntPoint& normal2DVector)
+{
+ m_lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->get(offset + cAlphaChannelOffset)) * data.surfaceScale);
+
+ float lightStrength;
+ if (!normal2DVector.x() && !normal2DVector.y()) {
+ // Normal vector is (0, 0, 1). This is a quite frequent case.
+ if (m_lightingType == FELighting::DiffuseLighting)
+ lightStrength = m_diffuseConstant * paintingData.lightVector.z() / paintingData.lightVectorLength;
+ else {
+ FloatPoint3D halfwayVector = paintingData.lightVector;
+ halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength);
+ float halfwayVectorLength = halfwayVector.length();
+ if (m_specularExponent == 1)
+ lightStrength = m_specularConstant * halfwayVector.z() / halfwayVectorLength;
+ else
+ lightStrength = m_specularConstant * powf(halfwayVector.z() / halfwayVectorLength, m_specularExponent);
+ }
+ } else {
+ FloatPoint3D normalVector;
+ normalVector.setX(factorX * static_cast<float>(normal2DVector.x()) * data.surfaceScale);
+ normalVector.setY(factorY * static_cast<float>(normal2DVector.y()) * data.surfaceScale);
+ normalVector.setZ(1);
+ float normalVectorLength = normalVector.length();
+
+ if (m_lightingType == FELighting::DiffuseLighting)
+ lightStrength = m_diffuseConstant * (normalVector * paintingData.lightVector) / (normalVectorLength * paintingData.lightVectorLength);
+ else {
+ FloatPoint3D halfwayVector = paintingData.lightVector;
+ halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength);
+ float halfwayVectorLength = halfwayVector.length();
+ if (m_specularExponent == 1)
+ lightStrength = m_specularConstant * (normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength);
+ else
+ lightStrength = m_specularConstant * powf((normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength), m_specularExponent);
+ }
+ }
+
+ if (lightStrength > 1)
+ lightStrength = 1;
+ if (lightStrength < 0)
+ lightStrength = 0;
+
+ data.pixels->set(offset, static_cast<unsigned char>(lightStrength * paintingData.colorVector.x()));
+ data.pixels->set(offset + 1, static_cast<unsigned char>(lightStrength * paintingData.colorVector.y()));
+ data.pixels->set(offset + 2, static_cast<unsigned char>(lightStrength * paintingData.colorVector.z()));
+}
+
+void FELighting::setPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData,
+ int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector)
+{
+ inlineSetPixel(offset, data, paintingData, lightX, lightY, factorX, factorY, normalVector);
+}
+
+bool FELighting::drawLighting(ByteArray* pixels, int width, int height)
+{
+ LightSource::PaintingData paintingData;
+ LightingData data;
+
+ if (!m_lightSource)
+ return false;
+
+ // FIXME: do something if width or height (or both) is 1 pixel.
+ // The W3 spec does not define this case. Now the filter just returns.
+ if (width <= 2 || height <= 2)
+ return false;
+
+ data.pixels = pixels;
+ data.surfaceScale = m_surfaceScale / 255.0f;
+ data.widthMultipliedByPixelSize = width * cPixelSize;
+ data.widthDecreasedByOne = width - 1;
+ data.heightDecreasedByOne = height - 1;
+ paintingData.colorVector = FloatPoint3D(m_lightingColor.red(), m_lightingColor.green(), m_lightingColor.blue());
+ m_lightSource->initPaintingData(paintingData);
+
+ // Top/Left corner
+ IntPoint normalVector;
+ int offset = 0;
+ data.topLeft(offset, normalVector);
+ setPixel(offset, data, paintingData, 0, 0, cFactor2div3, cFactor2div3, normalVector);
+
+ // Top/Right pixel
+ offset = data.widthMultipliedByPixelSize - cPixelSize;
+ data.topRight(offset, normalVector);
+ setPixel(offset, data, paintingData, data.widthDecreasedByOne, 0, cFactor2div3, cFactor2div3, normalVector);
+
+ // Bottom/Left pixel
+ offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize;
+ data.bottomLeft(offset, normalVector);
+ setPixel(offset, data, paintingData, 0, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector);
+
+ // Bottom/Right pixel
+ offset = height * data.widthMultipliedByPixelSize - cPixelSize;
+ data.bottomRight(offset, normalVector);
+ setPixel(offset, data, paintingData, data.widthDecreasedByOne, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector);
+
+ if (width >= 3) {
+ // Top row
+ offset = cPixelSize;
+ for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
+ data.topRow(offset, normalVector);
+ inlineSetPixel(offset, data, paintingData, x, 0, cFactor1div3, cFactor1div2, normalVector);
+ }
+ // Bottom row
+ offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize + cPixelSize;
+ for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
+ data.bottomRow(offset, normalVector);
+ inlineSetPixel(offset, data, paintingData, x, data.heightDecreasedByOne, cFactor1div3, cFactor1div2, normalVector);
+ }
+ }
+
+ if (height >= 3) {
+ // Left column
+ offset = data.widthMultipliedByPixelSize;
+ for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) {
+ data.leftColumn(offset, normalVector);
+ inlineSetPixel(offset, data, paintingData, 0, y, cFactor1div2, cFactor1div3, normalVector);
+ }
+ // Right column
+ offset = (data.widthMultipliedByPixelSize << 1) - cPixelSize;
+ for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) {
+ data.rightColumn(offset, normalVector);
+ inlineSetPixel(offset, data, paintingData, data.widthDecreasedByOne, y, cFactor1div2, cFactor1div3, normalVector);
+ }
+ }
+
+ if (width >= 3 && height >= 3) {
+ // Interior pixels
+ for (int y = 1; y < data.heightDecreasedByOne; ++y) {
+ offset = y * data.widthMultipliedByPixelSize + cPixelSize;
+ for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
+ data.interior(offset, normalVector);
+ inlineSetPixel(offset, data, paintingData, x, y, cFactor1div4, cFactor1div4, normalVector);
+ }
+ }
+ }
+
+ int lastPixel = data.widthMultipliedByPixelSize * height;
+ if (m_lightingType == DiffuseLighting) {
+ for (int i = cAlphaChannelOffset; i < lastPixel; i += cPixelSize)
+ data.pixels->set(i, cOpaqueAlpha);
+ } else {
+ for (int i = 0; i < lastPixel; i += cPixelSize) {
+ unsigned char a1 = data.pixels->get(i);
+ unsigned char a2 = data.pixels->get(i + 1);
+ unsigned char a3 = data.pixels->get(i + 2);
+ // alpha set to set to max(a1, a2, a3)
+ data.pixels->set(i + 3, a1 >= a2 ? (a1 >= a3 ? a1 : a3) : (a2 >= a3 ? a2 : a3));
+ }
+ }
+
+ return true;
+}
+
+void FELighting::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ in->apply();
+ if (!in->hasResult())
+ return;
+
+ ByteArray* srcPixelArray = createUnmultipliedImageResult();
+ if (!srcPixelArray)
+ return;
+
+ setIsAlphaImage(false);
+
+ IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
+ in->copyUnmultipliedImage(srcPixelArray, effectDrawingRect);
+
+ // FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3
+ // standard has no test case for them, and other browsers (like Firefox) has strange
+ // output for various kernelUnitLengths, and I am not sure they are reliable.
+ // Anyway, feConvolveMatrix should also use the implementation
+
+ IntSize absolutePaintSize = absolutePaintRect().size();
+ drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height());
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FELighting.h b/Source/WebCore/platform/graphics/filters/FELighting.h
new file mode 100644
index 0000000..fa1c0aa
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FELighting.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Zoltan Herczeg
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 FELighting_h
+#define FELighting_h
+
+#if ENABLE(FILTERS)
+#include "Color.h"
+#include "Filter.h"
+#include "FilterEffect.h"
+#include "LightSource.h"
+#include <wtf/ByteArray.h>
+
+// Common base class for FEDiffuseLighting and FESpecularLighting
+
+namespace WebCore {
+
+class FELighting : public FilterEffect {
+public:
+ virtual void apply();
+
+ virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(maxEffectRect()); }
+
+protected:
+ enum LightingType {
+ DiffuseLighting,
+ SpecularLighting
+ };
+
+ struct LightingData {
+ // This structure contains only read-only (SMP safe) data
+ ByteArray* pixels;
+ float surfaceScale;
+ int widthMultipliedByPixelSize;
+ int widthDecreasedByOne;
+ int heightDecreasedByOne;
+
+ inline void topLeft(int offset, IntPoint& normalVector);
+ inline void topRow(int offset, IntPoint& normalVector);
+ inline void topRight(int offset, IntPoint& normalVector);
+ inline void leftColumn(int offset, IntPoint& normalVector);
+ inline void interior(int offset, IntPoint& normalVector);
+ inline void rightColumn(int offset, IntPoint& normalVector);
+ inline void bottomLeft(int offset, IntPoint& normalVector);
+ inline void bottomRow(int offset, IntPoint& normalVector);
+ inline void bottomRight(int offset, IntPoint& normalVector);
+ };
+
+ FELighting(Filter*, LightingType, const Color&, float, float, float, float, float, float, PassRefPtr<LightSource>);
+
+ bool drawLighting(ByteArray*, int, int);
+ inline void inlineSetPixel(int offset, LightingData&, LightSource::PaintingData&,
+ int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector);
+
+ // Not worth to inline every occurence of setPixel.
+ void setPixel(int offset, LightingData&, LightSource::PaintingData&,
+ int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector);
+
+ LightingType m_lightingType;
+ RefPtr<LightSource> m_lightSource;
+
+ Color m_lightingColor;
+ float m_surfaceScale;
+ float m_diffuseConstant;
+ float m_specularConstant;
+ float m_specularExponent;
+ float m_kernelUnitLengthX;
+ float m_kernelUnitLengthY;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FELighting_h
diff --git a/Source/WebCore/platform/graphics/filters/FEMerge.cpp b/Source/WebCore/platform/graphics/filters/FEMerge.cpp
new file mode 100644
index 0000000..4395321
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEMerge.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEMerge.h"
+
+#include "Filter.h"
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+FEMerge::FEMerge(Filter* filter)
+ : FilterEffect(filter)
+{
+}
+
+PassRefPtr<FEMerge> FEMerge::create(Filter* filter)
+{
+ return adoptRef(new FEMerge(filter));
+}
+
+void FEMerge::apply()
+{
+ if (hasResult())
+ return;
+ unsigned size = numberOfEffectInputs();
+ ASSERT(size > 0);
+ for (unsigned i = 0; i < size; ++i) {
+ FilterEffect* in = inputEffect(i);
+ in->apply();
+ if (!in->hasResult())
+ return;
+ }
+
+ ImageBuffer* resultImage = createImageBufferResult();
+ if (!resultImage)
+ return;
+
+ GraphicsContext* filterContext = resultImage->context();
+ for (unsigned i = 0; i < size; ++i) {
+ FilterEffect* in = inputEffect(i);
+ filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+ }
+}
+
+void FEMerge::dump()
+{
+}
+
+TextStream& FEMerge::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feMerge";
+ FilterEffect::externalRepresentation(ts);
+ unsigned size = numberOfEffectInputs();
+ ASSERT(size > 0);
+ ts << " mergeNodes=\"" << size << "\"]\n";
+ for (unsigned i = 0; i < size; ++i)
+ inputEffect(i)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEMerge.h b/Source/WebCore/platform/graphics/filters/FEMerge.h
new file mode 100644
index 0000000..dbee610
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEMerge.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEMerge_h
+#define FEMerge_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+#include "Filter.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class FEMerge : public FilterEffect {
+public:
+ static PassRefPtr<FEMerge> create(Filter*);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEMerge(Filter*);
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEMerge_h
diff --git a/Source/WebCore/platform/graphics/filters/FEMorphology.cpp b/Source/WebCore/platform/graphics/filters/FEMorphology.cpp
new file mode 100644
index 0000000..45c7edb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEMorphology.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEMorphology.h"
+
+#include "Filter.h"
+
+#include <wtf/ByteArray.h>
+#include <wtf/Vector.h>
+
+using std::min;
+using std::max;
+
+namespace WebCore {
+
+FEMorphology::FEMorphology(Filter* filter, MorphologyOperatorType type, float radiusX, float radiusY)
+ : FilterEffect(filter)
+ , m_type(type)
+ , m_radiusX(radiusX)
+ , m_radiusY(radiusY)
+{
+}
+
+PassRefPtr<FEMorphology> FEMorphology::create(Filter* filter, MorphologyOperatorType type, float radiusX, float radiusY)
+{
+ return adoptRef(new FEMorphology(filter, type, radiusX, radiusY));
+}
+
+MorphologyOperatorType FEMorphology::morphologyOperator() const
+{
+ return m_type;
+}
+
+void FEMorphology::setMorphologyOperator(MorphologyOperatorType type)
+{
+ m_type = type;
+}
+
+float FEMorphology::radiusX() const
+{
+ return m_radiusX;
+}
+
+void FEMorphology::setRadiusX(float radiusX)
+{
+ m_radiusX = radiusX;
+}
+
+float FEMorphology::radiusY() const
+{
+ return m_radiusY;
+}
+
+void FEMorphology::determineAbsolutePaintRect()
+{
+ FloatRect paintRect = inputEffect(0)->absolutePaintRect();
+ Filter* filter = this->filter();
+ paintRect.inflateX(filter->applyHorizontalScale(m_radiusX));
+ paintRect.inflateY(filter->applyVerticalScale(m_radiusY));
+ paintRect.intersect(maxEffectRect());
+ setAbsolutePaintRect(enclosingIntRect(paintRect));
+}
+
+void FEMorphology::setRadiusY(float radiusY)
+{
+ m_radiusY = radiusY;
+}
+
+void FEMorphology::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ in->apply();
+ if (!in->hasResult())
+ return;
+
+ ByteArray* dstPixelArray = createPremultipliedImageResult();
+ if (!dstPixelArray)
+ return;
+
+ setIsAlphaImage(in->isAlphaImage());
+ if (m_radiusX <= 0 || m_radiusY <= 0)
+ return;
+
+ Filter* filter = this->filter();
+ int radiusX = static_cast<int>(floorf(filter->applyHorizontalScale(m_radiusX)));
+ int radiusY = static_cast<int>(floorf(filter->applyVerticalScale(m_radiusY)));
+
+ IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
+ RefPtr<ByteArray> srcPixelArray = in->asPremultipliedImage(effectDrawingRect);
+
+ int effectWidth = effectDrawingRect.width() * 4;
+
+ // Limit the radius size to effect dimensions
+ radiusX = min(effectDrawingRect.width() - 1, radiusX);
+ radiusY = min(effectDrawingRect.height() - 1, radiusY);
+
+ Vector<unsigned char> extrema;
+ for (int y = 0; y < effectDrawingRect.height(); ++y) {
+ int startY = max(0, y - radiusY);
+ int endY = min(effectDrawingRect.height() - 1, y + radiusY);
+ for (unsigned channel = 0; channel < 4; ++channel) {
+ // Fill the kernel
+ extrema.clear();
+ for (int j = 0; j <= radiusX; ++j) {
+ unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + 4 * j + channel);
+ for (int i = startY; i <= endY; ++i) {
+ unsigned char pixel = srcPixelArray->get(i * effectWidth + 4 * j + channel);
+ if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) ||
+ (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema))
+ columnExtrema = pixel;
+ }
+ extrema.append(columnExtrema);
+ }
+
+ // Kernel is filled, get extrema of next column
+ for (int x = 0; x < effectDrawingRect.width(); ++x) {
+ unsigned endX = min(x + radiusX, effectDrawingRect.width() - 1);
+ unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + endX * 4 + channel);
+ for (int i = startY; i <= endY; ++i) {
+ unsigned char pixel = srcPixelArray->get(i * effectWidth + endX * 4 + channel);
+ if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) ||
+ (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema))
+ columnExtrema = pixel;
+ }
+ if (x - radiusX >= 0)
+ extrema.remove(0);
+ if (x + radiusX <= effectDrawingRect.width())
+ extrema.append(columnExtrema);
+ unsigned char entireExtrema = extrema[0];
+ for (unsigned kernelIndex = 0; kernelIndex < extrema.size(); ++kernelIndex) {
+ if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema) ||
+ (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema))
+ entireExtrema = extrema[kernelIndex];
+ }
+ dstPixelArray->set(y * effectWidth + 4 * x + channel, entireExtrema);
+ }
+ }
+ }
+}
+
+void FEMorphology::dump()
+{
+}
+
+static TextStream& operator<<(TextStream& ts, const MorphologyOperatorType& type)
+{
+ switch (type) {
+ case FEMORPHOLOGY_OPERATOR_UNKNOWN:
+ ts << "UNKNOWN";
+ break;
+ case FEMORPHOLOGY_OPERATOR_ERODE:
+ ts << "ERODE";
+ break;
+ case FEMORPHOLOGY_OPERATOR_DILATE:
+ ts << "DILATE";
+ break;
+ }
+ return ts;
+}
+
+TextStream& FEMorphology::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feMorphology";
+ FilterEffect::externalRepresentation(ts);
+ ts << " operator=\"" << morphologyOperator() << "\" "
+ << "radius=\"" << radiusX() << ", " << radiusY() << "\"]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEMorphology.h b/Source/WebCore/platform/graphics/filters/FEMorphology.h
new file mode 100644
index 0000000..683e7d0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEMorphology.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEMorphology_h
+#define FEMorphology_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+#include "Filter.h"
+
+namespace WebCore {
+
+enum MorphologyOperatorType {
+ FEMORPHOLOGY_OPERATOR_UNKNOWN = 0,
+ FEMORPHOLOGY_OPERATOR_ERODE = 1,
+ FEMORPHOLOGY_OPERATOR_DILATE = 2
+};
+
+class FEMorphology : public FilterEffect {
+public:
+ static PassRefPtr<FEMorphology> create(Filter*, MorphologyOperatorType, float radiusX, float radiusY);
+ MorphologyOperatorType morphologyOperator() const;
+ void setMorphologyOperator(MorphologyOperatorType);
+
+ float radiusX() const;
+ void setRadiusX(float);
+
+ float radiusY() const;
+ void setRadiusY(float);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEMorphology(Filter*, MorphologyOperatorType, float radiusX, float radiusY);
+
+ MorphologyOperatorType m_type;
+ float m_radiusX;
+ float m_radiusY;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEMorphology_h
diff --git a/Source/WebCore/platform/graphics/filters/FEOffset.cpp b/Source/WebCore/platform/graphics/filters/FEOffset.cpp
new file mode 100644
index 0000000..f1d5914
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEOffset.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEOffset.h"
+
+#include "Filter.h"
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+FEOffset::FEOffset(Filter* filter, float dx, float dy)
+ : FilterEffect(filter)
+ , m_dx(dx)
+ , m_dy(dy)
+{
+}
+
+PassRefPtr<FEOffset> FEOffset::create(Filter* filter, float dx, float dy)
+{
+ return adoptRef(new FEOffset(filter, dx, dy));
+}
+
+float FEOffset::dx() const
+{
+ return m_dx;
+}
+
+void FEOffset::setDx(float dx)
+{
+ m_dx = dx;
+}
+
+float FEOffset::dy() const
+{
+ return m_dy;
+}
+
+void FEOffset::setDy(float dy)
+{
+ m_dy = dy;
+}
+
+void FEOffset::determineAbsolutePaintRect()
+{
+ FloatRect paintRect = inputEffect(0)->absolutePaintRect();
+ Filter* filter = this->filter();
+ paintRect.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy));
+ paintRect.intersect(maxEffectRect());
+ setAbsolutePaintRect(enclosingIntRect(paintRect));
+}
+
+void FEOffset::apply()
+{
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ in->apply();
+ if (!in->hasResult())
+ return;
+
+ ImageBuffer* resultImage = createImageBufferResult();
+ if (!resultImage)
+ return;
+
+ setIsAlphaImage(in->isAlphaImage());
+
+ FloatRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect());
+ Filter* filter = this->filter();
+ drawingRegion.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy));
+ resultImage->context()->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegion);
+}
+
+void FEOffset::dump()
+{
+}
+
+TextStream& FEOffset::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feOffset";
+ FilterEffect::externalRepresentation(ts);
+ ts << " dx=\"" << dx() << "\" dy=\"" << dy() << "\"]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FEOffset.h b/Source/WebCore/platform/graphics/filters/FEOffset.h
new file mode 100644
index 0000000..5aa5c38
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FEOffset.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FEOffset_h
+#define FEOffset_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+#include "Filter.h"
+
+namespace WebCore {
+
+class FEOffset : public FilterEffect {
+public:
+ static PassRefPtr<FEOffset> create(Filter*, float dx, float dy);
+
+ float dx() const;
+ void setDx(float);
+
+ float dy() const;
+ void setDy(float);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FEOffset(Filter*, float dx, float dy);
+
+ float m_dx;
+ float m_dy;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEOffset_h
diff --git a/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp b/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp
new file mode 100644
index 0000000..d21dafd
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FESpecularLighting.h"
+
+#include "LightSource.h"
+
+namespace WebCore {
+
+FESpecularLighting::FESpecularLighting(Filter* filter, const Color& lightingColor, float surfaceScale,
+ float specularConstant, float specularExponent, float kernelUnitLengthX,
+ float kernelUnitLengthY, PassRefPtr<LightSource> lightSource)
+ : FELighting(filter, SpecularLighting, lightingColor, surfaceScale, 0, specularConstant, specularExponent, kernelUnitLengthX, kernelUnitLengthY, lightSource)
+{
+}
+
+PassRefPtr<FESpecularLighting> FESpecularLighting::create(Filter* filter, const Color& lightingColor,
+ float surfaceScale, float specularConstant, float specularExponent,
+ float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource)
+{
+ return adoptRef(new FESpecularLighting(filter, lightingColor, surfaceScale, specularConstant, specularExponent,
+ kernelUnitLengthX, kernelUnitLengthY, lightSource));
+}
+
+FESpecularLighting::~FESpecularLighting()
+{
+}
+
+Color FESpecularLighting::lightingColor() const
+{
+ return m_lightingColor;
+}
+
+void FESpecularLighting::setLightingColor(const Color& lightingColor)
+{
+ m_lightingColor = lightingColor;
+}
+
+float FESpecularLighting::surfaceScale() const
+{
+ return m_surfaceScale;
+}
+
+void FESpecularLighting::setSurfaceScale(float surfaceScale)
+{
+ m_surfaceScale = surfaceScale;
+}
+
+float FESpecularLighting::specularConstant() const
+{
+ return m_specularConstant;
+}
+
+void FESpecularLighting::setSpecularConstant(float specularConstant)
+{
+ m_specularConstant = specularConstant;
+}
+
+float FESpecularLighting::specularExponent() const
+{
+ return m_specularExponent;
+}
+
+void FESpecularLighting::setSpecularExponent(float specularExponent)
+{
+ m_specularExponent = specularExponent;
+}
+
+float FESpecularLighting::kernelUnitLengthX() const
+{
+ return m_kernelUnitLengthX;
+}
+
+void FESpecularLighting::setKernelUnitLengthX(float kernelUnitLengthX)
+{
+ m_kernelUnitLengthX = kernelUnitLengthX;
+}
+
+float FESpecularLighting::kernelUnitLengthY() const
+{
+ return m_kernelUnitLengthY;
+}
+
+void FESpecularLighting::setKernelUnitLengthY(float kernelUnitLengthY)
+{
+ m_kernelUnitLengthY = kernelUnitLengthY;
+}
+
+const LightSource* FESpecularLighting::lightSource() const
+{
+ return m_lightSource.get();
+}
+
+void FESpecularLighting::setLightSource(PassRefPtr<LightSource> lightSource)
+{
+ m_lightSource = lightSource;
+}
+
+void FESpecularLighting::dump()
+{
+}
+
+TextStream& FESpecularLighting::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feSpecularLighting";
+ FilterEffect::externalRepresentation(ts);
+ ts << " surfaceScale=\"" << m_surfaceScale << "\" "
+ << "specualConstant=\"" << m_specularConstant << "\" "
+ << "specularExponent=\"" << m_specularExponent << "\"]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FESpecularLighting.h b/Source/WebCore/platform/graphics/filters/FESpecularLighting.h
new file mode 100644
index 0000000..b3ccfbc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FESpecularLighting.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FESpecularLighting_h
+#define FESpecularLighting_h
+
+#if ENABLE(FILTERS)
+#include "FELighting.h"
+
+namespace WebCore {
+
+class FESpecularLighting : public FELighting {
+public:
+ static PassRefPtr<FESpecularLighting> create(Filter*, const Color&, float, float,
+ float, float, float, PassRefPtr<LightSource>);
+ virtual ~FESpecularLighting();
+
+ Color lightingColor() const;
+ void setLightingColor(const Color&);
+
+ float surfaceScale() const;
+ void setSurfaceScale(float);
+
+ float specularConstant() const;
+ void setSpecularConstant(float);
+
+ float specularExponent() const;
+ void setSpecularExponent(float);
+
+ float kernelUnitLengthX() const;
+ void setKernelUnitLengthX(float);
+
+ float kernelUnitLengthY() const;
+ void setKernelUnitLengthY(float);
+
+ const LightSource* lightSource() const;
+ void setLightSource(PassRefPtr<LightSource>);
+
+ virtual void dump();
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FESpecularLighting(Filter*, const Color&, float, float, float, float, float, PassRefPtr<LightSource>);
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FESpecularLighting_h
diff --git a/Source/WebCore/platform/graphics/filters/FETile.cpp b/Source/WebCore/platform/graphics/filters/FETile.cpp
new file mode 100644
index 0000000..e516c7e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FETile.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FETile.h"
+
+#include "AffineTransform.h"
+#include "Filter.h"
+#include "GraphicsContext.h"
+#include "Pattern.h"
+#include "SVGImageBufferTools.h"
+
+namespace WebCore {
+
+FETile::FETile(Filter* filter)
+ : FilterEffect(filter)
+{
+}
+
+PassRefPtr<FETile> FETile::create(Filter* filter)
+{
+ return adoptRef(new FETile(filter));
+}
+
+void FETile::apply()
+{
+// FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise.
+#if ENABLE(SVG)
+ if (hasResult())
+ return;
+ FilterEffect* in = inputEffect(0);
+ in->apply();
+ if (!in->hasResult())
+ return;
+
+ ImageBuffer* resultImage = createImageBufferResult();
+ if (!resultImage)
+ return;
+
+ setIsAlphaImage(in->isAlphaImage());
+
+ // Source input needs more attention. It has the size of the filterRegion but gives the
+ // size of the cutted sourceImage back. This is part of the specification and optimization.
+ FloatRect tileRect = in->maxEffectRect();
+ FloatPoint inMaxEffectLocation = tileRect.location();
+ FloatPoint maxEffectLocation = maxEffectRect().location();
+ if (in->filterEffectType() == FilterEffectTypeSourceInput) {
+ Filter* filter = this->filter();
+ tileRect = filter->filterRegion();
+ tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
+ }
+
+ OwnPtr<ImageBuffer> tileImage;
+ if (!SVGImageBufferTools::createImageBuffer(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB))
+ return;
+
+ GraphicsContext* tileImageContext = tileImage->context();
+ tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y());
+ tileImageContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, in->absolutePaintRect().location());
+
+ RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true);
+
+ AffineTransform patternTransform;
+ patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y());
+ pattern->setPatternSpaceTransform(patternTransform);
+ GraphicsContext* filterContext = resultImage->context();
+ filterContext->setFillPattern(pattern);
+ filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()));
+#endif
+}
+
+void FETile::dump()
+{
+}
+
+TextStream& FETile::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feTile";
+ FilterEffect::externalRepresentation(ts);
+ ts << "]\n";
+ inputEffect(0)->externalRepresentation(ts, indent + 1);
+
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FETile.h b/Source/WebCore/platform/graphics/filters/FETile.h
new file mode 100644
index 0000000..9b02b4c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FETile.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FETile_h
+#define FETile_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+#include "Filter.h"
+
+namespace WebCore {
+
+class FETile : public FilterEffect {
+public:
+ static PassRefPtr<FETile> create(Filter* filter);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(maxEffectRect()); }
+
+ virtual FilterEffectType filterEffectType() const { return FilterEffectTypeTile; }
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ FETile(Filter*);
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FETile_h
diff --git a/Source/WebCore/platform/graphics/filters/FETurbulence.cpp b/Source/WebCore/platform/graphics/filters/FETurbulence.cpp
new file mode 100644
index 0000000..f1a159b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FETurbulence.cpp
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FETurbulence.h"
+
+#include "Filter.h"
+
+#include <wtf/ByteArray.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+/*
+ Produces results in the range [1, 2**31 - 2]. Algorithm is:
+ r = (a * r) mod m where a = randAmplitude = 16807 and
+ m = randMaximum = 2**31 - 1 = 2147483647, r = seed.
+ See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
+ To test: the algorithm should produce the result 1043618065
+ as the 10,000th generated number if the original seed is 1.
+*/
+static const int s_perlinNoise = 4096;
+static const long s_randMaximum = 2147483647; // 2**31 - 1
+static const int s_randAmplitude = 16807; // 7**5; primitive root of m
+static const int s_randQ = 127773; // m / a
+static const int s_randR = 2836; // m % a
+
+FETurbulence::FETurbulence(Filter* filter, TurbulanceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
+ : FilterEffect(filter)
+ , m_type(type)
+ , m_baseFrequencyX(baseFrequencyX)
+ , m_baseFrequencyY(baseFrequencyY)
+ , m_numOctaves(numOctaves)
+ , m_seed(seed)
+ , m_stitchTiles(stitchTiles)
+{
+}
+
+PassRefPtr<FETurbulence> FETurbulence::create(Filter* filter, TurbulanceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
+{
+ return adoptRef(new FETurbulence(filter, type, baseFrequencyX, baseFrequencyY, numOctaves, seed, stitchTiles));
+}
+
+TurbulanceType FETurbulence::type() const
+{
+ return m_type;
+}
+
+void FETurbulence::setType(TurbulanceType type)
+{
+ m_type = type;
+}
+
+float FETurbulence::baseFrequencyY() const
+{
+ return m_baseFrequencyY;
+}
+
+void FETurbulence::setBaseFrequencyY(float baseFrequencyY)
+{
+ m_baseFrequencyY = baseFrequencyY;
+}
+
+float FETurbulence::baseFrequencyX() const
+{
+ return m_baseFrequencyX;
+}
+
+void FETurbulence::setBaseFrequencyX(float baseFrequencyX)
+{
+ m_baseFrequencyX = baseFrequencyX;
+}
+
+float FETurbulence::seed() const
+{
+ return m_seed;
+}
+
+void FETurbulence::setSeed(float seed)
+{
+ m_seed = seed;
+}
+
+int FETurbulence::numOctaves() const
+{
+ return m_numOctaves;
+}
+
+void FETurbulence::setNumOctaves(bool numOctaves)
+{
+ m_numOctaves = numOctaves;
+}
+
+bool FETurbulence::stitchTiles() const
+{
+ return m_stitchTiles;
+}
+
+void FETurbulence::setStitchTiles(bool stitch)
+{
+ m_stitchTiles = stitch;
+}
+
+// The turbulence calculation code is an adapted version of what appears in the SVG 1.1 specification:
+// http://www.w3.org/TR/SVG11/filters.html#feTurbulence
+
+FETurbulence::PaintingData::PaintingData(long paintingSeed, const IntSize& paintingSize)
+ : seed(paintingSeed)
+ , width(0)
+ , height(0)
+ , wrapX(0)
+ , wrapY(0)
+ , channel(0)
+ , filterSize(paintingSize)
+{
+}
+
+// Compute pseudo random number.
+inline long FETurbulence::PaintingData::random()
+{
+ long result = s_randAmplitude * (seed % s_randQ) - s_randR * (seed / s_randQ);
+ if (result <= 0)
+ result += s_randMaximum;
+ seed = result;
+ return result;
+}
+
+inline float smoothCurve(float t)
+{
+ return t * t * (3 - 2 * t);
+}
+
+inline float linearInterpolation(float t, float a, float b)
+{
+ return a + t * (b - a);
+}
+
+inline void FETurbulence::initPaint(PaintingData& paintingData)
+{
+ float normalizationFactor;
+
+ // The seed value clamp to the range [1, s_randMaximum - 1].
+ if (paintingData.seed <= 0)
+ paintingData.seed = -(paintingData.seed % (s_randMaximum - 1)) + 1;
+ if (paintingData.seed > s_randMaximum - 1)
+ paintingData.seed = s_randMaximum - 1;
+
+ float* gradient;
+ for (int channel = 0; channel < 4; ++channel) {
+ for (int i = 0; i < s_blockSize; ++i) {
+ paintingData.latticeSelector[i] = i;
+ gradient = paintingData.gradient[channel][i];
+ gradient[0] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
+ gradient[1] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
+ normalizationFactor = sqrtf(gradient[0] * gradient[0] + gradient[1] * gradient[1]);
+ gradient[0] /= normalizationFactor;
+ gradient[1] /= normalizationFactor;
+ }
+ }
+ for (int i = s_blockSize - 1; i > 0; --i) {
+ int k = paintingData.latticeSelector[i];
+ int j = paintingData.random() % s_blockSize;
+ ASSERT(j >= 0);
+ ASSERT(j < 2 * s_blockSize + 2);
+ paintingData.latticeSelector[i] = paintingData.latticeSelector[j];
+ paintingData.latticeSelector[j] = k;
+ }
+ for (int i = 0; i < s_blockSize + 2; ++i) {
+ paintingData.latticeSelector[s_blockSize + i] = paintingData.latticeSelector[i];
+ for (int channel = 0; channel < 4; ++channel) {
+ paintingData.gradient[channel][s_blockSize + i][0] = paintingData.gradient[channel][i][0];
+ paintingData.gradient[channel][s_blockSize + i][1] = paintingData.gradient[channel][i][1];
+ }
+ }
+}
+
+inline void checkNoise(int& noiseValue, int limitValue, int newValue)
+{
+ if (noiseValue >= limitValue)
+ noiseValue -= newValue;
+ if (noiseValue >= limitValue - 1)
+ noiseValue -= newValue - 1;
+}
+
+float FETurbulence::noise2D(PaintingData& paintingData, const FloatPoint& noiseVector)
+{
+ struct Noise {
+ int noisePositionIntegerValue;
+ float noisePositionFractionValue;
+
+ Noise(float component)
+ {
+ float position = component + s_perlinNoise;
+ noisePositionIntegerValue = static_cast<int>(position);
+ noisePositionFractionValue = position - noisePositionIntegerValue;
+ }
+ };
+
+ Noise noiseX(noiseVector.x());
+ Noise noiseY(noiseVector.y());
+ float* q;
+ float sx, sy, a, b, u, v;
+
+ // If stitching, adjust lattice points accordingly.
+ if (m_stitchTiles) {
+ checkNoise(noiseX.noisePositionIntegerValue, paintingData.wrapX, paintingData.width);
+ checkNoise(noiseY.noisePositionIntegerValue, paintingData.wrapY, paintingData.height);
+ }
+
+ noiseX.noisePositionIntegerValue &= s_blockMask;
+ noiseY.noisePositionIntegerValue &= s_blockMask;
+ int latticeIndex = paintingData.latticeSelector[noiseX.noisePositionIntegerValue];
+ int nextLatticeIndex = paintingData.latticeSelector[(noiseX.noisePositionIntegerValue + 1) & s_blockMask];
+
+ sx = smoothCurve(noiseX.noisePositionFractionValue);
+ sy = smoothCurve(noiseY.noisePositionFractionValue);
+
+ // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
+ int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
+ q = paintingData.gradient[paintingData.channel][temp];
+ u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
+ temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
+ q = paintingData.gradient[paintingData.channel][temp];
+ v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1];
+ a = linearInterpolation(sx, u, v);
+ temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1];
+ q = paintingData.gradient[paintingData.channel][temp];
+ u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
+ temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1];
+ q = paintingData.gradient[paintingData.channel][temp];
+ v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
+ b = linearInterpolation(sx, u, v);
+ return linearInterpolation(sy, a, b);
+}
+
+unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paintingData, const FloatPoint& point)
+{
+ float tileWidth = paintingData.filterSize.width();
+ ASSERT(tileWidth > 0);
+ float tileHeight = paintingData.filterSize.height();
+ ASSERT(tileHeight > 0);
+ // Adjust the base frequencies if necessary for stitching.
+ if (m_stitchTiles) {
+ // When stitching tiled turbulence, the frequencies must be adjusted
+ // so that the tile borders will be continuous.
+ if (m_baseFrequencyX) {
+ float lowFrequency = floorf(tileWidth * m_baseFrequencyX) / tileWidth;
+ float highFrequency = ceilf(tileWidth * m_baseFrequencyX) / tileWidth;
+ // BaseFrequency should be non-negative according to the standard.
+ if (m_baseFrequencyX / lowFrequency < highFrequency / m_baseFrequencyX)
+ m_baseFrequencyX = lowFrequency;
+ else
+ m_baseFrequencyX = highFrequency;
+ }
+ if (m_baseFrequencyY) {
+ float lowFrequency = floorf(tileHeight * m_baseFrequencyY) / tileHeight;
+ float highFrequency = ceilf(tileHeight * m_baseFrequencyY) / tileHeight;
+ if (m_baseFrequencyY / lowFrequency < highFrequency / m_baseFrequencyY)
+ m_baseFrequencyY = lowFrequency;
+ else
+ m_baseFrequencyY = highFrequency;
+ }
+ // Set up TurbulenceInitial stitch values.
+ paintingData.width = roundf(tileWidth * m_baseFrequencyX);
+ paintingData.wrapX = s_perlinNoise + paintingData.width;
+ paintingData.height = roundf(tileHeight * m_baseFrequencyY);
+ paintingData.wrapY = s_perlinNoise + paintingData.height;
+ }
+ float turbulenceFunctionResult = 0;
+ FloatPoint noiseVector(point.x() * m_baseFrequencyX, point.y() * m_baseFrequencyY);
+ float ratio = 1;
+ for (int octave = 0; octave < m_numOctaves; ++octave) {
+ if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
+ turbulenceFunctionResult += noise2D(paintingData, noiseVector) / ratio;
+ else
+ turbulenceFunctionResult += fabsf(noise2D(paintingData, noiseVector)) / ratio;
+ noiseVector.setX(noiseVector.x() * 2);
+ noiseVector.setY(noiseVector.y() * 2);
+ ratio *= 2;
+ if (m_stitchTiles) {
+ // Update stitch values. Subtracting s_perlinNoiseoise before the multiplication and
+ // adding it afterward simplifies to subtracting it once.
+ paintingData.width *= 2;
+ paintingData.wrapX = 2 * paintingData.wrapX - s_perlinNoise;
+ paintingData.height *= 2;
+ paintingData.wrapY = 2 * paintingData.wrapY - s_perlinNoise;
+ }
+ }
+
+ // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult * 255) + 255) / 2 by fractalNoise
+ // and (turbulenceFunctionResult * 255) by turbulence.
+ if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
+ turbulenceFunctionResult = turbulenceFunctionResult * 0.5f + 0.5f;
+ // Clamp result
+ turbulenceFunctionResult = std::max(std::min(turbulenceFunctionResult, 1.f), 0.f);
+ return static_cast<unsigned char>(turbulenceFunctionResult * 255);
+}
+
+void FETurbulence::apply()
+{
+ if (hasResult())
+ return;
+ ByteArray* pixelArray = createUnmultipliedImageResult();
+ if (!pixelArray)
+ return;
+
+ if (absolutePaintRect().isEmpty())
+ return;
+
+ PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size()));
+ initPaint(paintingData);
+
+ FloatRect filterRegion = absolutePaintRect();
+ FloatPoint point;
+ point.setY(filterRegion.y());
+ int indexOfPixelChannel = 0;
+ for (int y = 0; y < absolutePaintRect().height(); ++y) {
+ point.setY(point.y() + 1);
+ point.setX(filterRegion.x());
+ for (int x = 0; x < absolutePaintRect().width(); ++x) {
+ point.setX(point.x() + 1);
+ for (paintingData.channel = 0; paintingData.channel < 4; ++paintingData.channel, ++indexOfPixelChannel)
+ pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, filter()->mapAbsolutePointToLocalPoint(point)));
+ }
+ }
+}
+
+void FETurbulence::dump()
+{
+}
+
+static TextStream& operator<<(TextStream& ts, const TurbulanceType& type)
+{
+ switch (type) {
+ case FETURBULENCE_TYPE_UNKNOWN:
+ ts << "UNKNOWN";
+ break;
+ case FETURBULENCE_TYPE_TURBULENCE:
+ ts << "TURBULANCE";
+ break;
+ case FETURBULENCE_TYPE_FRACTALNOISE:
+ ts << "NOISE";
+ break;
+ }
+ return ts;
+}
+
+TextStream& FETurbulence::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[feTurbulence";
+ FilterEffect::externalRepresentation(ts);
+ ts << " type=\"" << type() << "\" "
+ << "baseFrequency=\"" << baseFrequencyX() << ", " << baseFrequencyY() << "\" "
+ << "seed=\"" << seed() << "\" "
+ << "numOctaves=\"" << numOctaves() << "\" "
+ << "stitchTiles=\"" << stitchTiles() << "\"]\n";
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FETurbulence.h b/Source/WebCore/platform/graphics/filters/FETurbulence.h
new file mode 100644
index 0000000..1bad123
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FETurbulence.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FETurbulence_h
+#define FETurbulence_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+#include "Filter.h"
+
+namespace WebCore {
+
+enum TurbulanceType {
+ FETURBULENCE_TYPE_UNKNOWN = 0,
+ FETURBULENCE_TYPE_FRACTALNOISE = 1,
+ FETURBULENCE_TYPE_TURBULENCE = 2
+};
+
+class FETurbulence : public FilterEffect {
+public:
+ static PassRefPtr<FETurbulence> create(Filter*, TurbulanceType, float, float, int, float, bool);
+
+ TurbulanceType type() const;
+ void setType(TurbulanceType);
+
+ float baseFrequencyY() const;
+ void setBaseFrequencyY(float);
+
+ float baseFrequencyX() const;
+ void setBaseFrequencyX(float);
+
+ float seed() const;
+ void setSeed(float);
+
+ int numOctaves() const;
+ void setNumOctaves(bool);
+
+ bool stitchTiles() const;
+ void setStitchTiles(bool);
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(maxEffectRect()); }
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ static const int s_blockSize = 256;
+ static const int s_blockMask = s_blockSize - 1;
+
+ struct PaintingData {
+ long seed;
+ int latticeSelector[2 * s_blockSize + 2];
+ float gradient[4][2 * s_blockSize + 2][2];
+ int width; // How much to subtract to wrap for stitching.
+ int height;
+ int wrapX; // Minimum value to wrap.
+ int wrapY;
+ int channel;
+ IntSize filterSize;
+
+ PaintingData(long paintingSeed, const IntSize& paintingSize);
+ inline long random();
+ };
+
+ FETurbulence(Filter*, TurbulanceType, float, float, int, float, bool);
+
+ inline void initPaint(PaintingData&);
+ float noise2D(PaintingData&, const FloatPoint&);
+ unsigned char calculateTurbulenceValueForPoint(PaintingData&, const FloatPoint&);
+
+ TurbulanceType m_type;
+ float m_baseFrequencyX;
+ float m_baseFrequencyY;
+ int m_numOctaves;
+ float m_seed;
+ bool m_stitchTiles;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FETurbulence_h
diff --git a/Source/WebCore/platform/graphics/filters/Filter.h b/Source/WebCore/platform/graphics/filters/Filter.h
new file mode 100644
index 0000000..33cf724
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/Filter.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef Filter_h
+#define Filter_h
+
+#if ENABLE(FILTERS)
+#include "FloatRect.h"
+#include "FloatSize.h"
+#include "ImageBuffer.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+ class FilterEffect;
+
+ class Filter : public RefCounted<Filter> {
+ public:
+ virtual ~Filter() { }
+
+ void setSourceImage(PassOwnPtr<ImageBuffer> sourceImage) { m_sourceImage = sourceImage; }
+ ImageBuffer* sourceImage() { return m_sourceImage.get(); }
+
+ FloatSize filterResolution() const { return m_filterResolution; }
+ void setFilterResolution(const FloatSize& filterResolution) { m_filterResolution = filterResolution; }
+
+ virtual float applyHorizontalScale(float value) const { return value * m_filterResolution.width(); }
+ virtual float applyVerticalScale(float value) const { return value * m_filterResolution.height(); }
+
+ virtual FloatRect sourceImageRect() const = 0;
+ virtual FloatRect filterRegion() const = 0;
+
+ virtual FloatPoint mapAbsolutePointToLocalPoint(const FloatPoint&) const { return FloatPoint(); }
+
+ virtual FloatRect filterRegionInUserSpace() const { return FloatRect(); }
+
+ virtual bool effectBoundingBoxMode() const = 0;
+
+ private:
+ OwnPtr<ImageBuffer> m_sourceImage;
+ FloatSize m_filterResolution;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // Filter_h
diff --git a/Source/WebCore/platform/graphics/filters/FilterEffect.cpp b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp
new file mode 100644
index 0000000..05c2a47
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+
+#include <wtf/ByteArray.h>
+
+namespace WebCore {
+
+FilterEffect::FilterEffect(Filter* filter)
+ : m_alphaImage(false)
+ , m_filter(filter)
+ , m_hasX(false)
+ , m_hasY(false)
+ , m_hasWidth(false)
+ , m_hasHeight(false)
+{
+ ASSERT(m_filter);
+}
+
+FilterEffect::~FilterEffect()
+{
+}
+
+void FilterEffect::determineAbsolutePaintRect()
+{
+ m_absolutePaintRect = IntRect();
+ unsigned size = m_inputEffects.size();
+ for (unsigned i = 0; i < size; ++i)
+ m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect());
+
+ // SVG specification wants us to clip to primitive subregion.
+ m_absolutePaintRect.intersect(m_maxEffectRect);
+}
+
+IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const
+{
+ ASSERT(hasResult());
+ IntPoint location = m_absolutePaintRect.location();
+ location.move(-effectRect.x(), -effectRect.y());
+ return IntRect(location, m_absolutePaintRect.size());
+}
+
+IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
+{
+ return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(),
+ srcRect.y() - m_absolutePaintRect.y()), srcRect.size());
+}
+
+FilterEffect* FilterEffect::inputEffect(unsigned number) const
+{
+ ASSERT(number < m_inputEffects.size());
+ return m_inputEffects.at(number).get();
+}
+
+ImageBuffer* FilterEffect::asImageBuffer()
+{
+ if (!hasResult())
+ return 0;
+ if (m_imageBufferResult)
+ return m_imageBufferResult.get();
+ m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
+ IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
+ if (m_premultipliedImageResult)
+ m_imageBufferResult->putPremultipliedImageData(m_premultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
+ else
+ m_imageBufferResult->putUnmultipliedImageData(m_unmultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
+ return m_imageBufferResult.get();
+}
+
+PassRefPtr<ByteArray> FilterEffect::asUnmultipliedImage(const IntRect& rect)
+{
+ RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
+ copyUnmultipliedImage(imageData.get(), rect);
+ return imageData.release();
+}
+
+PassRefPtr<ByteArray> FilterEffect::asPremultipliedImage(const IntRect& rect)
+{
+ RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
+ copyPremultipliedImage(imageData.get(), rect);
+ return imageData.release();
+}
+
+inline void FilterEffect::copyImageBytes(ByteArray* source, ByteArray* destination, const IntRect& rect)
+{
+ // Copy the necessary lines.
+ if (rect.x() < 0 || rect.y() < 0 || rect.bottom() > m_absolutePaintRect.width() || rect.bottom() > m_absolutePaintRect.height())
+ memset(destination->data(), 0, destination->length());
+
+ int xOrigin = rect.x();
+ int xDest = 0;
+ if (xOrigin < 0) {
+ xDest = -xOrigin;
+ xOrigin = 0;
+ }
+ int xEnd = rect.right();
+ if (xEnd > m_absolutePaintRect.width())
+ xEnd = m_absolutePaintRect.width();
+
+ int yOrigin = rect.y();
+ int yDest = 0;
+ if (yOrigin < 0) {
+ yDest = -yOrigin;
+ yOrigin = 0;
+ }
+ int yEnd = rect.bottom();
+ if (yEnd > m_absolutePaintRect.height())
+ yEnd = m_absolutePaintRect.height();
+
+ int size = (xEnd - xOrigin) * 4;
+ int destinationScanline = rect.width() * 4;
+ int sourceScanline = m_absolutePaintRect.width() * 4;
+ unsigned char *destinationPixel = destination->data() + ((yDest * rect.width()) + xDest) * 4;
+ unsigned char *sourcePixel = source->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4;
+
+ while (yOrigin < yEnd) {
+ memcpy(destinationPixel, sourcePixel, size);
+ destinationPixel += destinationScanline;
+ sourcePixel += sourceScanline;
+ ++yOrigin;
+ }
+}
+
+void FilterEffect::copyUnmultipliedImage(ByteArray* destination, const IntRect& rect)
+{
+ ASSERT(hasResult());
+
+ if (!m_unmultipliedImageResult) {
+ // We prefer a conversion from the image buffer.
+ if (m_imageBufferResult)
+ m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
+ else {
+ m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ unsigned char* sourceComponent = m_premultipliedImageResult->data();
+ unsigned char* destinationComponent = m_unmultipliedImageResult->data();
+ unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ while (sourceComponent < end) {
+ int alpha = sourceComponent[3];
+ if (alpha) {
+ destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha;
+ destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha;
+ destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha;
+ } else {
+ destinationComponent[0] = 0;
+ destinationComponent[1] = 0;
+ destinationComponent[2] = 0;
+ }
+ destinationComponent[3] = alpha;
+ sourceComponent += 4;
+ destinationComponent += 4;
+ }
+ }
+ }
+ copyImageBytes(m_unmultipliedImageResult.get(), destination, rect);
+}
+
+void FilterEffect::copyPremultipliedImage(ByteArray* destination, const IntRect& rect)
+{
+ ASSERT(hasResult());
+
+ if (!m_premultipliedImageResult) {
+ // We prefer a conversion from the image buffer.
+ if (m_imageBufferResult)
+ m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
+ else {
+ m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ unsigned char* sourceComponent = m_unmultipliedImageResult->data();
+ unsigned char* destinationComponent = m_premultipliedImageResult->data();
+ unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ while (sourceComponent < end) {
+ int alpha = sourceComponent[3];
+ destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
+ destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255;
+ destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255;
+ destinationComponent[3] = alpha;
+ sourceComponent += 4;
+ destinationComponent += 4;
+ }
+ }
+ }
+ copyImageBytes(m_premultipliedImageResult.get(), destination, rect);
+}
+
+ImageBuffer* FilterEffect::createImageBufferResult()
+{
+ // Only one result type is allowed.
+ ASSERT(!hasResult());
+ determineAbsolutePaintRect();
+ if (m_absolutePaintRect.isEmpty())
+ return 0;
+ m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
+ if (!m_imageBufferResult)
+ return 0;
+ ASSERT(m_imageBufferResult->context());
+ return m_imageBufferResult.get();
+}
+
+ByteArray* FilterEffect::createUnmultipliedImageResult()
+{
+ // Only one result type is allowed.
+ ASSERT(!hasResult());
+ determineAbsolutePaintRect();
+ if (m_absolutePaintRect.isEmpty())
+ return 0;
+ m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ return m_unmultipliedImageResult.get();
+}
+
+ByteArray* FilterEffect::createPremultipliedImageResult()
+{
+ // Only one result type is allowed.
+ ASSERT(!hasResult());
+ determineAbsolutePaintRect();
+ if (m_absolutePaintRect.isEmpty())
+ return 0;
+ m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ return m_premultipliedImageResult.get();
+}
+
+TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
+{
+ // FIXME: We should dump the subRegions of the filter primitives here later. This isn't
+ // possible at the moment, because we need more detailed informations from the target object.
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/FilterEffect.h b/Source/WebCore/platform/graphics/filters/FilterEffect.h
new file mode 100644
index 0000000..2554d4b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/FilterEffect.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FilterEffect_h
+#define FilterEffect_h
+
+#if ENABLE(FILTERS)
+#include "Filter.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "RenderTreeAsText.h"
+#include "TextStream.h"
+
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+typedef Vector<RefPtr<FilterEffect> > FilterEffectVector;
+
+enum FilterEffectType {
+ FilterEffectTypeUnknown,
+ FilterEffectTypeImage,
+ FilterEffectTypeTile,
+ FilterEffectTypeSourceInput
+};
+
+class FilterEffect : public RefCounted<FilterEffect> {
+public:
+ virtual ~FilterEffect();
+
+ bool hasResult() const { return m_imageBufferResult || m_unmultipliedImageResult || m_premultipliedImageResult; }
+ ImageBuffer* asImageBuffer();
+ PassRefPtr<ByteArray> asUnmultipliedImage(const IntRect&);
+ PassRefPtr<ByteArray> asPremultipliedImage(const IntRect&);
+ void copyUnmultipliedImage(ByteArray* destination, const IntRect&);
+ void copyPremultipliedImage(ByteArray* destination, const IntRect&);
+
+ FilterEffectVector& inputEffects() { return m_inputEffects; }
+ FilterEffect* inputEffect(unsigned) const;
+ unsigned numberOfEffectInputs() const { return m_inputEffects.size(); }
+
+ IntRect drawingRegionOfInputImage(const IntRect&) const;
+ IntRect requestedRegionOfInputImageData(const IntRect&) const;
+
+ // Solid black image with different alpha values.
+ bool isAlphaImage() const { return m_alphaImage; }
+ void setIsAlphaImage(bool alphaImage) { m_alphaImage = alphaImage; }
+
+ IntRect absolutePaintRect() const { return m_absolutePaintRect; }
+ void setAbsolutePaintRect(const IntRect& absolutePaintRect) { m_absolutePaintRect = absolutePaintRect; }
+
+ IntRect maxEffectRect() const { return m_maxEffectRect; }
+ void setMaxEffectRect(const IntRect& maxEffectRect) { m_maxEffectRect = maxEffectRect; }
+
+ virtual void apply() = 0;
+ virtual void dump() = 0;
+
+ virtual void determineAbsolutePaintRect();
+
+ virtual FilterEffectType filterEffectType() const { return FilterEffectTypeUnknown; }
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention = 0) const;
+
+public:
+ // The following functions are SVG specific and will move to RenderSVGResourceFilterPrimitive.
+ // See bug https://bugs.webkit.org/show_bug.cgi?id=45614.
+ bool hasX() const { return m_hasX; }
+ void setHasX(bool value) { m_hasX = value; }
+
+ bool hasY() const { return m_hasY; }
+ void setHasY(bool value) { m_hasY = value; }
+
+ bool hasWidth() const { return m_hasWidth; }
+ void setHasWidth(bool value) { m_hasWidth = value; }
+
+ bool hasHeight() const { return m_hasHeight; }
+ void setHasHeight(bool value) { m_hasHeight = value; }
+
+ FloatRect filterPrimitiveSubregion() const { return m_filterPrimitiveSubregion; }
+ void setFilterPrimitiveSubregion(const FloatRect& filterPrimitiveSubregion) { m_filterPrimitiveSubregion = filterPrimitiveSubregion; }
+
+ FloatRect effectBoundaries() const { return m_effectBoundaries; }
+ void setEffectBoundaries(const FloatRect& effectBoundaries) { m_effectBoundaries = effectBoundaries; }
+
+ Filter* filter() { return m_filter; }
+
+protected:
+ FilterEffect(Filter*);
+
+ ImageBuffer* createImageBufferResult();
+ ByteArray* createUnmultipliedImageResult();
+ ByteArray* createPremultipliedImageResult();
+
+private:
+ OwnPtr<ImageBuffer> m_imageBufferResult;
+ RefPtr<ByteArray> m_unmultipliedImageResult;
+ RefPtr<ByteArray> m_premultipliedImageResult;
+ FilterEffectVector m_inputEffects;
+
+ bool m_alphaImage;
+
+ IntRect m_absolutePaintRect;
+
+ // The maximum size of a filter primitive. In SVG this is the primitive subregion in absolute coordinate space.
+ // The absolute paint rect should never be bigger than m_maxEffectRect.
+ IntRect m_maxEffectRect;
+ Filter* m_filter;
+
+private:
+ inline void copyImageBytes(ByteArray* source, ByteArray* destination, const IntRect&);
+
+ // The following member variables are SVG specific and will move to RenderSVGResourceFilterPrimitive.
+ // See bug https://bugs.webkit.org/show_bug.cgi?id=45614.
+
+ // The subregion of a filter primitive according to the SVG Filter specification in local coordinates.
+ // This is SVG specific and needs to move to RenderSVGResourceFilterPrimitive.
+ FloatRect m_filterPrimitiveSubregion;
+
+ // x, y, width and height of the actual SVGFE*Element. Is needed to determine the subregion of the
+ // filter primitive on a later step.
+ FloatRect m_effectBoundaries;
+ bool m_hasX;
+ bool m_hasY;
+ bool m_hasWidth;
+ bool m_hasHeight;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FilterEffect_h
diff --git a/Source/WebCore/platform/graphics/filters/LightSource.cpp b/Source/WebCore/platform/graphics/filters/LightSource.cpp
new file mode 100644
index 0000000..de0691e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/LightSource.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "LightSource.h"
+
+#include "DistantLightSource.h"
+#include "PointLightSource.h"
+#include "RenderTreeAsText.h"
+#include "SpotLightSource.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+void PointLightSource::initPaintingData(PaintingData&)
+{
+}
+
+void PointLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z)
+{
+ paintingData.lightVector.setX(m_position.x() - x);
+ paintingData.lightVector.setY(m_position.y() - y);
+ paintingData.lightVector.setZ(m_position.z() - z);
+ paintingData.lightVectorLength = paintingData.lightVector.length();
+}
+
+// spot-light edge darkening depends on an absolute treshold
+// according to the SVG 1.1 SE light regression tests
+static const float antiAliasTreshold = 0.016f;
+
+void SpotLightSource::initPaintingData(PaintingData& paintingData)
+{
+ paintingData.privateColorVector = paintingData.colorVector;
+ paintingData.directionVector.setX(m_direction.x() - m_position.x());
+ paintingData.directionVector.setY(m_direction.y() - m_position.y());
+ paintingData.directionVector.setZ(m_direction.z() - m_position.z());
+ paintingData.directionVector.normalize();
+
+ if (!m_limitingConeAngle) {
+ paintingData.coneCutOffLimit = 0.0f;
+ paintingData.coneFullLight = -antiAliasTreshold;
+ } else {
+ float limitingConeAngle = m_limitingConeAngle;
+ if (limitingConeAngle < 0.0f)
+ limitingConeAngle = -limitingConeAngle;
+ if (limitingConeAngle > 90.0f)
+ limitingConeAngle = 90.0f;
+ paintingData.coneCutOffLimit = cosf(deg2rad(180.0f - limitingConeAngle));
+ paintingData.coneFullLight = paintingData.coneCutOffLimit - antiAliasTreshold;
+ }
+
+ // Optimization for common specularExponent values
+ if (!m_specularExponent)
+ paintingData.specularExponent = 0;
+ else if (m_specularExponent == 1.0f)
+ paintingData.specularExponent = 1;
+ else // It is neither 0.0f nor 1.0f
+ paintingData.specularExponent = 2;
+}
+
+void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z)
+{
+ paintingData.lightVector.setX(m_position.x() - x);
+ paintingData.lightVector.setY(m_position.y() - y);
+ paintingData.lightVector.setZ(m_position.z() - z);
+ paintingData.lightVectorLength = paintingData.lightVector.length();
+
+ float cosineOfAngle = (paintingData.lightVector * paintingData.directionVector) / paintingData.lightVectorLength;
+ if (cosineOfAngle > paintingData.coneCutOffLimit) {
+ // No light is produced, scanlines are not updated
+ paintingData.colorVector.setX(0.0f);
+ paintingData.colorVector.setY(0.0f);
+ paintingData.colorVector.setZ(0.0f);
+ return;
+ }
+
+ // Set the color of the pixel
+ float lightStrength;
+ switch (paintingData.specularExponent) {
+ case 0:
+ lightStrength = 1.0f; // -cosineOfAngle ^ 0 == 1
+ break;
+ case 1:
+ lightStrength = -cosineOfAngle; // -cosineOfAngle ^ 1 == -cosineOfAngle
+ break;
+ default:
+ lightStrength = powf(-cosineOfAngle, m_specularExponent);
+ break;
+ }
+
+ if (cosineOfAngle > paintingData.coneFullLight)
+ lightStrength *= (paintingData.coneCutOffLimit - cosineOfAngle) / (paintingData.coneCutOffLimit - paintingData.coneFullLight);
+
+ if (lightStrength > 1.0f)
+ lightStrength = 1.0f;
+
+ paintingData.colorVector.setX(paintingData.privateColorVector.x() * lightStrength);
+ paintingData.colorVector.setY(paintingData.privateColorVector.y() * lightStrength);
+ paintingData.colorVector.setZ(paintingData.privateColorVector.z() * lightStrength);
+}
+
+void DistantLightSource::initPaintingData(PaintingData& paintingData)
+{
+ float azimuth = deg2rad(m_azimuth);
+ float elevation = deg2rad(m_elevation);
+ paintingData.lightVector.setX(cosf(azimuth) * cosf(elevation));
+ paintingData.lightVector.setY(sinf(azimuth) * cosf(elevation));
+ paintingData.lightVector.setZ(sinf(elevation));
+ paintingData.lightVectorLength = 1;
+}
+
+void DistantLightSource::updatePaintingData(PaintingData&, int, int, float)
+{
+}
+
+static TextStream& operator<<(TextStream& ts, const FloatPoint3D& p)
+{
+ ts << "x=" << p.x() << " y=" << p.y() << " z=" << p.z();
+ return ts;
+}
+
+TextStream& PointLightSource::externalRepresentation(TextStream& ts) const
+{
+ ts << "[type=POINT-LIGHT] ";
+ ts << "[position=\"" << position() << "\"]";
+ return ts;
+}
+
+TextStream& SpotLightSource::externalRepresentation(TextStream& ts) const
+{
+ ts << "[type=SPOT-LIGHT] ";
+ ts << "[position=\"" << position() << "\"]";
+ ts << "[direction=\"" << direction() << "\"]";
+ ts << "[specularExponent=\"" << specularExponent() << "\"]";
+ ts << "[limitingConeAngle=\"" << limitingConeAngle() << "\"]";
+ return ts;
+}
+
+TextStream& DistantLightSource::externalRepresentation(TextStream& ts) const
+{
+ ts << "[type=DISTANT-LIGHT] ";
+ ts << "[azimuth=\"" << azimuth() << "\"]";
+ ts << "[elevation=\"" << elevation() << "\"]";
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/LightSource.h b/Source/WebCore/platform/graphics/filters/LightSource.h
new file mode 100644
index 0000000..013e910
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/LightSource.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef LightSource_h
+#define LightSource_h
+
+#if ENABLE(FILTERS)
+#include "FloatPoint3D.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+enum LightType {
+ LS_DISTANT,
+ LS_POINT,
+ LS_SPOT
+};
+
+class TextStream;
+
+class LightSource : public RefCounted<LightSource> {
+public:
+
+ // Light vectors must be calculated for every pixel during
+ // painting. It is expensive to pass all these arguments to
+ // a frequently called function, especially because not all
+ // light sources require all of them. Instead, we just pass
+ // a reference to the following structure
+ struct PaintingData {
+ // SVGFELighting also use them
+ FloatPoint3D lightVector;
+ FloatPoint3D colorVector;
+ float lightVectorLength;
+ // Private members
+ FloatPoint3D directionVector;
+ FloatPoint3D privateColorVector;
+ float coneCutOffLimit;
+ float coneFullLight;
+ int specularExponent;
+ };
+
+ LightSource(LightType type)
+ : m_type(type)
+ { }
+
+ virtual ~LightSource() { }
+
+ LightType type() const { return m_type; }
+ virtual TextStream& externalRepresentation(TextStream&) const = 0;
+
+ virtual void initPaintingData(PaintingData&) = 0;
+ // z is a float number, since it is the alpha value scaled by a user
+ // specified "surfaceScale" constant, which type is <number> in the SVG standard
+ virtual void updatePaintingData(PaintingData&, int x, int y, float z) = 0;
+
+private:
+ LightType m_type;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // LightSource_h
diff --git a/Source/WebCore/platform/graphics/filters/PointLightSource.h b/Source/WebCore/platform/graphics/filters/PointLightSource.h
new file mode 100644
index 0000000..163c829
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/PointLightSource.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PointLightSource_h
+#define PointLightSource_h
+
+#if ENABLE(FILTERS)
+#include "LightSource.h"
+
+namespace WebCore {
+
+class PointLightSource : public LightSource {
+public:
+ static PassRefPtr<PointLightSource> create(const FloatPoint3D& position)
+ {
+ return adoptRef(new PointLightSource(position));
+ }
+
+ const FloatPoint3D& position() const { return m_position; }
+
+ virtual void initPaintingData(PaintingData&);
+ virtual void updatePaintingData(PaintingData&, int x, int y, float z);
+
+ virtual TextStream& externalRepresentation(TextStream&) const;
+
+private:
+ PointLightSource(const FloatPoint3D& position)
+ : LightSource(LS_POINT)
+ , m_position(position)
+ {
+ }
+
+ FloatPoint3D m_position;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // PointLightSource_h
diff --git a/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp b/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp
new file mode 100644
index 0000000..2d2de00
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "SourceAlpha.h"
+
+#include "Color.h"
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include "Filter.h"
+
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+PassRefPtr<SourceAlpha> SourceAlpha::create(Filter* filter)
+{
+ return adoptRef(new SourceAlpha(filter));
+}
+
+const AtomicString& SourceAlpha::effectName()
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, s_effectName, ("SourceAlpha"));
+ return s_effectName;
+}
+
+void SourceAlpha::determineAbsolutePaintRect()
+{
+ Filter* filter = this->filter();
+ FloatRect paintRect = filter->sourceImageRect();
+ paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
+ setAbsolutePaintRect(enclosingIntRect(paintRect));
+}
+
+void SourceAlpha::apply()
+{
+ if (hasResult())
+ return;
+ ImageBuffer* resultImage = createImageBufferResult();
+ Filter* filter = this->filter();
+ if (!resultImage || !filter->sourceImage())
+ return;
+
+ setIsAlphaImage(true);
+
+ FloatRect imageRect(FloatPoint(), absolutePaintRect().size());
+ GraphicsContext* filterContext = resultImage->context();
+ filterContext->save();
+ filterContext->clipToImageBuffer(filter->sourceImage(), imageRect);
+ filterContext->fillRect(imageRect, Color::black, ColorSpaceDeviceRGB);
+ filterContext->restore();
+}
+
+void SourceAlpha::dump()
+{
+}
+
+TextStream& SourceAlpha::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[SourceAlpha]\n";
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/SourceAlpha.h b/Source/WebCore/platform/graphics/filters/SourceAlpha.h
new file mode 100644
index 0000000..c6f95d3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/SourceAlpha.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SourceAlpha_h
+#define SourceAlpha_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+
+#include "PlatformString.h"
+#include "Filter.h"
+
+namespace WebCore {
+
+class SourceAlpha : public FilterEffect {
+public:
+ static PassRefPtr<SourceAlpha> create(Filter*);
+
+ static const AtomicString& effectName();
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect();
+
+ virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; }
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ SourceAlpha(Filter* filter)
+ : FilterEffect(filter)
+ {
+ }
+};
+
+} //namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // SourceAlpha_h
diff --git a/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp b/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp
new file mode 100644
index 0000000..04082ad
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "SourceGraphic.h"
+
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include "Filter.h"
+
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+PassRefPtr<SourceGraphic> SourceGraphic::create(Filter* filter)
+{
+ return adoptRef(new SourceGraphic(filter));
+}
+
+const AtomicString& SourceGraphic::effectName()
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, s_effectName, ("SourceGraphic"));
+ return s_effectName;
+}
+
+void SourceGraphic::determineAbsolutePaintRect()
+{
+ Filter* filter = this->filter();
+ FloatRect paintRect = filter->sourceImageRect();
+ paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
+ setAbsolutePaintRect(enclosingIntRect(paintRect));
+}
+
+void SourceGraphic::apply()
+{
+ if (hasResult())
+ return;
+ ImageBuffer* resultImage = createImageBufferResult();
+ Filter* filter = this->filter();
+ if (!resultImage || !filter->sourceImage())
+ return;
+
+ resultImage->context()->drawImageBuffer(filter->sourceImage(), ColorSpaceDeviceRGB, IntPoint());
+}
+
+void SourceGraphic::dump()
+{
+}
+
+TextStream& SourceGraphic::externalRepresentation(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "[SourceGraphic]\n";
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/Source/WebCore/platform/graphics/filters/SourceGraphic.h b/Source/WebCore/platform/graphics/filters/SourceGraphic.h
new file mode 100644
index 0000000..97d6882
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/SourceGraphic.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SourceGraphic_h
+#define SourceGraphic_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+
+#include "Filter.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class SourceGraphic : public FilterEffect {
+public:
+ static PassRefPtr<SourceGraphic> create(Filter*);
+
+ static const AtomicString& effectName();
+
+ virtual void apply();
+ virtual void dump();
+
+ virtual void determineAbsolutePaintRect();
+
+ virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; }
+
+ virtual TextStream& externalRepresentation(TextStream&, int indention) const;
+
+private:
+ SourceGraphic(Filter* filter)
+ : FilterEffect(filter)
+ {
+ }
+};
+
+} //namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // SourceGraphic_h
diff --git a/Source/WebCore/platform/graphics/filters/SpotLightSource.h b/Source/WebCore/platform/graphics/filters/SpotLightSource.h
new file mode 100644
index 0000000..cd6a614
--- /dev/null
+++ b/Source/WebCore/platform/graphics/filters/SpotLightSource.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SpotLightSource_h
+#define SpotLightSource_h
+
+#if ENABLE(FILTERS)
+#include "LightSource.h"
+
+namespace WebCore {
+
+class SpotLightSource : public LightSource {
+public:
+ static PassRefPtr<SpotLightSource> create(const FloatPoint3D& position,
+ const FloatPoint3D& direction, float specularExponent, float limitingConeAngle)
+ {
+ return adoptRef(new SpotLightSource(position, direction, specularExponent, limitingConeAngle));
+ }
+
+ const FloatPoint3D& position() const { return m_position; }
+ const FloatPoint3D& direction() const { return m_direction; }
+
+ float specularExponent() const { return m_specularExponent; }
+ float limitingConeAngle() const { return m_limitingConeAngle; }
+
+ virtual void initPaintingData(PaintingData&);
+ virtual void updatePaintingData(PaintingData&, int x, int y, float z);
+
+ virtual TextStream& externalRepresentation(TextStream&) const;
+
+private:
+ SpotLightSource(const FloatPoint3D& position, const FloatPoint3D& direction,
+ float specularExponent, float limitingConeAngle)
+ : LightSource(LS_SPOT)
+ , m_position(position)
+ , m_direction(direction)
+ , m_specularExponent(specularExponent)
+ , m_limitingConeAngle(limitingConeAngle)
+ {
+ }
+
+ FloatPoint3D m_position;
+ FloatPoint3D m_direction;
+
+ float m_specularExponent;
+ float m_limitingConeAngle;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // SpotLightSource_h
diff --git a/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp b/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp
new file mode 100644
index 0000000..1430124
--- /dev/null
+++ b/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "CString.h"
+#include "Font.h"
+#include "OwnPtrCairo.h"
+#include "RefPtrCairo.h"
+#include "SimpleFontData.h"
+#include <cairo-ft.h>
+#include <cairo.h>
+#include <fontconfig/fcfreetype.h>
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+ // It's fine to call FcInit multiple times per the documentation.
+ if (!FcInit())
+ ASSERT_NOT_REACHED();
+}
+
+FcPattern* createFontConfigPatternForCharacters(const UChar* characters, int length)
+{
+ FcPattern* pattern = FcPatternCreate();
+
+ FcCharSet* fontConfigCharSet = FcCharSetCreate();
+ for (int i = 0; i < length; ++i) {
+ if (U16_IS_SURROGATE(characters[i]) && U16_IS_SURROGATE_LEAD(characters[i])
+ && i != length - 1 && U16_IS_TRAIL(characters[i + 1])) {
+ FcCharSetAddChar(fontConfigCharSet, U16_GET_SUPPLEMENTARY(characters[i], characters[i+1]));
+ i++;
+ } else
+ FcCharSetAddChar(fontConfigCharSet, characters[i]);
+ }
+ FcPatternAddCharSet(pattern, FC_CHARSET, fontConfigCharSet);
+ FcCharSetDestroy(fontConfigCharSet);
+
+ FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+ return pattern;
+}
+
+FcPattern* findBestFontGivenFallbacks(const FontPlatformData& fontData, FcPattern* pattern)
+{
+ if (!fontData.m_pattern)
+ return 0;
+
+ if (!fontData.m_fallbacks) {
+ FcResult fontConfigResult;
+ fontData.m_fallbacks = FcFontSort(0, fontData.m_pattern.get(), FcTrue, 0, &fontConfigResult);
+ }
+
+ if (!fontData.m_fallbacks)
+ return 0;
+
+ FcFontSet* sets[] = { fontData.m_fallbacks };
+ FcResult fontConfigResult;
+ return FcFontSetMatch(0, sets, 1, pattern, &fontConfigResult);
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ RefPtr<FcPattern> pattern = adoptRef(createFontConfigPatternForCharacters(characters, length));
+ const FontPlatformData& fontData = font.primaryFont()->platformData();
+
+ RefPtr<FcPattern> fallbackPattern = adoptRef(findBestFontGivenFallbacks(fontData, pattern.get()));
+ if (fallbackPattern) {
+ FontPlatformData alternateFontData(fallbackPattern.get(), font.fontDescription());
+ return getCachedFontData(&alternateFontData);
+ }
+
+ FcResult fontConfigResult;
+ RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(0, pattern.get(), &fontConfigResult));
+ if (!resultPattern)
+ return 0;
+ FontPlatformData alternateFontData(resultPattern.get(), font.fontDescription());
+ return getCachedFontData(&alternateFontData);
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ // We want to return a fallback font here, otherwise the logic preventing FontConfig
+ // matches for non-fallback fonts might return 0. See isFallbackFontAllowed.
+ static AtomicString timesStr("serif");
+ return getCachedFontData(fontDescription, timesStr);
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+}
+
+static String getFamilyNameStringFromFontDescriptionAndFamily(const FontDescription& fontDescription, const AtomicString& family)
+{
+ // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into
+ // the fallback name (like "monospace") that fontconfig understands.
+ if (family.length() && !family.startsWith("-webkit-"))
+ return family.string();
+
+ switch (fontDescription.genericFamily()) {
+ case FontDescription::StandardFamily:
+ case FontDescription::SerifFamily:
+ return "serif";
+ case FontDescription::SansSerifFamily:
+ return "sans-serif";
+ case FontDescription::MonospaceFamily:
+ return "monospace";
+ case FontDescription::CursiveFamily:
+ return "cursive";
+ case FontDescription::FantasyFamily:
+ return "fantasy";
+ case FontDescription::NoFamily:
+ default:
+ return "";
+ }
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ // The CSS font matching algorithm (http://www.w3.org/TR/css3-fonts/#font-matching-algorithm)
+ // says that we must find an exact match for font family, slant (italic or oblique can be used)
+ // and font weight (we only match bold/non-bold here).
+ RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
+ String familyNameString(getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family));
+ if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.utf8().data())))
+ return 0;
+
+ bool italic = fontDescription.italic();
+ if (!FcPatternAddInteger(pattern.get(), FC_SLANT, italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN))
+ return 0;
+ bool bold = fontDescription.weight() >= FontWeightBold;
+ if (!FcPatternAddInteger(pattern.get(), FC_WEIGHT, bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL))
+ return 0;
+ if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize()))
+ return 0;
+
+ // The strategy is originally from Skia (src/ports/SkFontHost_fontconfig.cpp):
+
+ // Allow Fontconfig to do pre-match substitution. Unless we are accessing a "fallback"
+ // family like "sans," this is the only time we allow Fontconfig to substitute one
+ // family name for another (i.e. if the fonts are aliased to each other).
+ FcConfigSubstitute(0, pattern.get(), FcMatchPattern);
+ FcDefaultSubstitute(pattern.get());
+
+ FcChar8* fontConfigFamilyNameAfterConfiguration;
+ FcPatternGetString(pattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration);
+ String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration));
+
+ FcResult fontConfigResult;
+ RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(0, pattern.get(), &fontConfigResult));
+ if (!resultPattern) // No match.
+ return 0;
+
+ FcChar8* fontConfigFamilyNameAfterMatching;
+ FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching);
+ String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching));
+
+ // If Fontconfig gave use a different font family than the one we requested, we should ignore it
+ // and allow WebCore to give us the next font on the CSS fallback list. The only exception is if
+ // this family name is a commonly used generic family.
+ if (!equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching)
+ && !(equalIgnoringCase(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif")
+ || equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace")
+ || equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive")))
+ return 0;
+
+ // Verify that this font has an encoding compatible with Fontconfig. Fontconfig currently
+ // supports three encodings in FcFreeTypeCharIndex: Unicode, Symbol and AppleRoman.
+ // If this font doesn't have one of these three encodings, don't select it.
+ FontPlatformData* platformData = new FontPlatformData(resultPattern.get(), fontDescription);
+ if (!platformData->hasCompatibleCharmap()) {
+ delete platformData;
+ return 0;
+ }
+
+ return platformData;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp b/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp
new file mode 100644
index 0000000..c547224
--- /dev/null
+++ b/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "FontPlatformData.h"
+#include "SharedBuffer.h"
+#include "WOFFFileFormat.h"
+#include <cairo-ft.h>
+#include <cairo.h>
+
+namespace WebCore {
+
+static void releaseCustomFontData(void* data)
+{
+ static_cast<SharedBuffer*>(data)->deref();
+}
+
+FontCustomPlatformData::FontCustomPlatformData(FT_Face freeTypeFace, SharedBuffer* buffer)
+ : m_freeTypeFace(freeTypeFace)
+ , m_fontFace(cairo_ft_font_face_create_for_ft_face(freeTypeFace, 0))
+{
+ // FIXME Should we be setting some hinting options here?
+
+ buffer->ref(); // This is balanced by the buffer->deref() in releaseCustomFontData.
+ static cairo_user_data_key_t bufferKey;
+ cairo_font_face_set_user_data(m_fontFace, &bufferKey, buffer,
+ static_cast<cairo_destroy_func_t>(releaseCustomFontData));
+
+ // Cairo doesn't do FreeType reference counting, so we need to ensure that when
+ // this cairo_font_face_t is destroyed, it cleans up the FreeType face as well.
+ static cairo_user_data_key_t freeTypeFaceKey;
+ cairo_font_face_set_user_data(m_fontFace, &freeTypeFaceKey, freeTypeFace,
+ reinterpret_cast<cairo_destroy_func_t>(FT_Done_Face));
+}
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ // m_freeTypeFace will be destroyed along with m_fontFace. See the constructor.
+ cairo_font_face_destroy(m_fontFace);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode)
+{
+ return FontPlatformData(m_fontFace, size, bold, italic);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+ RefPtr<SharedBuffer> sfntBuffer;
+ if (isWOFF(buffer)) {
+ Vector<char> sfnt;
+ if (!convertWOFFToSfnt(buffer, sfnt))
+ return 0;
+
+ sfntBuffer = SharedBuffer::adoptVector(sfnt);
+ buffer = sfntBuffer.get();
+ }
+
+ static FT_Library library = 0;
+ if (!library && FT_Init_FreeType(&library)) {
+ library = 0;
+ return 0;
+ }
+
+ FT_Face freeTypeFace;
+ if (FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(buffer->data()), buffer->size(), 0, &freeTypeFace))
+ return 0;
+ return new FontCustomPlatformData(freeTypeFace, buffer);
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype") || equalIgnoringCase(format, "woff");
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/freetype/FontPlatformData.h b/Source/WebCore/platform/graphics/freetype/FontPlatformData.h
new file mode 100644
index 0000000..2841b14
--- /dev/null
+++ b/Source/WebCore/platform/graphics/freetype/FontPlatformData.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2010 Igalia S.L.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformDataFreeType_h
+#define FontPlatformDataFreeType_h
+
+#include "FontDescription.h"
+#include "FontOrientation.h"
+#include "GlyphBuffer.h"
+#include "HashFunctions.h"
+#include "RefPtrCairo.h"
+#include <wtf/Forward.h>
+
+typedef struct _FcFontSet FcFontSet;
+
+namespace WebCore {
+
+class FontPlatformData {
+public:
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_fallbacks(0)
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(hashTableDeletedFontValue())
+ { }
+
+ FontPlatformData()
+ : m_fallbacks(0)
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+ { }
+
+ FontPlatformData(FcPattern*, const FontDescription&);
+ FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic);
+ FontPlatformData(float size, bool bold, bool italic);
+ FontPlatformData(const FontPlatformData&);
+ FontPlatformData(const FontPlatformData&, float size);
+
+ ~FontPlatformData();
+
+ bool isFixedPitch();
+ float size() const { return m_size; }
+ void setSize(float size) { m_size = size; }
+ bool syntheticBold() const { return m_syntheticBold; }
+ bool syntheticOblique() const { return m_syntheticOblique; }
+ bool hasCompatibleCharmap();
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+ cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
+
+ unsigned hash() const
+ {
+ return PtrHash<cairo_scaled_font_t*>::hash(m_scaledFont);
+ }
+
+ bool operator==(const FontPlatformData&) const;
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool isHashTableDeletedValue() const
+ {
+ return m_scaledFont == hashTableDeletedFontValue();
+ }
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+ RefPtr<FcPattern> m_pattern;
+ mutable FcFontSet* m_fallbacks; // Initialized lazily.
+ float m_size;
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+ bool m_fixedWidth;
+ cairo_scaled_font_t* m_scaledFont;
+
+private:
+ void initializeWithFontFace(cairo_font_face_t*);
+ static cairo_scaled_font_t* hashTableDeletedFontValue() { return reinterpret_cast<cairo_scaled_font_t*>(-1); }
+};
+
+}
+
+#endif // FontPlatformDataFreeType_h
diff --git a/Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp b/Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp
new file mode 100644
index 0000000..7340e76
--- /dev/null
+++ b/Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2009, 2010 Igalia S.L.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include "FontDescription.h"
+#include <cairo-ft.h>
+#include <cairo.h>
+#include <fontconfig/fcfreetype.h>
+
+#if !PLATFORM(EFL) || ENABLE(GLIB_SUPPORT)
+#include <gdk/gdk.h>
+#endif
+
+namespace WebCore {
+
+cairo_subpixel_order_t convertFontConfigSubpixelOrder(int fontConfigOrder)
+{
+ switch (fontConfigOrder) {
+ case FC_RGBA_RGB:
+ return CAIRO_SUBPIXEL_ORDER_RGB;
+ case FC_RGBA_BGR:
+ return CAIRO_SUBPIXEL_ORDER_BGR;
+ case FC_RGBA_VRGB:
+ return CAIRO_SUBPIXEL_ORDER_VRGB;
+ case FC_RGBA_VBGR:
+ return CAIRO_SUBPIXEL_ORDER_VBGR;
+ case FC_RGBA_NONE:
+ case FC_RGBA_UNKNOWN:
+ return CAIRO_SUBPIXEL_ORDER_DEFAULT;
+ }
+ return CAIRO_SUBPIXEL_ORDER_DEFAULT;
+}
+
+cairo_hint_style_t convertFontConfigHintStyle(int fontConfigStyle)
+{
+ switch (fontConfigStyle) {
+ case FC_HINT_NONE:
+ return CAIRO_HINT_STYLE_NONE;
+ case FC_HINT_SLIGHT:
+ return CAIRO_HINT_STYLE_SLIGHT;
+ case FC_HINT_MEDIUM:
+ return CAIRO_HINT_STYLE_MEDIUM;
+ case FC_HINT_FULL:
+ return CAIRO_HINT_STYLE_FULL;
+ }
+ return CAIRO_HINT_STYLE_NONE;
+}
+
+void setCairoFontOptionsFromFontConfigPattern(cairo_font_options_t* options, FcPattern* pattern)
+{
+ FcBool booleanResult;
+ int integerResult;
+
+ if (FcPatternGetInteger(pattern, FC_RGBA, 0, &integerResult) == FcResultMatch) {
+ cairo_font_options_set_subpixel_order(options, convertFontConfigSubpixelOrder(integerResult));
+
+ // Based on the logic in cairo-ft-font.c in the cairo source, a font with
+ // a subpixel order implies that is uses subpixel antialiasing.
+ if (integerResult != FC_RGBA_NONE)
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_SUBPIXEL);
+ }
+
+ if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &booleanResult) == FcResultMatch) {
+ // Only override the anti-aliasing setting if was previously turned off. Otherwise
+ // we'll override the preference which decides between gray anti-aliasing and
+ // subpixel anti-aliasing.
+ if (!booleanResult)
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_NONE);
+ else if (cairo_font_options_get_antialias(options) == CAIRO_ANTIALIAS_NONE)
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
+ }
+
+ if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &integerResult) == FcResultMatch)
+ cairo_font_options_set_hint_style(options, convertFontConfigHintStyle(integerResult));
+ if (FcPatternGetBool(pattern, FC_HINTING, 0, &booleanResult) == FcResultMatch && !booleanResult)
+ cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
+}
+
+static const cairo_font_options_t* getDefaultFontOptions()
+{
+ static const cairo_font_options_t* options = cairo_font_options_create();
+#if PLATFORM(GTK) || ENABLE(GLIB_SUPPORT)
+ if (GdkScreen* screen = gdk_screen_get_default()) {
+ const cairo_font_options_t* screenOptions = gdk_screen_get_font_options(screen);
+ if (screenOptions)
+ options = screenOptions;
+ }
+#endif
+ return options;
+}
+
+FontPlatformData::FontPlatformData(FcPattern* pattern, const FontDescription& fontDescription)
+ : m_pattern(pattern)
+ , m_fallbacks(0)
+ , m_size(fontDescription.computedPixelSize())
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_fixedWidth(false)
+ , m_scaledFont(0)
+{
+ RefPtr<cairo_font_face_t> fontFace = adoptRef(cairo_ft_font_face_create_for_pattern(m_pattern.get()));
+ initializeWithFontFace(fontFace.get());
+
+ int spacing;
+ if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing) == FcResultMatch && spacing == FC_MONO)
+ m_fixedWidth = true;
+
+ if (fontDescription.weight() >= FontWeightBold) {
+ // The FC_EMBOLDEN property instructs us to fake the boldness of the font.
+ FcBool fontConfigEmbolden;
+ if (FcPatternGetBool(pattern, FC_EMBOLDEN, 0, &fontConfigEmbolden) == FcResultMatch)
+ m_syntheticBold = fontConfigEmbolden;
+ }
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool italic)
+ : m_fallbacks(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
+ , m_fixedWidth(false)
+ , m_scaledFont(0)
+{
+ // We cannot create a scaled font here.
+}
+
+FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic)
+ : m_fallbacks(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
+ , m_scaledFont(0)
+{
+ initializeWithFontFace(fontFace);
+
+ FT_Face fontConfigFace = cairo_ft_scaled_font_lock_face(m_scaledFont);
+ if (fontConfigFace) {
+ m_fixedWidth = fontConfigFace->face_flags & FT_FACE_FLAG_FIXED_WIDTH;
+ cairo_ft_scaled_font_unlock_face(m_scaledFont);
+ }
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ // Check for self-assignment.
+ if (this == &other)
+ return *this;
+
+ m_size = other.m_size;
+ m_syntheticBold = other.m_syntheticBold;
+ m_syntheticOblique = other.m_syntheticOblique;
+ m_fixedWidth = other.m_fixedWidth;
+ m_pattern = other.m_pattern;
+
+ if (m_fallbacks) {
+ FcFontSetDestroy(m_fallbacks);
+ // This will be re-created on demand.
+ m_fallbacks = 0;
+ }
+
+ if (m_scaledFont && m_scaledFont != hashTableDeletedFontValue())
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = cairo_scaled_font_reference(other.m_scaledFont);
+
+ return *this;
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& other)
+ : m_fallbacks(0)
+ , m_scaledFont(0)
+{
+ *this = other;
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& other, float size)
+{
+ *this = other;
+
+ // We need to reinitialize the instance, because the difference in size
+ // necessitates a new scaled font instance.
+ m_size = size;
+ initializeWithFontFace(cairo_scaled_font_get_font_face(m_scaledFont));
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ if (m_fallbacks) {
+ FcFontSetDestroy(m_fallbacks);
+ m_fallbacks = 0;
+ }
+
+ if (m_scaledFont && m_scaledFont != hashTableDeletedFontValue())
+ cairo_scaled_font_destroy(m_scaledFont);
+}
+
+bool FontPlatformData::isFixedPitch()
+{
+ return m_fixedWidth;
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& other) const
+{
+ if (m_pattern == other.m_pattern)
+ return true;
+ if (!m_pattern || !other.m_pattern)
+ return false;
+ return FcPatternEqual(m_pattern.get(), other.m_pattern.get())
+ && m_scaledFont == other.m_scaledFont && m_size == other.m_size
+ && m_syntheticOblique == other.m_syntheticOblique && m_syntheticBold == other.m_syntheticBold;
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+void FontPlatformData::initializeWithFontFace(cairo_font_face_t* fontFace)
+{
+ cairo_font_options_t* options = cairo_font_options_copy(getDefaultFontOptions());
+
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity(&ctm);
+
+ cairo_matrix_t fontMatrix;
+ if (!m_pattern)
+ cairo_matrix_init_scale(&fontMatrix, m_size, m_size);
+ else {
+ setCairoFontOptionsFromFontConfigPattern(options, m_pattern.get());
+
+ // FontConfig may return a list of transformation matrices with the pattern, for instance,
+ // for fonts that are oblique. We use that to initialize the cairo font matrix.
+ FcMatrix fontConfigMatrix, *tempFontConfigMatrix;
+ FcMatrixInit(&fontConfigMatrix);
+
+ // These matrices may be stacked in the pattern, so it's our job to get them all and multiply them.
+ for (int i = 0; FcPatternGetMatrix(m_pattern.get(), FC_MATRIX, i, &tempFontConfigMatrix) == FcResultMatch; i++)
+ FcMatrixMultiply(&fontConfigMatrix, &fontConfigMatrix, tempFontConfigMatrix);
+ cairo_matrix_init(&fontMatrix, fontConfigMatrix.xx, -fontConfigMatrix.yx,
+ -fontConfigMatrix.xy, fontConfigMatrix.yy, 0, 0);
+
+ // The matrix from FontConfig does not include the scale.
+ cairo_matrix_scale(&fontMatrix, m_size, m_size);
+ }
+
+ m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
+ cairo_font_options_destroy(options);
+}
+
+bool FontPlatformData::hasCompatibleCharmap()
+{
+ if (!m_scaledFont)
+ return false;
+
+ FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_scaledFont);
+ bool hasCompatibleCharmap = !(FT_Select_Charmap(freeTypeFace, ft_encoding_unicode)
+ && FT_Select_Charmap(freeTypeFace, ft_encoding_symbol)
+ && FT_Select_Charmap(freeTypeFace, ft_encoding_apple_roman));
+ cairo_ft_scaled_font_unlock_face(m_scaledFont);
+ return hasCompatibleCharmap;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/freetype/GlyphPageTreeNodeFreeType.cpp b/Source/WebCore/platform/graphics/freetype/GlyphPageTreeNodeFreeType.cpp
new file mode 100644
index 0000000..e2f09f4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/freetype/GlyphPageTreeNodeFreeType.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+#include <cairo-ft.h>
+#include <cairo.h>
+#include <fontconfig/fcfreetype.h>
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters.
+ // We won't support this for now.
+ if (bufferLength > GlyphPage::size)
+ return false;
+
+ FT_Face face = cairo_ft_scaled_font_lock_face(fontData->platformData().scaledFont());
+ if (!face)
+ return false;
+
+ bool haveGlyphs = false;
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = FcFreeTypeCharIndex(face, buffer[i]);
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+
+ cairo_ft_scaled_font_unlock_face(fontData->platformData().scaledFont());
+
+ return haveGlyphs;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp b/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp
new file mode 100644
index 0000000..97fd81a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "FloatRect.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "FontDescription.h"
+#include "GlyphBuffer.h"
+#include <cairo-ft.h>
+#include <cairo.h>
+#include <fontconfig/fcfreetype.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ cairo_font_extents_t font_extents;
+ cairo_text_extents_t text_extents;
+ cairo_scaled_font_extents(m_platformData.scaledFont(), &font_extents);
+ m_ascent = static_cast<int>(lroundf(font_extents.ascent));
+ m_descent = static_cast<int>(lroundf(font_extents.descent));
+ m_lineSpacing = static_cast<int>(lroundf(font_extents.height));
+ // There seems to be some rounding error in cairo (or in how we
+ // use cairo) with some fonts, like DejaVu Sans Mono, which makes
+ // cairo report a height smaller than ascent + descent, which is
+ // wrong and confuses WebCore's layout system. Workaround this
+ // while we figure out what's going on.
+ if (m_lineSpacing < m_ascent + m_descent)
+ m_lineSpacing = m_ascent + m_descent;
+ cairo_scaled_font_text_extents(m_platformData.scaledFont(), "x", &text_extents);
+ m_xHeight = text_extents.height;
+ cairo_scaled_font_text_extents(m_platformData.scaledFont(), " ", &text_extents);
+ m_spaceWidth = static_cast<float>(text_extents.x_advance);
+ m_lineGap = m_lineSpacing - m_ascent - m_descent;
+ m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f;
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ m_avgCharWidth = 0.f;
+ m_maxCharWidth = 0.f;
+ initCharWidths();
+}
+
+void SimpleFontData::platformDestroy()
+{
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ return new SimpleFontData(FontPlatformData(cairo_scaled_font_get_font_face(m_platformData.scaledFont()),
+ scaleFactor * fontDescription.computedSize(), m_platformData.syntheticBold(), m_platformData.syntheticOblique()),
+ isCustomFont(), false);
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ // FIXME: I think we want to ask FontConfig for the right font again.
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ FT_Face face = cairo_ft_scaled_font_lock_face(m_platformData.scaledFont());
+
+ if (!face)
+ return false;
+
+ for (int i = 0; i < length; i++) {
+ if (FcFreeTypeCharIndex(face, characters[i]) == 0) {
+ cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont());
+ return false;
+ }
+ }
+
+ cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont());
+
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = m_platformData.isFixedPitch();
+}
+
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const
+{
+ return FloatRect();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ ASSERT(m_platformData.scaledFont());
+
+ cairo_glyph_t cglyph = { glyph, 0, 0 };
+ cairo_text_extents_t extents;
+ cairo_scaled_font_glyph_extents(m_platformData.scaledFont(), &cglyph, 1, &extents);
+
+ float w = (float)m_spaceWidth;
+ if (cairo_scaled_font_status(m_platformData.scaledFont()) == CAIRO_STATUS_SUCCESS && extents.x_advance)
+ w = (float)extents.x_advance;
+
+ return w;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp
new file mode 100644
index 0000000..d2415ca
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(3D_CANVAS)
+
+#include "DrawingBuffer.h"
+
+#include "Extensions3D.h"
+
+namespace WebCore {
+
+PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, const IntSize& size)
+{
+ RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, size));
+ Extensions3D* extensions = context->getExtensions();
+ bool multisampleSupported = extensions->supports("GL_ANGLE_framebuffer_blit") && extensions->supports("GL_ANGLE_framebuffer_multisample");
+ if (multisampleSupported) {
+ extensions->ensureEnabled("GL_ANGLE_framebuffer_blit");
+ extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample");
+ }
+ drawingBuffer->m_multisampleExtensionSupported = multisampleSupported;
+ return (drawingBuffer->m_context) ? drawingBuffer.release() : 0;
+}
+
+void DrawingBuffer::clear()
+{
+ if (!m_context)
+ return;
+
+ m_context->makeContextCurrent();
+ m_context->deleteTexture(m_colorBuffer);
+ m_colorBuffer = 0;
+
+ if (m_multisampleColorBuffer) {
+ m_context->deleteRenderbuffer(m_multisampleColorBuffer);
+ m_multisampleColorBuffer = 0;
+ }
+
+ if (m_multisampleDepthStencilBuffer) {
+ m_context->deleteRenderbuffer(m_multisampleDepthStencilBuffer);
+ m_multisampleDepthStencilBuffer = 0;
+ }
+
+ if (m_depthStencilBuffer) {
+ m_context->deleteRenderbuffer(m_depthStencilBuffer);
+ m_depthStencilBuffer = 0;
+ }
+
+ if (m_multisampleFBO) {
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO);
+ m_context->deleteFramebuffer(m_multisampleFBO);
+ m_multisampleFBO = 0;
+ }
+
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
+ m_context->deleteFramebuffer(m_fbo);
+ m_fbo = 0;
+
+ m_context.clear();
+}
+
+void DrawingBuffer::reset(const IntSize& newSize)
+{
+ if (m_size == newSize)
+ return;
+ m_size = newSize;
+
+ if (!m_context)
+ return;
+
+ m_context->makeContextCurrent();
+
+ const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes();
+ unsigned long internalColorFormat, colorFormat, internalDepthStencilFormat = 0;
+ if (attributes.alpha) {
+ internalColorFormat = GraphicsContext3D::RGBA;
+ colorFormat = GraphicsContext3D::RGBA;
+ } else {
+ internalColorFormat = GraphicsContext3D::RGB;
+ colorFormat = GraphicsContext3D::RGB;
+ }
+ if (attributes.stencil || attributes.depth) {
+ // We don't allow the logic where stencil is required and depth is not.
+ // See GraphicsContext3D constructor.
+ if (attributes.stencil && attributes.depth)
+ internalDepthStencilFormat = GraphicsContext3D::DEPTH_STENCIL;
+ else
+ internalDepthStencilFormat = GraphicsContext3D::DEPTH_COMPONENT;
+ }
+
+ // resize multisample FBO
+ if (multisample()) {
+ int maxSampleCount = 0;
+
+ m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount);
+ int sampleCount = std::min(8, maxSampleCount);
+
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO);
+
+ m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer);
+ m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalColorFormat, m_size.width(), m_size.height());
+ m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer);
+ if (attributes.stencil || attributes.depth) {
+ m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleDepthStencilBuffer);
+ m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalDepthStencilFormat, m_size.width(), m_size.height());
+ if (attributes.stencil)
+ m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_multisampleDepthStencilBuffer);
+ if (attributes.depth)
+ m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_multisampleDepthStencilBuffer);
+ }
+ m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
+ if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+ // Cleanup
+ clear();
+ return;
+ }
+ }
+
+ // resize regular FBO
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
+
+ m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer);
+ m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE);
+ m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE, m_colorBuffer, 0);
+ m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
+ if (!multisample() && (attributes.stencil || attributes.depth)) {
+ m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthStencilBuffer);
+ m_context->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, internalDepthStencilFormat, m_size.width(), m_size.height());
+ if (attributes.stencil)
+ m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthStencilBuffer);
+ if (attributes.depth)
+ m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthStencilBuffer);
+ m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
+ }
+ if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+ // Cleanup
+ clear();
+ return;
+ }
+
+ if (multisample())
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO);
+
+ if (!m_context->getExtensions()->supports("GL_CHROMIUM_resource_safe")) {
+ // Initialize renderbuffers (depth/stencil).
+ float clearDepth = 0;
+ int clearStencil = 0;
+ unsigned char depthMask = true;
+ unsigned int stencilMask = 0xffffffff;
+ unsigned char isScissorEnabled = false;
+ unsigned long clearMask = 0;
+ if (attributes.depth) {
+ m_context->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &clearDepth);
+ m_context->clearDepth(1);
+ m_context->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask);
+ m_context->depthMask(true);
+ clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
+ }
+ if (attributes.stencil) {
+ m_context->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &clearStencil);
+ m_context->clearStencil(0);
+ m_context->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<int*>(&stencilMask));
+ m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xffffffff);
+ clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
+ }
+ if (clearMask) {
+ isScissorEnabled = m_context->isEnabled(GraphicsContext3D::SCISSOR_TEST);
+ m_context->disable(GraphicsContext3D::SCISSOR_TEST);
+
+ m_context->clear(clearMask);
+
+ if (attributes.depth) {
+ m_context->clearDepth(clearDepth);
+ m_context->depthMask(depthMask);
+ }
+ if (attributes.stencil) {
+ m_context->clearStencil(clearStencil);
+ m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, stencilMask);
+ }
+ if (isScissorEnabled)
+ m_context->enable(GraphicsContext3D::SCISSOR_TEST);
+ else
+ m_context->disable(GraphicsContext3D::SCISSOR_TEST);
+ }
+ }
+
+ m_context->flush();
+
+ didReset();
+}
+
+void DrawingBuffer::commit(long x, long y, long width, long height)
+{
+ if (!m_context)
+ return;
+
+ if (width < 0)
+ width = m_size.width();
+ if (height < 0)
+ height = m_size.height();
+
+ m_context->makeContextCurrent();
+
+ if (m_multisampleFBO) {
+ m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, m_multisampleFBO);
+ m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, m_fbo);
+ m_context->getExtensions()->blitFramebuffer(x, y, width, height, x, y, width, height, GraphicsContext3D::COLOR_BUFFER_BIT, GraphicsContext3D::LINEAR);
+ }
+
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
+}
+
+void DrawingBuffer::bind()
+{
+ if (!m_context)
+ return;
+
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo);
+ m_context->viewport(0, 0, m_size.width(), m_size.height());
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h
new file mode 100644
index 0000000..9f79889
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 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 DrawingBuffer_h
+#define DrawingBuffer_h
+
+#include "GraphicsContext3D.h"
+#include "GraphicsLayer.h"
+#include "IntSize.h"
+
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#if PLATFORM(MAC)
+#include <wtf/RetainPtr.h>
+#endif
+
+namespace WebCore {
+
+#if PLATFORM(CHROMIUM)
+struct DrawingBufferInternal;
+#endif
+
+// Manages a rendering target (framebuffer + attachment) for a canvas. Can publish its rendering
+// results to a PlatformLayer for compositing.
+class DrawingBuffer : public RefCounted<DrawingBuffer> {
+public:
+ friend class GraphicsContext3D;
+
+ ~DrawingBuffer();
+
+ void reset(const IntSize&);
+ void bind();
+ IntSize size() const { return m_size; }
+
+ // Clear all resources from this object, as well as context. Called when context is destroyed
+ // to prevent invalid accesses to the resources.
+ void clear();
+
+ // Copies the multisample color buffer to the normal color buffer and leaves m_fbo bound
+ void commit(long x = 0, long y = 0, long width = -1, long height = -1);
+
+ bool multisample() const { return m_context && m_context->getContextAttributes().antialias && m_multisampleExtensionSupported; }
+
+ Platform3DObject platformColorBuffer() const;
+
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer();
+ void publishToPlatformLayer();
+#endif
+
+#if PLATFORM(CHROMIUM)
+ class WillPublishCallback : public Noncopyable {
+ public:
+ virtual ~WillPublishCallback() { }
+
+ virtual void willPublish() = 0;
+ };
+
+ void setWillPublishCallback(PassOwnPtr<WillPublishCallback> callback) { m_callback = callback; }
+#endif
+
+ PassRefPtr<GraphicsContext3D> graphicsContext3D() const { return m_context; }
+
+private:
+ static PassRefPtr<DrawingBuffer> create(GraphicsContext3D*, const IntSize&);
+
+ DrawingBuffer(GraphicsContext3D*, const IntSize&);
+
+ // Platform specific function called after reset() so each platform can do extra work if needed
+ void didReset();
+
+ RefPtr<GraphicsContext3D> m_context;
+ IntSize m_size;
+ bool m_multisampleExtensionSupported;
+ Platform3DObject m_fbo;
+ Platform3DObject m_colorBuffer;
+ Platform3DObject m_depthStencilBuffer;
+
+ // For multisampling
+ Platform3DObject m_multisampleFBO;
+ Platform3DObject m_multisampleColorBuffer;
+ Platform3DObject m_multisampleDepthStencilBuffer;
+
+#if PLATFORM(CHROMIUM)
+ OwnPtr<WillPublishCallback> m_callback;
+ OwnPtr<DrawingBufferInternal> m_internal;
+#endif
+
+#if PLATFORM(MAC)
+ RetainPtr<WebGLLayer> m_platformLayer;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // DrawingBuffer_h
diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp
new file mode 100644
index 0000000..672b4d7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "LoopBlinnClassifier.h"
+
+#include "LoopBlinnMathUtils.h"
+
+namespace WebCore {
+
+using LoopBlinnMathUtils::approxEqual;
+using LoopBlinnMathUtils::roundToZero;
+
+LoopBlinnClassifier::Result LoopBlinnClassifier::classify(const FloatPoint& c0,
+ const FloatPoint& c1,
+ const FloatPoint& c2,
+ const FloatPoint& c3)
+{
+ // Consult the chapter for the definitions of the following
+ // (terse) variable names. Note that the b0..b3 coordinates are
+ // homogeneous, so the "z" value (actually the w coordinate) must
+ // be 1.0.
+ FloatPoint3D b0(c0.x(), c0.y(), 1.0f);
+ FloatPoint3D b1(c1.x(), c1.y(), 1.0f);
+ FloatPoint3D b2(c2.x(), c2.y(), 1.0f);
+ FloatPoint3D b3(c3.x(), c3.y(), 1.0f);
+
+ // Compute a1..a3.
+ float a1 = b0 * b3.cross(b2);
+ float a2 = b1 * b0.cross(b3);
+ float a3 = b2 * b1.cross(b0);
+
+ // Compute d1..d3.
+ float d1 = a1 - 2 * a2 + 3 * a3;
+ float d2 = -a2 + 3 * a3;
+ float d3 = 3 * a3;
+
+ // Experimentation has shown that the texture coordinates computed
+ // from these values quickly become huge, leading to roundoff errors
+ // and artifacts in the shader. It turns out that if we normalize
+ // the vector defined by (d1, d2, d3), this fixes the problem of the
+ // texture coordinates getting too large without affecting the
+ // classification results.
+ FloatPoint3D nd(d1, d2, d3);
+ nd.normalize();
+ d1 = nd.x();
+ d2 = nd.y();
+ d3 = nd.z();
+
+ // Compute the discriminant.
+ // term0 is a common term in the computation which helps decide
+ // which way to classify the cusp case: as serpentine or loop.
+ float term0 = (3 * d2 * d2 - 4 * d1 * d3);
+ float discriminant = d1 * d1 * term0;
+
+ // Experimentation has also shown that when the classification is
+ // near the boundary between one curve type and another, the shader
+ // becomes numerically unstable, particularly with the cusp case.
+ // Correct for this by rounding d1..d3 and the discriminant to zero
+ // when they get near it.
+ d1 = roundToZero(d1);
+ d2 = roundToZero(d2);
+ d3 = roundToZero(d3);
+ discriminant = roundToZero(discriminant);
+
+ // Do the classification.
+ if (approxEqual(b0, b1) && approxEqual(b0, b2) && approxEqual(b0, b3))
+ return Result(kPoint, d1, d2, d3);
+
+ if (!discriminant) {
+ if (!d1 && !d2) {
+ if (!d3)
+ return Result(kLine, d1, d2, d3);
+ return Result(kQuadratic, d1, d2, d3);
+ }
+
+ if (!d1)
+ return Result(kCusp, d1, d2, d3);
+
+ // This is the boundary case described in Loop and Blinn's
+ // SIGGRAPH '05 paper of a cusp with inflection at infinity.
+ // Because term0 might not be exactly 0, we decide between using
+ // the serpentine and loop cases depending on its sign to avoid
+ // taking the square root of a negative number when computing the
+ // cubic texture coordinates.
+ if (term0 < 0)
+ return Result(kLoop, d1, d2, d3);
+
+ return Result(kSerpentine, d1, d2, d3);
+ }
+
+ if (discriminant > 0)
+ return Result(kSerpentine, d1, d2, d3);
+
+ // discriminant < 0
+ return Result(kLoop, d1, d2, d3);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnClassifier.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnClassifier.h
new file mode 100644
index 0000000..c665844
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnClassifier.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+// Cubic curve classification algorithm from "Rendering Vector Art on
+// the GPU" by Loop and Blinn, GPU Gems 3, Chapter 25:
+// http://http.developer.nvidia.com/GPUGems3/gpugems3_ch25.html .
+
+#ifndef LoopBlinnClassifier_h
+#define LoopBlinnClassifier_h
+
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class FloatPoint;
+
+// Classifies cubic curves into specific types.
+class LoopBlinnClassifier : public Noncopyable {
+public:
+ // The types of cubic curves.
+ enum CurveType {
+ kSerpentine,
+ kCusp,
+ kLoop,
+ kQuadratic,
+ kLine,
+ kPoint
+ };
+
+ // The result of the classifier.
+ struct Result {
+ public:
+ Result(CurveType inputCurveType, float inputD1, float inputD2, float inputD3)
+ : curveType(inputCurveType)
+ , d1(inputD1)
+ , d2(inputD2)
+ , d3(inputD3) { }
+
+ CurveType curveType;
+
+ // These are coefficients used later in the computation of
+ // texture coordinates per vertex.
+ float d1;
+ float d2;
+ float d3;
+ };
+
+ // Classifies the given cubic bezier curve starting at c0, ending
+ // at c3, and affected by control points c1 and c2.
+ static Result classify(const FloatPoint& c0,
+ const FloatPoint& c1,
+ const FloatPoint& c2,
+ const FloatPoint& c3);
+
+private:
+ // This class does not need to be instantiated.
+ LoopBlinnClassifier() { }
+};
+
+} // namespace WebCore
+
+#endif // LoopBlinnClassifier_h
diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnConstants.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnConstants.h
new file mode 100644
index 0000000..1997d9f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnConstants.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 LoopBlinnConstants_h
+#define LoopBlinnConstants_h
+
+namespace WebCore {
+namespace LoopBlinnConstants {
+
+enum FillSide {
+ LeftSide,
+ RightSide
+};
+
+} // namespace LoopBlinnConstants
+} // namespace WebCore
+
+#endif // LoopBlinnConstants_h
diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp
new file mode 100644
index 0000000..1517a67
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "LoopBlinnLocalTriangulator.h"
+
+#include "LoopBlinnMathUtils.h"
+#include <algorithm>
+
+namespace WebCore {
+
+using LoopBlinnMathUtils::approxEqual;
+using LoopBlinnMathUtils::linesIntersect;
+using LoopBlinnMathUtils::pointInTriangle;
+
+bool LoopBlinnLocalTriangulator::Triangle::contains(LoopBlinnLocalTriangulator::Vertex* v)
+{
+ return indexForVertex(v) >= 0;
+}
+
+LoopBlinnLocalTriangulator::Vertex* LoopBlinnLocalTriangulator::Triangle::nextVertex(LoopBlinnLocalTriangulator::Vertex* current, bool traverseCounterClockwise)
+{
+ int index = indexForVertex(current);
+ ASSERT(index >= 0);
+ if (traverseCounterClockwise)
+ ++index;
+ else
+ --index;
+ if (index < 0)
+ index += 3;
+ else
+ index = index % 3;
+ return m_vertices[index];
+}
+
+int LoopBlinnLocalTriangulator::Triangle::indexForVertex(LoopBlinnLocalTriangulator::Vertex* vertex)
+{
+ for (int i = 0; i < 3; ++i)
+ if (m_vertices[i] == vertex)
+ return i;
+ return -1;
+}
+
+void LoopBlinnLocalTriangulator::Triangle::makeCounterClockwise()
+{
+ // Possibly swaps two vertices so that the triangle's vertices are
+ // always specified in counterclockwise order. This orders the
+ // vertices canonically when walking the interior edges from the
+ // start to the end vertex.
+ FloatPoint3D point0(m_vertices[0]->xyCoordinates());
+ FloatPoint3D point1(m_vertices[1]->xyCoordinates());
+ FloatPoint3D point2(m_vertices[2]->xyCoordinates());
+ FloatPoint3D crossProduct = (point1 - point0).cross(point2 - point0);
+ if (crossProduct.z() < 0)
+ std::swap(m_vertices[1], m_vertices[2]);
+}
+
+LoopBlinnLocalTriangulator::LoopBlinnLocalTriangulator()
+{
+ reset();
+}
+
+void LoopBlinnLocalTriangulator::reset()
+{
+ m_numberOfTriangles = 0;
+ m_numberOfInteriorVertices = 0;
+ for (int i = 0; i < 4; ++i) {
+ m_interiorVertices[i] = 0;
+ m_vertices[i].resetFlags();
+ }
+}
+
+void LoopBlinnLocalTriangulator::triangulate(InsideEdgeComputation computeInsideEdges, LoopBlinnConstants::FillSide sideToFill)
+{
+ triangulateHelper(sideToFill);
+
+ if (computeInsideEdges == ComputeInsideEdges) {
+ // We need to compute which vertices describe the path along the
+ // interior portion of the shape, to feed these vertices to the
+ // more general tessellation algorithm. It is possible that we
+ // could determine this directly while producing triangles above.
+ // Here we try to do it generally just by examining the triangles
+ // that have already been produced. We walk around them in a
+ // specific direction determined by which side of the curve is
+ // being filled. We ignore the interior vertex unless it is also
+ // the ending vertex, and skip the edges shared between two
+ // triangles.
+ Vertex* v = &m_vertices[0];
+ addInteriorVertex(v);
+ int numSteps = 0;
+ while (!v->end() && numSteps < 4) {
+ // Find the next vertex according to the above rules
+ bool gotNext = false;
+ for (int i = 0; i < numberOfTriangles() && !gotNext; ++i) {
+ Triangle* tri = getTriangle(i);
+ if (tri->contains(v)) {
+ Vertex* next = tri->nextVertex(v, sideToFill == LoopBlinnConstants::RightSide);
+ if (!next->marked() && !isSharedEdge(v, next) && (!next->interior() || next->end())) {
+ addInteriorVertex(next);
+ v = next;
+ // Break out of for loop
+ gotNext = true;
+ }
+ }
+ }
+ ++numSteps;
+ }
+ if (!v->end()) {
+ // Something went wrong with the above algorithm; add the last
+ // vertex to the interior vertices anyway. (FIXME: should we
+ // add an assert here and do more extensive testing?)
+ addInteriorVertex(&m_vertices[3]);
+ }
+ }
+}
+
+void LoopBlinnLocalTriangulator::triangulateHelper(LoopBlinnConstants::FillSide sideToFill)
+{
+ reset();
+
+ m_vertices[3].setEnd(true);
+
+ // First test for degenerate cases.
+ for (int i = 0; i < 4; ++i) {
+ for (int j = i + 1; j < 4; ++j) {
+ if (approxEqual(m_vertices[i].xyCoordinates(), m_vertices[j].xyCoordinates())) {
+ // Two of the vertices are coincident, so we can eliminate at
+ // least one triangle. We might be able to eliminate the other
+ // as well, but this seems sufficient to avoid degenerate
+ // triangulations.
+ int indices[3] = { 0 };
+ int index = 0;
+ for (int k = 0; k < 4; ++k)
+ if (k != j)
+ indices[index++] = k;
+ addTriangle(&m_vertices[indices[0]],
+ &m_vertices[indices[1]],
+ &m_vertices[indices[2]]);
+ return;
+ }
+ }
+ }
+
+ // See whether any of the points are fully contained in the
+ // triangle defined by the other three.
+ for (int i = 0; i < 4; ++i) {
+ int indices[3] = { 0 };
+ int index = 0;
+ for (int j = 0; j < 4; ++j)
+ if (i != j)
+ indices[index++] = j;
+ if (pointInTriangle(m_vertices[i].xyCoordinates(),
+ m_vertices[indices[0]].xyCoordinates(),
+ m_vertices[indices[1]].xyCoordinates(),
+ m_vertices[indices[2]].xyCoordinates())) {
+ // Produce three triangles surrounding this interior vertex.
+ for (int j = 0; j < 3; ++j)
+ addTriangle(&m_vertices[indices[j % 3]],
+ &m_vertices[indices[(j + 1) % 3]],
+ &m_vertices[i]);
+ // Mark the interior vertex so we ignore it if trying to trace
+ // the interior edge.
+ m_vertices[i].setInterior(true);
+ return;
+ }
+ }
+
+ // There are only a few permutations of the vertices, ignoring
+ // rotations, which are irrelevant:
+ //
+ // 0--3 0--2 0--3 0--1 0--2 0--1
+ // | | | | | | | | | | | |
+ // | | | | | | | | | | | |
+ // 1--2 1--3 2--1 2--3 3--1 3--2
+ //
+ // Note that three of these are reflections of each other.
+ // Therefore there are only three possible triangulations:
+ //
+ // 0--3 0--2 0--3
+ // |\ | |\ | |\ |
+ // | \| | \| | \|
+ // 1--2 1--3 2--1
+ //
+ // From which we can choose by seeing which of the potential
+ // diagonals intersect. Note that we choose the shortest diagonal
+ // to split the quad.
+ if (linesIntersect(m_vertices[0].xyCoordinates(),
+ m_vertices[2].xyCoordinates(),
+ m_vertices[1].xyCoordinates(),
+ m_vertices[3].xyCoordinates())) {
+ if ((m_vertices[2].xyCoordinates() - m_vertices[0].xyCoordinates()).diagonalLengthSquared() <
+ (m_vertices[3].xyCoordinates() - m_vertices[1].xyCoordinates()).diagonalLengthSquared()) {
+ addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[2]);
+ addTriangle(&m_vertices[0], &m_vertices[2], &m_vertices[3]);
+ } else {
+ addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[3]);
+ addTriangle(&m_vertices[1], &m_vertices[2], &m_vertices[3]);
+ }
+ } else if (linesIntersect(m_vertices[0].xyCoordinates(),
+ m_vertices[3].xyCoordinates(),
+ m_vertices[1].xyCoordinates(),
+ m_vertices[2].xyCoordinates())) {
+ if ((m_vertices[3].xyCoordinates() - m_vertices[0].xyCoordinates()).diagonalLengthSquared() <
+ (m_vertices[2].xyCoordinates() - m_vertices[1].xyCoordinates()).diagonalLengthSquared()) {
+ addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[3]);
+ addTriangle(&m_vertices[0], &m_vertices[3], &m_vertices[2]);
+ } else {
+ addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[2]);
+ addTriangle(&m_vertices[2], &m_vertices[1], &m_vertices[3]);
+ }
+ } else {
+ // Lines (0->1), (2->3) intersect -- or should, modulo numerical
+ // precision issues
+ if ((m_vertices[1].xyCoordinates() - m_vertices[0].xyCoordinates()).diagonalLengthSquared() <
+ (m_vertices[3].xyCoordinates() - m_vertices[2].xyCoordinates()).diagonalLengthSquared()) {
+ addTriangle(&m_vertices[0], &m_vertices[2], &m_vertices[1]);
+ addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[3]);
+ } else {
+ addTriangle(&m_vertices[0], &m_vertices[2], &m_vertices[3]);
+ addTriangle(&m_vertices[3], &m_vertices[2], &m_vertices[1]);
+ }
+ }
+}
+
+void LoopBlinnLocalTriangulator::addTriangle(Vertex* v0, Vertex* v1, Vertex* v2)
+{
+ ASSERT(m_numberOfTriangles < 3);
+ m_triangles[m_numberOfTriangles++].setVertices(v0, v1, v2);
+}
+
+void LoopBlinnLocalTriangulator::addInteriorVertex(Vertex* v)
+{
+ ASSERT(m_numberOfInteriorVertices < 4);
+ m_interiorVertices[m_numberOfInteriorVertices++] = v;
+ v->setMarked(true);
+}
+
+bool LoopBlinnLocalTriangulator::isSharedEdge(Vertex* v0, Vertex* v1)
+{
+ bool haveEdge01 = false;
+ bool haveEdge10 = false;
+ for (int i = 0; i < numberOfTriangles(); ++i) {
+ Triangle* tri = getTriangle(i);
+ if (tri->contains(v0) && tri->nextVertex(v0, true) == v1)
+ haveEdge01 = true;
+ if (tri->contains(v1) && tri->nextVertex(v1, true) == v0)
+ haveEdge10 = true;
+ }
+ return haveEdge01 && haveEdge10;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.h
new file mode 100644
index 0000000..ea3d7e3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 LoopBlinnLocalTriangulator_h
+#define LoopBlinnLocalTriangulator_h
+
+#include "FloatPoint.h"
+#include "FloatPoint3D.h"
+#include "LoopBlinnConstants.h"
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+// Performs a localized triangulation of the triangle mesh
+// corresponding to the four control point vertices of a cubic curve
+// segment.
+class LoopBlinnLocalTriangulator : public Noncopyable {
+public:
+ // The vertices that the triangulator operates upon, containing both
+ // the position information as well as the cubic texture
+ // coordinates.
+ class Vertex : public Noncopyable {
+ public:
+ Vertex()
+ {
+ resetFlags();
+ }
+
+ const FloatPoint& xyCoordinates() const
+ {
+ return m_xyCoordinates;
+ }
+
+ const FloatPoint3D& klmCoordinates() const
+ {
+ return m_klmCoordinates;
+ }
+
+ // Sets the position and texture coordinates of the vertex.
+ void set(float x, float y,
+ float k, float l, float m)
+ {
+ m_xyCoordinates.set(x, y);
+ m_klmCoordinates.set(k, l, m);
+ }
+
+ // Flags for walking from the start vertex to the end vertex.
+ bool end()
+ {
+ return m_end;
+ }
+
+ void setEnd(bool end)
+ {
+ m_end = end;
+ }
+
+ bool marked()
+ {
+ return m_marked;
+ }
+
+ void setMarked(bool marked)
+ {
+ m_marked = marked;
+ }
+
+ bool interior()
+ {
+ return m_interior;
+ }
+
+ void setInterior(bool interior)
+ {
+ m_interior = interior;
+ }
+
+ void resetFlags()
+ {
+ m_end = false;
+ m_marked = false;
+ m_interior = false;
+ }
+
+ private:
+ // 2D coordinates of the vertex in the plane.
+ FloatPoint m_xyCoordinates;
+ // Cubic texture coordinates for rendering the curve.
+ FloatPoint3D m_klmCoordinates;
+
+ // Flags for walking from the start vertex to the end vertex.
+ bool m_end;
+ bool m_marked;
+ bool m_interior;
+ };
+
+ // The triangles the Triangulator produces.
+ class Triangle {
+ public:
+ Triangle()
+ {
+ m_vertices[0] = 0;
+ m_vertices[1] = 0;
+ m_vertices[2] = 0;
+ }
+
+ // Gets the vertex at the given index, 0 <= index < 3.
+ Vertex* getVertex(int index)
+ {
+ ASSERT(index >= 0 && index < 3);
+ return m_vertices[index];
+ }
+
+ // Returns true if this triangle contains the given vertex (by
+ // identity, not geometrically).
+ bool contains(Vertex* v);
+
+ // Returns the vertex following the current one in the specified
+ // direction, counterclockwise or clockwise.
+ Vertex* nextVertex(Vertex* current, bool traverseCounterClockwise);
+
+ // Sets the vertices of this triangle, potentially reordering them
+ // to produce a canonical orientation.
+ void setVertices(Vertex* v0,
+ Vertex* v1,
+ Vertex* v2)
+ {
+ m_vertices[0] = v0;
+ m_vertices[1] = v1;
+ m_vertices[2] = v2;
+ makeCounterClockwise();
+ }
+
+ private:
+ // Returns the index [0..2] associated with the given vertex, or
+ // -1 if not found.
+ int indexForVertex(Vertex* vertex);
+
+ // Reorders the vertices in this triangle to make them
+ // counterclockwise when viewed in the 2D plane, in order to
+ // achieve a canonical ordering.
+ void makeCounterClockwise();
+
+ // Note: these are raw pointers because they point to the
+ // m_vertices contained in the surrounding triangulator.
+ Vertex* m_vertices[3];
+ };
+
+ LoopBlinnLocalTriangulator();
+
+ // Resets the triangulator's state. After each triangulation and
+ // before the next, call this to re-initialize the internal
+ // vertices' state.
+ void reset();
+
+ // Returns a mutable vertex stored in the triangulator. Use this to
+ // set up the vertices before a triangulation.
+ Vertex* getVertex(int index)
+ {
+ ASSERT(index >= 0 && index < 4);
+ return &m_vertices[index];
+ }
+
+ enum InsideEdgeComputation {
+ ComputeInsideEdges,
+ DontComputeInsideEdges
+ };
+
+ // Once the vertices' contents have been set up, call triangulate()
+ // to recompute the triangles.
+ //
+ // If computeInsideEdges is ComputeInsideEdges, then sideToFill
+ // will be used to determine which side of the cubic curve defined
+ // by the four control points is to be filled.
+ //
+ // The triangulation obeys the following guarantees:
+ // - If the convex hull is a quadrilateral, then the shortest edge
+ // will be chosen for the cut into two triangles.
+ // - If one of the vertices is contained in the triangle spanned
+ // by the other three, three triangles will be produced.
+ void triangulate(InsideEdgeComputation computeInsideEdges,
+ LoopBlinnConstants::FillSide sideToFill);
+
+ // Number of triangles computed by triangulate().
+ int numberOfTriangles() const
+ {
+ return m_numberOfTriangles;
+ }
+
+ // Returns the computed triangle at index, 0 <= index < numberOfTriangles().
+ Triangle* getTriangle(int index)
+ {
+ ASSERT(index >= 0 && index < m_numberOfTriangles);
+ return &m_triangles[index];
+ }
+
+ // Number of vertices facing the inside of the shape, if
+ // ComputeInsideEdges was passed when triangulate() was called.
+ int numberOfInteriorVertices() const
+ {
+ return m_numberOfInteriorVertices;
+ }
+
+ // Fetches the given interior vertex, 0 <= index < numberOfInteriorVertices().
+ Vertex* getInteriorVertex(int index)
+ {
+ ASSERT(index >= 0 && index < m_numberOfInteriorVertices);
+ return m_interiorVertices[index];
+ }
+
+private:
+ void triangulateHelper(LoopBlinnConstants::FillSide sideToFill);
+
+ // Adds a triangle to the triangulation.
+ void addTriangle(Vertex* v0, Vertex* v1, Vertex* v2);
+
+ // Adds a vertex to the list of interior vertices.
+ void addInteriorVertex(Vertex* v);
+
+ // Indicates whether the edge between vertex v0 and v1 is shared
+ // between two or more triangles.
+ bool isSharedEdge(Vertex* v0, Vertex* v1);
+
+ // The vertices being triangulated.
+ Vertex m_vertices[4];
+
+ // The vertices corresponding to the edges facing the inside of the
+ // shape, in order from the start vertex to the end vertex. The more
+ // general triangulation algorithm tessellates this interior region.
+ Vertex* m_interiorVertices[4];
+ // The number of interior vertices that are valid for the current
+ // triangulation.
+ int m_numberOfInteriorVertices;
+
+ // There can be at most three triangles computed by this local
+ // algorithm, which occurs when one of the vertices is contained in
+ // the triangle spanned by the other three. Most of the time the
+ // algorithm computes two triangles.
+ Triangle m_triangles[3];
+ int m_numberOfTriangles;
+};
+
+} // namespace WebCore
+
+#endif // LoopBlinnLocalTriangulator_h
diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp
new file mode 100644
index 0000000..5b155a5
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "LoopBlinnMathUtils.h"
+
+#include "FloatPoint.h"
+#include <algorithm>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+namespace LoopBlinnMathUtils {
+
+namespace {
+
+// Utility functions local to this file.
+int orientation(const FloatPoint& p1,
+ const FloatPoint& p2,
+ const FloatPoint& p3)
+{
+ float crossProduct = (p2.y() - p1.y()) * (p3.x() - p2.x()) - (p3.y() - p2.y()) * (p2.x() - p1.x());
+ return (crossProduct < 0.0f) ? -1 : ((crossProduct > 0.0f) ? 1 : 0);
+}
+
+bool edgeEdgeTest(const FloatSize& v0Delta,
+ const FloatPoint& v0,
+ const FloatPoint& u0,
+ const FloatPoint& u1)
+{
+ // This edge to edge test is based on Franlin Antonio's gem: "Faster
+ // Line Segment Intersection", in Graphics Gems III, pp. 199-202.
+ float ax = v0Delta.width();
+ float ay = v0Delta.height();
+ float bx = u0.x() - u1.x();
+ float by = u0.y() - u1.y();
+ float cx = v0.x() - u0.x();
+ float cy = v0.y() - u0.y();
+ float f = ay * bx - ax * by;
+ float d = by * cx - bx * cy;
+ if ((f > 0 && d >= 0 && d <= f) || (f < 0 && d <= 0 && d >= f)) {
+ float e = ax * cy - ay * cx;
+
+ // This additional test avoids reporting coincident edges, which
+ // is the behavior we want.
+ if (approxEqual(e, 0) || approxEqual(f, 0) || approxEqual(e, f))
+ return false;
+
+ if (f > 0)
+ return e >= 0 && e <= f;
+
+ return e <= 0 && e >= f;
+ }
+ return false;
+}
+
+bool edgeAgainstTriangleEdges(const FloatPoint& v0,
+ const FloatPoint& v1,
+ const FloatPoint& u0,
+ const FloatPoint& u1,
+ const FloatPoint& u2)
+{
+ FloatSize delta = v1 - v0;
+ // Test edge u0, u1 against v0, v1.
+ if (edgeEdgeTest(delta, v0, u0, u1))
+ return true;
+ // Test edge u1, u2 against v0, v1.
+ if (edgeEdgeTest(delta, v0, u1, u2))
+ return true;
+ // Test edge u2, u1 against v0, v1.
+ if (edgeEdgeTest(delta, v0, u2, u0))
+ return true;
+ return false;
+}
+
+// A roundoff factor in the cubic classification and texture coordinate
+// generation algorithms. It primarily determines the handling of corner
+// cases during the classification process. Be careful when adjusting it;
+// it has been determined empirically to work well. When changing it, you
+// should look in particular at shapes that contain quadratic curves and
+// ensure they still look smooth. Once pixel tests are running against this
+// algorithm, they should provide sufficient coverage to ensure that
+// adjusting the constant won't break anything.
+const float Epsilon = 5.0e-4f;
+
+} // anonymous namespace
+
+// Exported routines
+
+float roundToZero(float val)
+{
+ if (val < Epsilon && val > -Epsilon)
+ return 0;
+ return val;
+}
+
+bool approxEqual(const FloatPoint& v0, const FloatPoint& v1)
+{
+ return (v0 - v1).diagonalLengthSquared() < Epsilon * Epsilon;
+}
+
+bool approxEqual(const FloatPoint3D& v0, const FloatPoint3D& v1)
+{
+ return (v0 - v1).lengthSquared() < Epsilon * Epsilon;
+}
+
+bool approxEqual(float f0, float f1)
+{
+ return fabsf(f0 - f1) < Epsilon;
+}
+
+bool linesIntersect(const FloatPoint& p1,
+ const FloatPoint& q1,
+ const FloatPoint& p2,
+ const FloatPoint& q2)
+{
+ return (orientation(p1, q1, p2) != orientation(p1, q1, q2)
+ && orientation(p2, q2, p1) != orientation(p2, q2, q1));
+}
+
+bool pointInTriangle(const FloatPoint& point,
+ const FloatPoint& a,
+ const FloatPoint& b,
+ const FloatPoint& c)
+{
+ // Algorithm from http://www.blackpawn.com/texts/pointinpoly/default.html
+ float x0 = c.x() - a.x();
+ float y0 = c.y() - a.y();
+ float x1 = b.x() - a.x();
+ float y1 = b.y() - a.y();
+ float x2 = point.x() - a.x();
+ float y2 = point.y() - a.y();
+
+ float dot00 = x0 * x0 + y0 * y0;
+ float dot01 = x0 * x1 + y0 * y1;
+ float dot02 = x0 * x2 + y0 * y2;
+ float dot11 = x1 * x1 + y1 * y1;
+ float dot12 = x1 * x2 + y1 * y2;
+ float denominator = dot00 * dot11 - dot01 * dot01;
+ if (!denominator)
+ // Triangle is zero-area. Treat query point as not being inside.
+ return false;
+ // Compute
+ float inverseDenominator = 1.0f / denominator;
+ float u = (dot11 * dot02 - dot01 * dot12) * inverseDenominator;
+ float v = (dot00 * dot12 - dot01 * dot02) * inverseDenominator;
+
+ return (u > 0.0f) && (v > 0.0f) && (u + v < 1.0f);
+}
+
+bool trianglesOverlap(const FloatPoint& a1,
+ const FloatPoint& b1,
+ const FloatPoint& c1,
+ const FloatPoint& a2,
+ const FloatPoint& b2,
+ const FloatPoint& c2)
+{
+ // Derived from coplanar_tri_tri() at
+ // http://jgt.akpeters.com/papers/ShenHengTang03/tri_tri.html ,
+ // simplified for the 2D case and modified so that overlapping edges
+ // do not report overlapping triangles.
+
+ // Test all edges of triangle 1 against the edges of triangle 2.
+ if (edgeAgainstTriangleEdges(a1, b1, a2, b2, c2)
+ || edgeAgainstTriangleEdges(b1, c1, a2, b2, c2)
+ || edgeAgainstTriangleEdges(c1, a1, a2, b2, c2))
+ return true;
+ // Finally, test if tri1 is totally contained in tri2 or vice versa.
+ // The paper above only performs the first two point-in-triangle tests.
+ // Because we define that triangles sharing a vertex or edge don't
+ // overlap, we must perform additional tests to see whether one
+ // triangle is contained in the other.
+ if (pointInTriangle(a1, a2, b2, c2)
+ || pointInTriangle(a2, a1, b1, c1)
+ || pointInTriangle(b1, a2, b2, c2)
+ || pointInTriangle(b2, a1, b1, c1)
+ || pointInTriangle(c1, a2, b2, c2)
+ || pointInTriangle(c2, a1, b1, c1))
+ return true;
+ return false;
+}
+
+namespace {
+
+// Helper routines for public XRay queries below. All of this code
+// originated in Skia; see include/core/ and src/core/, SkScalar.h and
+// SkGeometry.{cpp,h}.
+
+const float NearlyZeroConstant = (1.0f / (1 << 12));
+
+bool nearlyZero(float x, float tolerance = NearlyZeroConstant)
+{
+ ASSERT(tolerance > 0.0f);
+ return ::fabsf(x) < tolerance;
+}
+
+// Linearly interpolate between a and b, based on t.
+// If t is 0, return a; if t is 1, return b; else interpolate.
+// t must be [0..1].
+float interpolate(float a, float b, float t)
+{
+ ASSERT(t >= 0 && t <= 1);
+ return a + (b - a) * t;
+}
+
+float evaluateCubic(float controlPoint0, float controlPoint1, float controlPoint2, float controlPoint3, float t)
+{
+ ASSERT(t >= 0 && t <= 1);
+
+ if (!t)
+ return controlPoint0;
+
+ float ab = interpolate(controlPoint0, controlPoint1, t);
+ float bc = interpolate(controlPoint1, controlPoint2, t);
+ float cd = interpolate(controlPoint2, controlPoint3, t);
+ float abc = interpolate(ab, bc, t);
+ float bcd = interpolate(bc, cd, t);
+ return interpolate(abc, bcd, t);
+}
+
+// Evaluates the point on the source cubic specified by t, 0 <= t <= 1.0.
+FloatPoint evaluateCubicAt(const FloatPoint cubic[4], float t)
+{
+ return FloatPoint(evaluateCubic(cubic[0].x(), cubic[1].x(), cubic[2].x(), cubic[3].x(), t),
+ evaluateCubic(cubic[0].y(), cubic[1].y(), cubic[2].y(), cubic[3].y(), t));
+}
+
+bool xRayCrossesMonotonicCubic(const XRay& xRay, const FloatPoint cubic[4], bool& ambiguous)
+{
+ ambiguous = false;
+
+ // Find the minimum and maximum y of the extrema, which are the
+ // first and last points since this cubic is monotonic
+ float minY = std::min(cubic[0].y(), cubic[3].y());
+ float maxY = std::max(cubic[0].y(), cubic[3].y());
+
+ if (xRay.y() == cubic[0].y()
+ || xRay.y() < minY
+ || xRay.y() > maxY) {
+ // The query line definitely does not cross the curve
+ ambiguous = (xRay.y() == cubic[0].y());
+ return false;
+ }
+
+ const bool pointAtExtremum = (xRay.y() == cubic[3].y());
+
+ float minX = std::min(std::min(std::min(cubic[0].x(), cubic[1].x()),
+ cubic[2].x()),
+ cubic[3].x());
+ if (xRay.x() < minX) {
+ // The query line definitely crosses the curve
+ ambiguous = pointAtExtremum;
+ return true;
+ }
+
+ float maxX = std::max(std::max(std::max(cubic[0].x(), cubic[1].x()),
+ cubic[2].x()),
+ cubic[3].x());
+ if (xRay.x() > maxX)
+ // The query line definitely does not cross the curve
+ return false;
+
+ // Do a binary search to find the parameter value which makes y as
+ // close as possible to the query point. See whether the query
+ // line's origin is to the left of the associated x coordinate.
+
+ // MaxIterations is chosen as the number of mantissa bits for a float,
+ // since there's no way we are going to get more precision by
+ // iterating more times than that.
+ const int MaxIterations = 23;
+ FloatPoint evaluatedPoint;
+ int iter = 0;
+ float upperT;
+ float lowerT;
+ // Need to invert direction of t parameter if cubic goes up
+ // instead of down
+ if (cubic[3].y() > cubic[0].y()) {
+ upperT = 1;
+ lowerT = 0;
+ } else {
+ upperT = 0;
+ lowerT = 1;
+ }
+ do {
+ float t = 0.5f * (upperT + lowerT);
+ evaluatedPoint = evaluateCubicAt(cubic, t);
+ if (xRay.y() > evaluatedPoint.y())
+ lowerT = t;
+ else
+ upperT = t;
+ } while (++iter < MaxIterations && !nearlyZero(evaluatedPoint.y() - xRay.y()));
+
+ // FIXME: once we have more regression tests for this code,
+ // determine whether this should be using a fuzzy test.
+ if (xRay.x() <= evaluatedPoint.x()) {
+ ambiguous = pointAtExtremum;
+ return true;
+ }
+ return false;
+}
+
+// Divides the numerator by the denominator safely for the case where
+// the result must lie in the range (0..1). Result indicates whether
+// the result is valid.
+bool safeUnitDivide(float numerator, float denominator, float& ratio)
+{
+ if (numerator < 0) {
+ // Make the "numerator >= denominator" check below work.
+ numerator = -numerator;
+ denominator = -denominator;
+ }
+ if (!numerator || !denominator || numerator >= denominator)
+ return false;
+ float r = numerator / denominator;
+ if (isnan(r))
+ return false;
+ ASSERT(r >= 0 && r < 1);
+ if (!r) // catch underflow if numerator <<<< denominator
+ return false;
+ ratio = r;
+ return true;
+}
+
+// From Numerical Recipes in C.
+//
+// q = -1/2 (b + sign(b) sqrt[b*b - 4*a*c])
+// x1 = q / a
+// x2 = c / q
+//
+// Returns the number of real roots of the equation [0..2]. Roots are
+// returned in sorted order, smaller root first.
+int findUnitQuadRoots(float a, float b, float c, float roots[2])
+{
+ if (!a)
+ return safeUnitDivide(-c, b, roots[0]) ? 1 : 0;
+
+ float discriminant = b*b - 4*a*c;
+ if (discriminant < 0 || isnan(discriminant)) // complex roots
+ return 0;
+ discriminant = sqrtf(discriminant);
+
+ float q = (b < 0) ? -(b - discriminant) / 2 : -(b + discriminant) / 2;
+ int numberOfRoots = 0;
+ if (safeUnitDivide(q, a, roots[numberOfRoots]))
+ ++numberOfRoots;
+ if (safeUnitDivide(c, q, roots[numberOfRoots]))
+ ++numberOfRoots;
+ if (numberOfRoots == 2) {
+ // Seemingly have two roots. Check for equality and sort.
+ if (roots[0] == roots[1])
+ return 1;
+ if (roots[0] > roots[1])
+ std::swap(roots[0], roots[1]);
+ }
+ return numberOfRoots;
+}
+
+// Cubic'(t) = pt^2 + qt + r, where
+// p = 3(-a + 3(b - c) + d)
+// q = 6(a - 2b + c)
+// r = 3(b - a)
+// Solve for t, keeping only those that fit between 0 < t < 1.
+int findCubicExtrema(float a, float b, float c, float d, float tValues[2])
+{
+ // Divide p, q, and r by 3 to simplify the equations.
+ float p = d - a + 3*(b - c);
+ float q = 2*(a - b - b + c);
+ float r = b - a;
+
+ return findUnitQuadRoots(p, q, r, tValues);
+}
+
+void interpolateCubicCoords(float controlPoint0, float controlPoint1, float controlPoint2, float controlPoint3, float* dst, float t)
+{
+ float ab = interpolate(controlPoint0, controlPoint1, t);
+ float bc = interpolate(controlPoint1, controlPoint2, t);
+ float cd = interpolate(controlPoint2, controlPoint3, t);
+ float abc = interpolate(ab, bc, t);
+ float bcd = interpolate(bc, cd, t);
+ float abcd = interpolate(abc, bcd, t);
+
+ dst[0] = controlPoint0;
+ dst[2] = ab;
+ dst[4] = abc;
+ dst[6] = abcd;
+ dst[8] = bcd;
+ dst[10] = cd;
+ dst[12] = controlPoint3;
+}
+
+#ifndef NDEBUG
+bool isUnitInterval(float x)
+{
+ return x > 0 && x < 1;
+}
+#endif
+
+void chopCubicAtTValues(const FloatPoint src[4], FloatPoint dst[], const float tValues[], int roots)
+{
+#ifndef NDEBUG
+ for (int i = 0; i < roots - 1; ++i) {
+ ASSERT(isUnitInterval(tValues[i]));
+ ASSERT(isUnitInterval(tValues[i+1]));
+ ASSERT(tValues[i] < tValues[i+1]);
+ }
+#endif
+
+ if (!roots) {
+ // nothing to chop
+ for (int j = 0; j < 4; ++j)
+ dst[j] = src[j];
+ return;
+ }
+
+ float t = tValues[0];
+ FloatPoint tmp[4];
+ for (int j = 0; j < 4; ++j)
+ tmp[j] = src[j];
+
+ for (int i = 0; i < roots; ++i) {
+ chopCubicAt(tmp, dst, t);
+ if (i == roots - 1)
+ break;
+
+ dst += 3;
+ // Make tmp contain the remaining cubic (after the first chop).
+ for (int j = 0; j < 4; ++j)
+ tmp[j] = dst[j];
+
+ // Watch out for the case that the renormalized t isn't in range.
+ if (!safeUnitDivide(tValues[i+1] - tValues[i], 1.0f - tValues[i], t)) {
+ // If it isn't, just create a degenerate cubic.
+ dst[4] = dst[5] = dst[6] = tmp[3];
+ break;
+ }
+ }
+}
+
+void flattenDoubleCubicYExtrema(FloatPoint coords[7])
+{
+ coords[2].setY(coords[3].y());
+ coords[4].setY(coords[3].y());
+}
+
+int chopCubicAtYExtrema(const FloatPoint src[4], FloatPoint dst[10])
+{
+ float tValues[2];
+ int roots = findCubicExtrema(src[0].y(), src[1].y(), src[2].y(), src[3].y(), tValues);
+
+ chopCubicAtTValues(src, dst, tValues, roots);
+ if (roots) {
+ // we do some cleanup to ensure our Y extrema are flat
+ flattenDoubleCubicYExtrema(&dst[0]);
+ if (roots == 2)
+ flattenDoubleCubicYExtrema(&dst[3]);
+ }
+ return roots;
+}
+
+} // anonymous namespace
+
+// Public cubic operations.
+
+void chopCubicAt(const FloatPoint src[4], FloatPoint dst[7], float t)
+{
+ ASSERT(t >= 0 && t <= 1);
+
+ float output[14];
+ interpolateCubicCoords(src[0].x(), src[1].x(), src[2].x(), src[3].x(), &output[0], t);
+ interpolateCubicCoords(src[0].y(), src[1].y(), src[2].y(), src[3].y(), &output[1], t);
+ for (int i = 0; i < 7; i++)
+ dst[i].set(output[2 * i], output[2 * i + 1]);
+}
+
+// Public XRay queries.
+
+bool xRayCrossesLine(const XRay& xRay, const FloatPoint pts[2], bool& ambiguous)
+{
+ ambiguous = false;
+
+ // Determine quick discards.
+ // Consider query line going exactly through point 0 to not
+ // intersect, for symmetry with xRayCrossesMonotonicCubic.
+ if (xRay.y() == pts[0].y()) {
+ ambiguous = true;
+ return false;
+ }
+ if (xRay.y() < pts[0].y() && xRay.y() < pts[1].y())
+ return false;
+ if (xRay.y() > pts[0].y() && xRay.y() > pts[1].y())
+ return false;
+ if (xRay.x() > pts[0].x() && xRay.x() > pts[1].x())
+ return false;
+ // Determine degenerate cases
+ if (nearlyZero(pts[0].y() - pts[1].y()))
+ return false;
+ if (nearlyZero(pts[0].x() - pts[1].x())) {
+ // We've already determined the query point lies within the
+ // vertical range of the line segment.
+ if (xRay.x() <= pts[0].x()) {
+ ambiguous = (xRay.y() == pts[1].y());
+ return true;
+ }
+ return false;
+ }
+ // Ambiguity check
+ if (xRay.y() == pts[1].y()) {
+ if (xRay.x() <= pts[1].x()) {
+ ambiguous = true;
+ return true;
+ }
+ return false;
+ }
+ // Full line segment evaluation
+ float deltaY = pts[1].y() - pts[0].y();
+ float deltaX = pts[1].x() - pts[0].x();
+ float slope = deltaY / deltaX;
+ float b = pts[0].y() - slope * pts[0].x();
+ // Solve for x coordinate at y = xRay.y()
+ float x = (xRay.y() - b) / slope;
+ return xRay.x() <= x;
+}
+
+int numXRayCrossingsForCubic(const XRay& xRay, const FloatPoint cubic[4], bool& ambiguous)
+{
+ int numCrossings = 0;
+ FloatPoint monotonicCubics[10];
+ int numMonotonicCubics = 1 + chopCubicAtYExtrema(cubic, monotonicCubics);
+ ambiguous = false;
+ FloatPoint* monotonicCubicsPointer = &monotonicCubics[0];
+ for (int i = 0; i < numMonotonicCubics; ++i) {
+ if (xRayCrossesMonotonicCubic(xRay, monotonicCubicsPointer, ambiguous))
+ ++numCrossings;
+ if (ambiguous)
+ return 0;
+ monotonicCubicsPointer += 3;
+ }
+ return numCrossings;
+}
+
+} // namespace LoopBlinnMathUtils
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h
new file mode 100644
index 0000000..b9d19c5
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 LoopBlinnMathUtils_h
+#define LoopBlinnMathUtils_h
+
+#include "FloatPoint.h"
+#include "FloatPoint3D.h"
+#include <math.h>
+
+namespace WebCore {
+
+// Use a namespace for these so we can easily import them.
+namespace LoopBlinnMathUtils {
+
+float roundToZero(float val);
+bool approxEqual(const FloatPoint& v0, const FloatPoint& v1);
+bool approxEqual(const FloatPoint3D& v0, const FloatPoint3D& v1);
+bool approxEqual(float f0, float f1);
+
+// Determines whether the line segment between (p1, q1) intersects
+// that between (p2, q2).
+bool linesIntersect(const FloatPoint& p1,
+ const FloatPoint& q1,
+ const FloatPoint& p2,
+ const FloatPoint& q2);
+
+// Determines whether "point" is inside the 2D triangle defined by
+// vertices a, b, and c. This test defines that points exactly on an
+// edge are not considered to be inside the triangle.
+bool pointInTriangle(const FloatPoint& point,
+ const FloatPoint& a,
+ const FloatPoint& b,
+ const FloatPoint& c);
+
+// Determines whether the triangles defined by the points (a1, b1, c1)
+// and (a2, b2, c2) overlap. The definition of this function is that
+// if the two triangles only share an adjacent edge or vertex, they
+// are not considered to overlap.
+bool trianglesOverlap(const FloatPoint& a1,
+ const FloatPoint& b1,
+ const FloatPoint& c1,
+ const FloatPoint& a2,
+ const FloatPoint& b2,
+ const FloatPoint& c2);
+
+// Given a src cubic bezier, chops it at the specified t value,
+// where 0 < t < 1, and returns the two new cubics in dst[0..3]
+// and dst[3..6].
+void chopCubicAt(const FloatPoint src[4], FloatPoint dst[7], float t);
+
+// "X-Ray" queries. An XRay is a half-line originating at the given
+// point and extending to x=+infinity.
+typedef FloatPoint XRay;
+
+// Given an arbitrary cubic bezier, return the number of times an XRay
+// crosses the cubic. Valid return values are [0..3].
+//
+// By definition the cubic is open at the starting point; in other
+// words, if pt.fY is equivalent to cubic[0].fY, and pt.fX is to the
+// left of the curve, the line is not considered to cross the curve,
+// but if it is equal to cubic[3].fY then it is considered to
+// cross.
+//
+// Outgoing "ambiguous" argument indicates whether the answer is ambiguous
+// because the query occurred exactly at one of the endpoints' y
+// coordinates or at a tangent point, indicating that another query y
+// coordinate is preferred for robustness.
+int numXRayCrossingsForCubic(const XRay& xRay,
+ const FloatPoint cubic[4],
+ bool& ambiguous);
+
+// Given a line segment from lineEndpoints[0] to lineEndpoints[1], and an
+// XRay, returns true if they intersect. Outgoing "ambiguous" argument
+// indicates whether the answer is ambiguous because the query occurred
+// exactly at one of the endpoints' y coordinates, indicating that another
+// query y coordinate is preferred for robustness.
+bool xRayCrossesLine(const XRay& xRay,
+ const FloatPoint lineEndpoints[2],
+ bool& ambiguous);
+
+} // namespace LoopBlinnMathUtils
+
+} // namespace WebCore
+
+#endif // LoopBlinnMathUtils_h
diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp
new file mode 100644
index 0000000..d272fe1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "LoopBlinnTextureCoords.h"
+
+#include <math.h>
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+LoopBlinnTextureCoords::Result LoopBlinnTextureCoords::compute(const LoopBlinnClassifier::Result& classification, LoopBlinnConstants::FillSide sideToFill)
+{
+ // Loop and Blinn's formulation states that the right side of the
+ // curve is defined to be the inside (filled region), but for some
+ // reason it looks like with the default orientation parameters we
+ // are filling the left side of the curve. Regardless, because we
+ // can receive arbitrarily oriented curves as input, we might have
+ // to reverse the orientation of the cubic texture coordinates even
+ // in cases where the paper doesn't say it is necessary.
+ bool reverseOrientation = false;
+ static const float OneThird = 1.0f / 3.0f;
+ static const float TwoThirds = 2.0f / 3.0f;
+ LoopBlinnClassifier::CurveType curveType = classification.curveType;
+
+ LoopBlinnTextureCoords::Result result;
+
+ switch (curveType) {
+ case LoopBlinnClassifier::kSerpentine: {
+ float t1 = sqrtf(9.0f * classification.d2 * classification.d2 - 12 * classification.d1 * classification.d3);
+ float ls = 3.0f * classification.d2 - t1;
+ float lt = 6.0f * classification.d1;
+ float ms = 3.0f * classification.d2 + t1;
+ float mt = lt;
+ float ltMinusLs = lt - ls;
+ float mtMinusMs = mt - ms;
+ result.klmCoordinates[0] = FloatPoint3D(ls * ms,
+ ls * ls * ls,
+ ms * ms * ms);
+ result.klmCoordinates[1] = FloatPoint3D(OneThird * (3.0f * ls * ms - ls * mt - lt * ms),
+ ls * ls * (ls - lt),
+ ms * ms * (ms - mt));
+ result.klmCoordinates[2] = FloatPoint3D(OneThird * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt)),
+ ltMinusLs * ltMinusLs * ls,
+ mtMinusMs * mtMinusMs * ms);
+ result.klmCoordinates[3] = FloatPoint3D(ltMinusLs * mtMinusMs,
+ -(ltMinusLs * ltMinusLs * ltMinusLs),
+ -(mtMinusMs * mtMinusMs * mtMinusMs));
+ if (classification.d1 < 0.0f)
+ reverseOrientation = true;
+ break;
+ }
+
+ case LoopBlinnClassifier::kLoop: {
+ float t1 = sqrtf(4.0f * classification.d1 * classification.d3 - 3.0f * classification.d2 * classification.d2);
+ float ls = classification.d2 - t1;
+ float lt = 2.0f * classification.d1;
+ float ms = classification.d2 + t1;
+ float mt = lt;
+
+ // Figure out whether there is a rendering artifact requiring
+ // the curve to be subdivided by the caller.
+ float ql = ls / lt;
+ float qm = ms / mt;
+ if (0.0f < ql && ql < 1.0f) {
+ result.hasRenderingArtifact = true;
+ result.subdivisionParameterValue = ql;
+ return result;
+ }
+
+ if (0.0f < qm && qm < 1.0f) {
+ result.hasRenderingArtifact = true;
+ result.subdivisionParameterValue = qm;
+ return result;
+ }
+
+ float ltMinusLs = lt - ls;
+ float mtMinusMs = mt - ms;
+ result.klmCoordinates[0] = FloatPoint3D(ls * ms,
+ ls * ls * ms,
+ ls * ms * ms);
+ result.klmCoordinates[1] = FloatPoint3D(OneThird * (-ls * mt - lt * ms + 3.0f * ls * ms),
+ -OneThird * ls * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms),
+ -OneThird * ms * (ls * (2.0f * mt - 3.0f * ms) + lt * ms));
+ result.klmCoordinates[2] = FloatPoint3D(OneThird * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt)),
+ OneThird * (lt - ls) * (ls * (2.0f * mt - 3.0f * ms) + lt * ms),
+ OneThird * (mt - ms) * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms));
+ result.klmCoordinates[3] = FloatPoint3D(ltMinusLs * mtMinusMs,
+ -(ltMinusLs * ltMinusLs) * mtMinusMs,
+ -ltMinusLs * mtMinusMs * mtMinusMs);
+ reverseOrientation = ((classification.d1 > 0.0f && result.klmCoordinates[0].x() < 0.0f)
+ || (classification.d1 < 0.0f && result.klmCoordinates[0].x() > 0.0f));
+ break;
+ }
+
+ case LoopBlinnClassifier::kCusp: {
+ float ls = classification.d3;
+ float lt = 3.0f * classification.d2;
+ float lsMinusLt = ls - lt;
+ result.klmCoordinates[0] = FloatPoint3D(ls,
+ ls * ls * ls,
+ 1.0f);
+ result.klmCoordinates[1] = FloatPoint3D(ls - OneThird * lt,
+ ls * ls * lsMinusLt,
+ 1.0f);
+ result.klmCoordinates[2] = FloatPoint3D(ls - TwoThirds * lt,
+ lsMinusLt * lsMinusLt * ls,
+ 1.0f);
+ result.klmCoordinates[3] = FloatPoint3D(lsMinusLt,
+ lsMinusLt * lsMinusLt * lsMinusLt,
+ 1.0f);
+ break;
+ }
+
+ case LoopBlinnClassifier::kQuadratic: {
+ result.klmCoordinates[0] = FloatPoint3D(0, 0, 0);
+ result.klmCoordinates[1] = FloatPoint3D(OneThird, 0, OneThird);
+ result.klmCoordinates[2] = FloatPoint3D(TwoThirds, OneThird, TwoThirds);
+ result.klmCoordinates[3] = FloatPoint3D(1, 1, 1);
+ if (classification.d3 < 0)
+ reverseOrientation = true;
+ break;
+ }
+
+ case LoopBlinnClassifier::kLine:
+ case LoopBlinnClassifier::kPoint:
+ result.isLineOrPoint = true;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ if (sideToFill == LoopBlinnConstants::RightSide)
+ reverseOrientation = !reverseOrientation;
+
+ if (reverseOrientation) {
+ for (int i = 0; i < 4; ++i) {
+ result.klmCoordinates[i].setX(-result.klmCoordinates[i].x());
+ result.klmCoordinates[i].setY(-result.klmCoordinates[i].y());
+ }
+ }
+
+ return result;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.h
new file mode 100644
index 0000000..5fdeb3b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 LoopBlinnTextureCoords_h
+#define LoopBlinnTextureCoords_h
+
+#include "FloatPoint3D.h"
+#include "LoopBlinnClassifier.h"
+#include "LoopBlinnConstants.h"
+
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+// Computes three-dimensional texture coordinates for the control
+// points of a cubic curve for rendering via the shader in "Rendering
+// Vector Art on the GPU" by Loop and Blinn, GPU Gems 3, Chapter 25.
+class LoopBlinnTextureCoords {
+public:
+ // Container for the cubic texture coordinates and other associated
+ // information.
+ struct Result {
+ Result()
+ : isLineOrPoint(false)
+ , hasRenderingArtifact(false)
+ , subdivisionParameterValue(0.0f) { }
+
+ // The (k, l, m) texture coordinates that are to be associated
+ // with the four control points of the cubic curve.
+ FloatPoint3D klmCoordinates[4];
+
+ // Indicates whether the curve is a line or a point, in which case
+ // we do not need to add its triangles to the mesh.
+ bool isLineOrPoint;
+
+ // For the loop case, indicates whether a rendering artifact was
+ // detected, in which case the curve needs to be further
+ // subdivided.
+ bool hasRenderingArtifact;
+
+ // If a rendering artifact will occur for the given loop curve,
+ // this is the parameter value (0 <= value <= 1) at which the
+ // curve needs to be subdivided to fix the artifact.
+ float subdivisionParameterValue;
+ };
+
+ // Computes the texture coordinates for a cubic curve segment's
+ // control points, given the classification of the curve as well as
+ // an indication of which side is to be filled.
+ static Result compute(const LoopBlinnClassifier::Result& classification,
+ LoopBlinnConstants::FillSide sideToFill);
+
+private:
+ // This class does not need to be instantiated.
+ LoopBlinnTextureCoords() { }
+};
+
+} // namespace WebCore
+
+#endif // LoopBlinnTextureCoords_h
diff --git a/Source/WebCore/platform/graphics/gpu/PODArena.h b/Source/WebCore/platform/graphics/gpu/PODArena.h
new file mode 100644
index 0000000..f68baef
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/PODArena.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PODArena_h
+#define PODArena_h
+
+#include <stdint.h>
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// An arena which allocates only Plain Old Data (POD), or classes and
+// structs bottoming out in Plain Old Data. NOTE: the constructors of
+// the objects allocated in this arena are called, but _not_ their
+// destructors.
+
+class PODArena : public RefCounted<PODArena> {
+public:
+ // The arena is configured with an allocator, which is responsible
+ // for allocating and freeing chunks of memory at a time.
+ class Allocator : public RefCounted<Allocator> {
+ public:
+ virtual void* allocate(size_t size) = 0;
+ virtual void free(void* ptr) = 0;
+ protected:
+ virtual ~Allocator() { }
+ friend class WTF::RefCounted<Allocator>;
+ };
+
+ // The Arena's default allocator, which uses fastMalloc and
+ // fastFree to allocate chunks of storage.
+ class FastMallocAllocator : public Allocator {
+ public:
+ static PassRefPtr<FastMallocAllocator> create()
+ {
+ return adoptRef(new FastMallocAllocator);
+ }
+
+ virtual void* allocate(size_t size) { return fastMalloc(size); }
+ virtual void free(void* ptr) { fastFree(ptr); }
+
+ protected:
+ FastMallocAllocator() { }
+ };
+
+ // Creates a new PODArena configured with a FastMallocAllocator.
+ static PassRefPtr<PODArena> create()
+ {
+ return adoptRef(new PODArena);
+ }
+
+ // Creates a new PODArena configured with the given Allocator.
+ static PassRefPtr<PODArena> create(PassRefPtr<Allocator> allocator)
+ {
+ return adoptRef(new PODArena(allocator));
+ }
+
+ // Allocates an object from the arena.
+ template<class T> T* allocateObject()
+ {
+ void* ptr = allocateBase<T>();
+ if (ptr) {
+ // Use placement operator new to allocate a T at this location.
+ new(ptr) T();
+ }
+ return static_cast<T*>(ptr);
+ }
+
+ // Allocates an object from the arena, calling a single-argument constructor.
+ template<class T, class Argument1Type> T* allocateObject(const Argument1Type& argument1)
+ {
+ void* ptr = allocateBase<T>();
+ if (ptr) {
+ // Use placement operator new to allocate a T at this location.
+ new(ptr) T(argument1);
+ }
+ return static_cast<T*>(ptr);
+ }
+
+ // The initial size of allocated chunks; increases as necessary to
+ // satisfy large allocations. Mainly public for unit tests.
+ enum {
+ DefaultChunkSize = 16384
+ };
+
+protected:
+ ~PODArena() { }
+ friend class WTF::RefCounted<PODArena>;
+
+private:
+ PODArena()
+ : m_allocator(FastMallocAllocator::create())
+ , m_current(0)
+ , m_currentChunkSize(DefaultChunkSize) { }
+
+ explicit PODArena(PassRefPtr<Allocator> allocator)
+ : m_allocator(allocator)
+ , m_current(0)
+ , m_currentChunkSize(DefaultChunkSize) { }
+
+ // Returns the alignment requirement for classes and structs on the
+ // current platform.
+ template <class T> static size_t minAlignment()
+ {
+ return WTF_ALIGN_OF(T);
+ }
+
+ template<class T> void* allocateBase()
+ {
+ void* ptr = 0;
+ size_t roundedSize = roundUp(sizeof(T), minAlignment<T>());
+ if (m_current)
+ ptr = m_current->allocate(roundedSize);
+
+ if (!ptr) {
+ if (roundedSize > m_currentChunkSize)
+ m_currentChunkSize = roundedSize;
+ m_chunks.append(adoptPtr(new Chunk(m_allocator.get(), m_currentChunkSize)));
+ m_current = m_chunks.last().get();
+ ptr = m_current->allocate(roundedSize);
+ }
+ return ptr;
+ }
+
+ // Rounds up the given allocation size to the specified alignment.
+ size_t roundUp(size_t size, size_t alignment)
+ {
+ ASSERT(!(alignment % 2));
+ return (size + alignment - 1) & ~(alignment - 1);
+ }
+
+ // Manages a chunk of memory and individual allocations out of it.
+ class Chunk : public Noncopyable {
+ public:
+ // Allocates a block of memory of the given size from the passed
+ // Allocator.
+ Chunk(Allocator* allocator, size_t size)
+ : m_allocator(allocator)
+ , m_size(size)
+ , m_currentOffset(0)
+ {
+ m_base = static_cast<uint8_t*>(m_allocator->allocate(size));
+ }
+
+ // Frees the memory allocated from the Allocator in the
+ // constructor.
+ ~Chunk()
+ {
+ m_allocator->free(m_base);
+ }
+
+ // Returns a pointer to "size" bytes of storage, or 0 if this
+ // Chunk could not satisfy the allocation.
+ void* allocate(size_t size)
+ {
+ // Check for overflow
+ if (m_currentOffset + size < m_currentOffset)
+ return 0;
+
+ if (m_currentOffset + size > m_size)
+ return 0;
+
+ void* result = m_base + m_currentOffset;
+ m_currentOffset += size;
+ return result;
+ }
+
+ private:
+ Allocator* m_allocator;
+ uint8_t* m_base;
+ size_t m_size;
+ size_t m_currentOffset;
+ };
+
+ RefPtr<Allocator> m_allocator;
+ Chunk* m_current;
+ size_t m_currentChunkSize;
+ Vector<OwnPtr<Chunk> > m_chunks;
+};
+
+} // namespace WebCore
+
+#endif // PODArena_h
diff --git a/Source/WebCore/platform/graphics/gpu/PODInterval.h b/Source/WebCore/platform/graphics/gpu/PODInterval.h
new file mode 100644
index 0000000..5c1dcc2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/PODInterval.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PODInterval_h
+#define PODInterval_h
+
+#ifndef NDEBUG
+#include <wtf/text/StringBuilder.h>
+#endif
+
+namespace WebCore {
+
+// Class representing a closed interval which can hold an arbitrary
+// Plain Old Datatype (POD) as its endpoints and a piece of user
+// data. An important characteristic for the algorithms we use is that
+// if two intervals have identical endpoints but different user data,
+// they are not considered to be equal. This situation can arise when
+// representing the vertical extents of bounding boxes of overlapping
+// triangles, where the pointer to the triangle is the user data of
+// the interval.
+//
+// *Note* that the destructors of type T and UserData will *not* be
+// called by this class. They must not allocate any memory that is
+// required to be cleaned up in their destructors.
+//
+// The following constructors and operators must be implemented on
+// type T:
+//
+// - Copy constructor (if user data is desired)
+// - operator<
+// - operator==
+// - operator=
+//
+// If the UserData type is specified, it must support a copy
+// constructor and assignment operator.
+//
+// In debug mode, printing of intervals and the data they contain is
+// enabled. This requires the following template specializations to be
+// available:
+//
+// template<> struct WebCore::ValueToString<T> {
+// static String string(const T& t);
+// };
+// template<> struct WebCore::ValueToString<UserData> {
+// static String string(const UserData& t);
+// };
+//
+// Note that this class requires a copy constructor and assignment
+// operator in order to be stored in the red-black tree.
+
+#ifndef NDEBUG
+template<class T>
+struct ValueToString;
+#endif
+
+template<class T, class UserData = void*>
+class PODInterval {
+public:
+ // Constructor from endpoints. This constructor only works when the
+ // UserData type is a pointer or other type which can be initialized
+ // with 0.
+ PODInterval(const T& low, const T& high)
+ : m_low(low)
+ , m_high(high)
+ , m_data(0)
+ , m_maxHigh(high)
+ {
+ }
+
+ // Constructor from two endpoints plus explicit user data.
+ PODInterval(const T& low, const T& high, const UserData data)
+ : m_low(low)
+ , m_high(high)
+ , m_data(data)
+ , m_maxHigh(high)
+ {
+ }
+
+ const T& low() const { return m_low; }
+ const T& high() const { return m_high; }
+ const UserData& data() const { return m_data; }
+
+ bool overlaps(const T& low, const T& high) const
+ {
+ if (this->high() < low)
+ return false;
+ if (high < this->low())
+ return false;
+ return true;
+ }
+
+ bool overlaps(const PODInterval& other) const
+ {
+ return overlaps(other.low(), other.high());
+ }
+
+ // Returns true if this interval is "less" than the other. The
+ // comparison is performed on the low endpoints of the intervals.
+ bool operator<(const PODInterval& other) const
+ {
+ return low() < other.low();
+ }
+
+ // Returns true if this interval is strictly equal to the other,
+ // including comparison of the user data.
+ bool operator==(const PODInterval& other) const
+ {
+ return (low() == other.low()
+ && high() == other.high()
+ && data() == other.data());
+ }
+
+ const T& maxHigh() const { return m_maxHigh; }
+ void setMaxHigh(const T& maxHigh) { m_maxHigh = maxHigh; }
+
+#ifndef NDEBUG
+ // Support for printing PODIntervals.
+ String toString() const
+ {
+ StringBuilder builder;
+ builder.append("[PODInterval (");
+ builder.append(ValueToString<T>::string(low()));
+ builder.append(", ");
+ builder.append(ValueToString<T>::string(high()));
+ builder.append("), data=");
+ builder.append(ValueToString<UserData>::string(data()));
+ builder.append(", maxHigh=");
+ builder.append(ValueToString<T>::string(maxHigh()));
+ builder.append("]");
+ return builder.toString();
+ }
+#endif
+
+private:
+ T m_low;
+ T m_high;
+ UserData m_data;
+ T m_maxHigh;
+};
+
+} // namespace WebCore
+
+#endif // PODInterval_h
diff --git a/Source/WebCore/platform/graphics/gpu/PODIntervalTree.h b/Source/WebCore/platform/graphics/gpu/PODIntervalTree.h
new file mode 100644
index 0000000..320ce60
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/PODIntervalTree.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PODIntervalTree_h
+#define PODIntervalTree_h
+
+#include "PODArena.h"
+#include "PODInterval.h"
+#include "PODRedBlackTree.h"
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+#ifndef NDEBUG
+template<class T>
+struct ValueToString;
+#endif
+
+// An interval tree, which is a form of augmented red-black tree. It
+// supports efficient (O(lg n)) insertion, removal and querying of
+// intervals in the tree.
+template<class T, class UserData = void*>
+class PODIntervalTree : public Noncopyable,
+ public PODRedBlackTree<PODInterval<T, UserData> > {
+public:
+ // Typedef to reduce typing when declaring intervals to be stored in
+ // this tree.
+ typedef PODInterval<T, UserData> IntervalType;
+
+ PODIntervalTree()
+ : PODRedBlackTree<IntervalType>()
+ {
+ init();
+ }
+
+ explicit PODIntervalTree(PassRefPtr<PODArena> arena)
+ : PODRedBlackTree<IntervalType>(arena)
+ {
+ init();
+ }
+
+ // Returns all intervals in the tree which overlap the given query
+ // interval. The returned intervals are sorted by increasing low
+ // endpoint.
+ Vector<IntervalType> allOverlaps(const IntervalType& interval) const
+ {
+ Vector<IntervalType> result;
+ allOverlaps(interval, result);
+ return result;
+ }
+
+ // Returns all intervals in the tree which overlap the given query
+ // interval. The returned intervals are sorted by increasing low
+ // endpoint.
+ void allOverlaps(const IntervalType& interval, Vector<IntervalType>& result) const
+ {
+ // Explicit dereference of "this" required because of
+ // inheritance rules in template classes.
+ searchForOverlapsFrom(this->root(), interval, result);
+ }
+
+ // Helper to create interval objects.
+ static IntervalType createInterval(const T& low, const T& high, const UserData data = 0)
+ {
+ return IntervalType(low, high, data);
+ }
+
+ virtual bool checkInvariants() const
+ {
+ if (!PODRedBlackTree<IntervalType>::checkInvariants())
+ return false;
+ if (!this->root())
+ return true;
+ return checkInvariantsFromNode(this->root(), 0);
+ }
+
+private:
+ typedef typename PODRedBlackTree<IntervalType>::Node IntervalNode;
+
+ // Initializes the tree.
+ void init()
+ {
+ // Explicit dereference of "this" required because of
+ // inheritance rules in template classes.
+ this->setNeedsFullOrderingComparisons(true);
+ }
+
+ // Starting from the given node, adds all overlaps with the given
+ // interval to the result vector. The intervals are sorted by
+ // increasing low endpoint.
+ void searchForOverlapsFrom(IntervalNode* node, const IntervalType& interval, Vector<IntervalType>& res) const
+ {
+ if (!node)
+ return;
+
+ // Because the intervals are sorted by left endpoint, inorder
+ // traversal produces results sorted as desired.
+
+ // See whether we need to traverse the left subtree.
+ IntervalNode* left = node->left();
+ if (left
+ // This is phrased this way to avoid the need for operator
+ // <= on type T.
+ && !(left->data().maxHigh() < interval.low()))
+ searchForOverlapsFrom(left, interval, res);
+
+ // Check for overlap with current node.
+ if (node->data().overlaps(interval))
+ res.append(node->data());
+
+ // See whether we need to traverse the right subtree.
+ // This is phrased this way to avoid the need for operator <=
+ // on type T.
+ if (!(interval.high() < node->data().low()))
+ searchForOverlapsFrom(node->right(), interval, res);
+ }
+
+ virtual bool updateNode(IntervalNode* node)
+ {
+ // Would use const T&, but need to reassign this reference in this
+ // function.
+ const T* curMax = &node->data().high();
+ IntervalNode* left = node->left();
+ if (left) {
+ if (*curMax < left->data().maxHigh())
+ curMax = &left->data().maxHigh();
+ }
+ IntervalNode* right = node->right();
+ if (right) {
+ if (*curMax < right->data().maxHigh())
+ curMax = &right->data().maxHigh();
+ }
+ // This is phrased like this to avoid needing operator!= on type T.
+ if (!(*curMax == node->data().maxHigh())) {
+ node->data().setMaxHigh(*curMax);
+ return true;
+ }
+ return false;
+ }
+
+ bool checkInvariantsFromNode(IntervalNode* node, T* currentMaxValue) const
+ {
+ // These assignments are only done in order to avoid requiring
+ // a default constructor on type T.
+ T leftMaxValue(node->data().maxHigh());
+ T rightMaxValue(node->data().maxHigh());
+ IntervalNode* left = node->left();
+ IntervalNode* right = node->right();
+ if (left) {
+ if (!checkInvariantsFromNode(left, &leftMaxValue))
+ return false;
+ }
+ if (right) {
+ if (!checkInvariantsFromNode(right, &rightMaxValue))
+ return false;
+ }
+ if (!left && !right) {
+ // Base case.
+ if (currentMaxValue)
+ *currentMaxValue = node->data().high();
+ return (node->data().high() == node->data().maxHigh());
+ }
+ T localMaxValue(node->data().maxHigh());
+ if (!left || !right) {
+ if (left)
+ localMaxValue = leftMaxValue;
+ else
+ localMaxValue = rightMaxValue;
+ } else
+ localMaxValue = (leftMaxValue < rightMaxValue) ? rightMaxValue : leftMaxValue;
+ if (localMaxValue < node->data().high())
+ localMaxValue = node->data().high();
+ if (!(localMaxValue == node->data().maxHigh())) {
+#ifndef NDEBUG
+ String localMaxValueString = ValueToString<T>::string(localMaxValue);
+ LOG_ERROR("PODIntervalTree verification failed at node 0x%p: localMaxValue=%s and data=%s",
+ node, localMaxValueString.utf8().data(), node->data().toString().utf8().data());
+#endif
+ return false;
+ }
+ if (currentMaxValue)
+ *currentMaxValue = localMaxValue;
+ return true;
+ }
+};
+
+#ifndef NDEBUG
+// Support for printing PODIntervals at the PODRedBlackTree level.
+template<class T, class UserData>
+struct ValueToString<PODInterval<T, UserData> > {
+ static String string(const PODInterval<T, UserData>& interval)
+ {
+ return interval.toString();
+ }
+};
+#endif
+
+} // namespace WebCore
+
+#endif // PODIntervalTree_h
diff --git a/Source/WebCore/platform/graphics/gpu/PODRedBlackTree.h b/Source/WebCore/platform/graphics/gpu/PODRedBlackTree.h
new file mode 100644
index 0000000..6d5954c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/PODRedBlackTree.h
@@ -0,0 +1,757 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+// A red-black tree, which is a form of a balanced binary tree. It
+// supports efficient insertion, deletion and queries of comparable
+// elements. The same element may be inserted multiple times. The
+// algorithmic complexity of common operations is:
+//
+// Insertion: O(lg(n))
+// Deletion: O(lg(n))
+// Querying: O(lg(n))
+//
+// The data type T that is stored in this red-black tree must be only
+// Plain Old Data (POD), or bottom out into POD. It must _not_ rely on
+// having its destructor called. This implementation internally
+// allocates storage in large chunks and does not call the destructor
+// on each object.
+//
+// Type T must supply a default constructor, a copy constructor, and
+// the "<" and "==" operators.
+//
+// In debug mode, printing of the data contained in the tree is
+// enabled. This requires the template specialization to be available:
+//
+// template<> struct WebCore::ValueToString<T> {
+// static String string(const T& t);
+// };
+//
+// Note that when complex types are stored in this red/black tree, it
+// is possible that single invocations of the "<" and "==" operators
+// will be insufficient to describe the ordering of elements in the
+// tree during queries. As a concrete example, consider the case where
+// intervals are stored in the tree sorted by low endpoint. The "<"
+// operator on the Interval class only compares the low endpoint, but
+// the "==" operator takes into account the high endpoint as well.
+// This makes the necessary logic for querying and deletion somewhat
+// more complex. In order to properly handle such situations, the
+// property "needsFullOrderingComparisons" must be set to true on
+// the tree.
+//
+// This red-black tree is designed to be _augmented_; subclasses can
+// add additional and summary information to each node to efficiently
+// store and index more complex data structures. A concrete example is
+// the IntervalTree, which extends each node with a summary statistic
+// to efficiently store one-dimensional intervals.
+//
+// The design of this red-black tree comes from Cormen, Leiserson,
+// and Rivest, _Introduction to Algorithms_, MIT Press, 1990.
+
+#ifndef PODRedBlackTree_h
+#define PODRedBlackTree_h
+
+#include "PODArena.h"
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+#ifndef NDEBUG
+#include "Logging.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+#endif
+
+namespace WebCore {
+
+#ifndef NDEBUG
+template<class T>
+struct ValueToString;
+#endif
+
+template<class T>
+class PODRedBlackTree {
+public:
+ // Visitor interface for walking all of the tree's elements.
+ class Visitor {
+ public:
+ virtual void visit(const T& data) = 0;
+ protected:
+ virtual ~Visitor() { }
+ };
+
+ // Constructs a new red-black tree, allocating temporary objects
+ // from a newly constructed PODArena.
+ PODRedBlackTree()
+ : m_arena(PODArena::create())
+ , m_root(0)
+ , m_needsFullOrderingComparisons(false)
+#ifndef NDEBUG
+ , m_verboseDebugging(false)
+#endif
+ {
+ }
+
+ // Constructs a new red-black tree, allocating temporary objects
+ // from the given PODArena.
+ explicit PODRedBlackTree(PassRefPtr<PODArena> arena)
+ : m_arena(arena)
+ , m_root(0)
+ , m_needsFullOrderingComparisons(false)
+#ifndef NDEBUG
+ , m_verboseDebugging(false)
+#endif
+ {
+ }
+
+ virtual ~PODRedBlackTree() { }
+
+ void add(const T& data)
+ {
+ Node* node = m_arena->allocateObject<Node, T>(data);
+ insertNode(node);
+ }
+
+ // Returns true if the datum was found in the tree.
+ bool remove(const T& data)
+ {
+ Node* node = treeSearch(data);
+ if (node) {
+ deleteNode(node);
+ return true;
+ }
+ return false;
+ }
+
+ bool contains(const T& data) const { return treeSearch(data); }
+
+ void visitInorder(Visitor* visitor) const
+ {
+ if (!m_root)
+ return;
+ visitInorderImpl(m_root, visitor);
+ }
+
+ int size() const
+ {
+ Counter counter;
+ visitInorder(&counter);
+ return counter.count();
+ }
+
+ // See the class documentation for an explanation of this property.
+ void setNeedsFullOrderingComparisons(bool needsFullOrderingComparisons)
+ {
+ m_needsFullOrderingComparisons = needsFullOrderingComparisons;
+ }
+
+ virtual bool checkInvariants() const
+ {
+ int blackCount;
+ return checkInvariantsFromNode(m_root, &blackCount);
+ }
+
+#ifndef NDEBUG
+ // Dumps the tree's contents to the logging info stream for
+ // debugging purposes.
+ void dump() const
+ {
+ dumpFromNode(m_root, 0);
+ }
+
+ // Turns on or off verbose debugging of the tree, causing many
+ // messages to be logged during insertion and other operations in
+ // debug mode.
+ void setVerboseDebugging(bool verboseDebugging)
+ {
+ m_verboseDebugging = verboseDebugging;
+ }
+#endif
+
+protected:
+ enum Color {
+ Red = 1,
+ Black
+ };
+
+ // The base Node class which is stored in the tree. Nodes are only
+ // an internal concept; users of the tree deal only with the data
+ // they store in it.
+ class Node : public Noncopyable {
+ public:
+ // Constructor. Newly-created nodes are colored red.
+ explicit Node(const T& data)
+ : m_left(0)
+ , m_right(0)
+ , m_parent(0)
+ , m_color(Red)
+ , m_data(data)
+ {
+ }
+
+ virtual ~Node() { }
+
+ Color color() const { return m_color; }
+ void setColor(Color color) { m_color = color; }
+
+ // Fetches the user data.
+ T& data() { return m_data; }
+
+ // Copies all user-level fields from the source node, but not
+ // internal fields. For example, the base implementation of this
+ // method copies the "m_data" field, but not the child or parent
+ // fields. Any augmentation information also does not need to be
+ // copied, as it will be recomputed. Subclasses must call the
+ // superclass implementation.
+ virtual void copyFrom(Node* src) { m_data = src->data(); }
+
+ Node* left() const { return m_left; }
+ void setLeft(Node* node) { m_left = node; }
+
+ Node* right() const { return m_right; }
+ void setRight(Node* node) { m_right = node; }
+
+ Node* parent() const { return m_parent; }
+ void setParent(Node* node) { m_parent = node; }
+
+ private:
+ Node* m_left;
+ Node* m_right;
+ Node* m_parent;
+ Color m_color;
+ T m_data;
+ };
+
+ // Returns the root of the tree, which is needed by some subclasses.
+ Node* root() const { return m_root; }
+
+private:
+ // This virtual method is the hook that subclasses should use when
+ // augmenting the red-black tree with additional per-node summary
+ // information. For example, in the case of an interval tree, this
+ // is used to compute the maximum endpoint of the subtree below the
+ // given node based on the values in the left and right children. It
+ // is guaranteed that this will be called in the correct order to
+ // properly update such summary information based only on the values
+ // in the left and right children. This method should return true if
+ // the node's summary information changed.
+ virtual bool updateNode(Node* node) { return false; }
+
+ //----------------------------------------------------------------------
+ // Generic binary search tree operations
+ //
+
+ // Searches the tree for the given datum.
+ Node* treeSearch(const T& data) const
+ {
+ if (m_needsFullOrderingComparisons)
+ return treeSearchFullComparisons(m_root, data);
+
+ return treeSearchNormal(m_root, data);
+ }
+
+ // Searches the tree using the normal comparison operations,
+ // suitable for simple data types such as numbers.
+ Node* treeSearchNormal(Node* current, const T& data) const
+ {
+ while (current) {
+ if (current->data() == data)
+ return current;
+ if (data < current->data())
+ current = current->left();
+ else
+ current = current->right();
+ }
+ return 0;
+ }
+
+ // Searches the tree using multiple comparison operations, required
+ // for data types with more complex behavior such as intervals.
+ Node* treeSearchFullComparisons(Node* current, const T& data) const
+ {
+ if (!current)
+ return 0;
+ if (data < current->data())
+ return treeSearchFullComparisons(current->left(), data);
+ if (current->data() < data)
+ return treeSearchFullComparisons(current->right(), data);
+ if (data == current->data())
+ return current;
+
+ // We may need to traverse both the left and right subtrees.
+ Node* result = treeSearchFullComparisons(current->left(), data);
+ if (!result)
+ result = treeSearchFullComparisons(current->right(), data);
+ return result;
+ }
+
+ void treeInsert(Node* z)
+ {
+ Node* y = 0;
+ Node* x = m_root;
+ while (x) {
+ y = x;
+ if (z->data() < x->data())
+ x = x->left();
+ else
+ x = x->right();
+ }
+ z->setParent(y);
+ if (!y)
+ m_root = z;
+ else {
+ if (z->data() < y->data())
+ y->setLeft(z);
+ else
+ y->setRight(z);
+ }
+ }
+
+ // Finds the node following the given one in sequential ordering of
+ // their data, or null if none exists.
+ Node* treeSuccessor(Node* x)
+ {
+ if (x->right())
+ return treeMinimum(x->right());
+ Node* y = x->parent();
+ while (y && x == y->right()) {
+ x = y;
+ y = y->parent();
+ }
+ return y;
+ }
+
+ // Finds the minimum element in the sub-tree rooted at the given
+ // node.
+ Node* treeMinimum(Node* x)
+ {
+ while (x->left())
+ x = x->left();
+ return x;
+ }
+
+ // Helper for maintaining the augmented red-black tree.
+ void propagateUpdates(Node* start)
+ {
+ bool shouldContinue = true;
+ while (start && shouldContinue) {
+ shouldContinue = updateNode(start);
+ start = start->parent();
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Red-Black tree operations
+ //
+
+ // Left-rotates the subtree rooted at x.
+ // Returns the new root of the subtree (x's right child).
+ Node* leftRotate(Node* x)
+ {
+ // Set y.
+ Node* y = x->right();
+
+ // Turn y's left subtree into x's right subtree.
+ x->setRight(y->left());
+ if (y->left())
+ y->left()->setParent(x);
+
+ // Link x's parent to y.
+ y->setParent(x->parent());
+ if (!x->parent())
+ m_root = y;
+ else {
+ if (x == x->parent()->left())
+ x->parent()->setLeft(y);
+ else
+ x->parent()->setRight(y);
+ }
+
+ // Put x on y's left.
+ y->setLeft(x);
+ x->setParent(y);
+
+ // Update nodes lowest to highest.
+ updateNode(x);
+ updateNode(y);
+ return y;
+ }
+
+ // Right-rotates the subtree rooted at y.
+ // Returns the new root of the subtree (y's left child).
+ Node* rightRotate(Node* y)
+ {
+ // Set x.
+ Node* x = y->left();
+
+ // Turn x's right subtree into y's left subtree.
+ y->setLeft(x->right());
+ if (x->right())
+ x->right()->setParent(y);
+
+ // Link y's parent to x.
+ x->setParent(y->parent());
+ if (!y->parent())
+ m_root = x;
+ else {
+ if (y == y->parent()->left())
+ y->parent()->setLeft(x);
+ else
+ y->parent()->setRight(x);
+ }
+
+ // Put y on x's right.
+ x->setRight(y);
+ y->setParent(x);
+
+ // Update nodes lowest to highest.
+ updateNode(y);
+ updateNode(x);
+ return x;
+ }
+
+ // Inserts the given node into the tree.
+ void insertNode(Node* x)
+ {
+ treeInsert(x);
+ x->setColor(Red);
+ updateNode(x);
+
+ logIfVerbose(" PODRedBlackTree::InsertNode");
+
+ // The node from which to start propagating updates upwards.
+ Node* updateStart = x->parent();
+
+ while (x != m_root && x->parent()->color() == Red) {
+ if (x->parent() == x->parent()->parent()->left()) {
+ Node* y = x->parent()->parent()->right();
+ if (y && y->color() == Red) {
+ // Case 1
+ logIfVerbose(" Case 1/1");
+ x->parent()->setColor(Black);
+ y->setColor(Black);
+ x->parent()->parent()->setColor(Red);
+ updateNode(x->parent());
+ x = x->parent()->parent();
+ updateNode(x);
+ updateStart = x->parent();
+ } else {
+ if (x == x->parent()->right()) {
+ logIfVerbose(" Case 1/2");
+ // Case 2
+ x = x->parent();
+ leftRotate(x);
+ }
+ // Case 3
+ logIfVerbose(" Case 1/3");
+ x->parent()->setColor(Black);
+ x->parent()->parent()->setColor(Red);
+ Node* newSubTreeRoot = rightRotate(x->parent()->parent());
+ updateStart = newSubTreeRoot->parent();
+ }
+ } else {
+ // Same as "then" clause with "right" and "left" exchanged.
+ Node* y = x->parent()->parent()->left();
+ if (y && y->color() == Red) {
+ // Case 1
+ logIfVerbose(" Case 2/1");
+ x->parent()->setColor(Black);
+ y->setColor(Black);
+ x->parent()->parent()->setColor(Red);
+ updateNode(x->parent());
+ x = x->parent()->parent();
+ updateNode(x);
+ updateStart = x->parent();
+ } else {
+ if (x == x->parent()->left()) {
+ // Case 2
+ logIfVerbose(" Case 2/2");
+ x = x->parent();
+ rightRotate(x);
+ }
+ // Case 3
+ logIfVerbose(" Case 2/3");
+ x->parent()->setColor(Black);
+ x->parent()->parent()->setColor(Red);
+ Node* newSubTreeRoot = leftRotate(x->parent()->parent());
+ updateStart = newSubTreeRoot->parent();
+ }
+ }
+ }
+
+ propagateUpdates(updateStart);
+
+ m_root->setColor(Black);
+ }
+
+ // Restores the red-black property to the tree after splicing out
+ // a node. Note that x may be null, which is why xParent must be
+ // supplied.
+ void deleteFixup(Node* x, Node* xParent)
+ {
+ while (x != m_root && (!x || x->color() == Black)) {
+ if (x == xParent->left()) {
+ // Note: the text points out that w can not be null.
+ // The reason is not obvious from simply looking at
+ // the code; it comes about from the properties of the
+ // red-black tree.
+ Node* w = xParent->right();
+ ASSERT(w); // x's sibling should not be null.
+ if (w->color() == Red) {
+ // Case 1
+ w->setColor(Black);
+ xParent->setColor(Red);
+ leftRotate(xParent);
+ w = xParent->right();
+ }
+ if ((!w->left() || w->left()->color() == Black)
+ && (!w->right() || w->right()->color() == Black)) {
+ // Case 2
+ w->setColor(Red);
+ x = xParent;
+ xParent = x->parent();
+ } else {
+ if (!w->right() || w->right()->color() == Black) {
+ // Case 3
+ w->left()->setColor(Black);
+ w->setColor(Red);
+ rightRotate(w);
+ w = xParent->right();
+ }
+ // Case 4
+ w->setColor(xParent->color());
+ xParent->setColor(Black);
+ if (w->right())
+ w->right()->setColor(Black);
+ leftRotate(xParent);
+ x = m_root;
+ xParent = x->parent();
+ }
+ } else {
+ // Same as "then" clause with "right" and "left"
+ // exchanged.
+
+ // Note: the text points out that w can not be null.
+ // The reason is not obvious from simply looking at
+ // the code; it comes about from the properties of the
+ // red-black tree.
+ Node* w = xParent->left();
+ ASSERT(w); // x's sibling should not be null.
+ if (w->color() == Red) {
+ // Case 1
+ w->setColor(Black);
+ xParent->setColor(Red);
+ rightRotate(xParent);
+ w = xParent->left();
+ }
+ if ((!w->right() || w->right()->color() == Black)
+ && (!w->left() || w->left()->color() == Black)) {
+ // Case 2
+ w->setColor(Red);
+ x = xParent;
+ xParent = x->parent();
+ } else {
+ if (!w->left() || w->left()->color() == Black) {
+ // Case 3
+ w->right()->setColor(Black);
+ w->setColor(Red);
+ leftRotate(w);
+ w = xParent->left();
+ }
+ // Case 4
+ w->setColor(xParent->color());
+ xParent->setColor(Black);
+ if (w->left())
+ w->left()->setColor(Black);
+ rightRotate(xParent);
+ x = m_root;
+ xParent = x->parent();
+ }
+ }
+ }
+ if (x)
+ x->setColor(Black);
+ }
+
+ // Deletes the given node from the tree. Note that this
+ // particular node may not actually be removed from the tree;
+ // instead, another node might be removed and its contents
+ // copied into z.
+ void deleteNode(Node* z)
+ {
+ // Y is the node to be unlinked from the tree.
+ Node* y;
+ if (!z->left() || !z->right())
+ y = z;
+ else
+ y = treeSuccessor(z);
+
+ // Y is guaranteed to be non-null at this point.
+ Node* x;
+ if (y->left())
+ x = y->left();
+ else
+ x = y->right();
+
+ // X is the child of y which might potentially replace y in
+ // the tree. X might be null at this point.
+ Node* xParent;
+ if (x) {
+ x->setParent(y->parent());
+ xParent = x->parent();
+ } else
+ xParent = y->parent();
+ if (!y->parent())
+ m_root = x;
+ else {
+ if (y == y->parent()->left())
+ y->parent()->setLeft(x);
+ else
+ y->parent()->setRight(x);
+ }
+ if (y != z) {
+ z->copyFrom(y);
+ // This node has changed location in the tree and must be updated.
+ updateNode(z);
+ // The parent and its parents may now be out of date.
+ propagateUpdates(z->parent());
+ }
+
+ // If we haven't already updated starting from xParent, do so now.
+ if (xParent && xParent != y && xParent != z)
+ propagateUpdates(xParent);
+ if (y->color() == Black)
+ deleteFixup(x, xParent);
+ }
+
+ // Visits the subtree rooted at the given node in order.
+ void visitInorderImpl(Node* node, Visitor* visitor) const
+ {
+ if (node->left())
+ visitInorderImpl(node->left(), visitor);
+ visitor->visit(node->data());
+ if (node->right())
+ visitInorderImpl(node->right(), visitor);
+ }
+
+ //----------------------------------------------------------------------
+ // Helper class for size()
+
+ // A Visitor which simply counts the number of visited elements.
+ class Counter : public Visitor, public Noncopyable {
+ public:
+ Counter()
+ : m_count(0) { }
+
+ virtual void visit(const T& data) { ++m_count; }
+ int count() const { return m_count; }
+
+ private:
+ int m_count;
+ };
+
+ //----------------------------------------------------------------------
+ // Verification and debugging routines
+ //
+
+ // Returns in the "blackCount" parameter the number of black
+ // children along all paths to all leaves of the given node.
+ bool checkInvariantsFromNode(Node* node, int* blackCount) const
+ {
+ // Base case is a leaf node.
+ if (!node) {
+ *blackCount = 1;
+ return true;
+ }
+
+ // Each node is either red or black.
+ if (!(node->color() == Red || node->color() == Black))
+ return false;
+
+ // Every leaf (or null) is black.
+
+ if (node->color() == Red) {
+ // Both of its children are black.
+ if (!((!node->left() || node->left()->color() == Black)))
+ return false;
+ if (!((!node->right() || node->right()->color() == Black)))
+ return false;
+ }
+
+ // Every simple path to a leaf node contains the same number of
+ // black nodes.
+ int leftCount = 0, rightCount = 0;
+ bool leftValid = checkInvariantsFromNode(node->left(), &leftCount);
+ bool rightValid = checkInvariantsFromNode(node->right(), &rightCount);
+ if (!leftValid || !rightValid)
+ return false;
+ *blackCount = leftCount + (node->color() == Black ? 1 : 0);
+ return leftCount == rightCount;
+ }
+
+#ifdef NDEBUG
+ void logIfVerbose(const char* output) const { }
+#else
+ void logIfVerbose(const char* output) const
+ {
+ if (m_verboseDebugging)
+ LOG_ERROR("%s", output);
+ }
+#endif
+
+#ifndef NDEBUG
+ // Dumps the subtree rooted at the given node.
+ void dumpFromNode(Node* node, int indentation) const
+ {
+ StringBuilder builder;
+ for (int i = 0; i < indentation; i++)
+ builder.append(" ");
+ builder.append("-");
+ if (node) {
+ builder.append(" ");
+ builder.append(ValueToString<T>::string(node->data()));
+ builder.append((node->color() == Black) ? " (black)" : " (red)");
+ }
+ LOG_ERROR("%s", builder.toString().ascii().data());
+ if (node) {
+ dumpFromNode(node->left(), indentation + 2);
+ dumpFromNode(node->right(), indentation + 2);
+ }
+ }
+#endif
+
+ //----------------------------------------------------------------------
+ // Data members
+
+ RefPtr<PODArena> m_arena;
+ Node* m_root;
+ bool m_needsFullOrderingComparisons;
+#ifndef NDEBUG
+ bool m_verboseDebugging;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // PODRedBlackTree_h
diff --git a/Source/WebCore/platform/graphics/gpu/Shader.cpp b/Source/WebCore/platform/graphics/gpu/Shader.cpp
new file mode 100644
index 0000000..6978322
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/Shader.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "Shader.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext3D.h"
+
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+// static
+void Shader::affineTo3x3(const AffineTransform& transform, float mat[9])
+{
+ mat[0] = transform.a();
+ mat[1] = transform.b();
+ mat[2] = 0.0f;
+ mat[3] = transform.c();
+ mat[4] = transform.d();
+ mat[5] = 0.0f;
+ mat[6] = transform.e();
+ mat[7] = transform.f();
+ mat[8] = 1.0f;
+}
+
+// static
+unsigned Shader::loadShader(GraphicsContext3D* context, unsigned type, const char* shaderSource)
+{
+ unsigned shader = context->createShader(type);
+ if (!shader)
+ return 0;
+
+ String shaderSourceStr(shaderSource);
+ context->shaderSource(shader, shaderSourceStr);
+ context->compileShader(shader);
+ int compileStatus = 0;
+ context->getShaderiv(shader, GraphicsContext3D::COMPILE_STATUS, &compileStatus);
+ if (!compileStatus) {
+ String infoLog = context->getShaderInfoLog(shader);
+ LOG_ERROR("%s", infoLog.utf8().data());
+ context->deleteShader(shader);
+ return 0;
+ }
+ return shader;
+}
+
+// static
+unsigned Shader::loadProgram(GraphicsContext3D* context, const char* vertexShaderSource, const char* fragmentShaderSource)
+{
+ unsigned vertexShader = loadShader(context, GraphicsContext3D::VERTEX_SHADER, vertexShaderSource);
+ if (!vertexShader)
+ return 0;
+ unsigned fragmentShader = loadShader(context, GraphicsContext3D::FRAGMENT_SHADER, fragmentShaderSource);
+ if (!fragmentShader)
+ return 0;
+ unsigned program = context->createProgram();
+ if (!program)
+ return 0;
+ context->attachShader(program, vertexShader);
+ context->attachShader(program, fragmentShader);
+ context->linkProgram(program);
+ int linkStatus = 0;
+ context->getProgramiv(program, GraphicsContext3D::LINK_STATUS, &linkStatus);
+ if (!linkStatus)
+ context->deleteProgram(program);
+ context->deleteShader(vertexShader);
+ context->deleteShader(fragmentShader);
+ return program;
+}
+
+Shader::Shader(GraphicsContext3D* context, unsigned program)
+ : m_context(context)
+ , m_program(program)
+{
+}
+
+Shader::~Shader()
+{
+ m_context->deleteProgram(m_program);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/Shader.h b/Source/WebCore/platform/graphics/gpu/Shader.h
new file mode 100644
index 0000000..e5bd8de
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/Shader.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 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 Shader_h
+#define Shader_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class AffineTransform;
+class GraphicsContext3D;
+class Color;
+
+class Shader : public Noncopyable {
+protected:
+ Shader(GraphicsContext3D*, unsigned program);
+ ~Shader();
+
+ static void affineTo3x3(const AffineTransform&, float mat[9]);
+ static unsigned loadShader(GraphicsContext3D*, unsigned type, const char* shaderSource);
+ static unsigned loadProgram(GraphicsContext3D*, const char* vertexShaderSource, const char* fragmentShaderSource);
+
+ GraphicsContext3D* m_context;
+ unsigned m_program;
+};
+
+}
+
+#endif // Shader_h
diff --git a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp
new file mode 100644
index 0000000..9d1298f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "SharedGraphicsContext3D.h"
+
+#include "AffineTransform.h"
+#include "Color.h"
+#include "Extensions3D.h"
+#include "FloatRect.h"
+#include "IntSize.h"
+#include "SolidFillShader.h"
+#include "TexShader.h"
+
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+// static
+PassRefPtr<SharedGraphicsContext3D> SharedGraphicsContext3D::create(HostWindow* hostWindow)
+{
+ GraphicsContext3D::Attributes attr;
+ attr.canRecoverFromContextLoss = false; // Canvas contexts can not handle lost contexts.
+ RefPtr<GraphicsContext3D> context = GraphicsContext3D::create(attr, hostWindow);
+ if (!context)
+ return 0;
+ OwnPtr<SolidFillShader> solidFillShader = SolidFillShader::create(context.get());
+ if (!solidFillShader)
+ return 0;
+ OwnPtr<TexShader> texShader = TexShader::create(context.get());
+ if (!texShader)
+ return 0;
+ return adoptRef(new SharedGraphicsContext3D(context.release(), solidFillShader.release(), texShader.release()));
+}
+
+SharedGraphicsContext3D::SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<SolidFillShader> solidFillShader, PassOwnPtr<TexShader> texShader)
+ : m_context(context)
+ , m_bgraSupported(false)
+ , m_quadVertices(0)
+ , m_solidFillShader(solidFillShader)
+ , m_texShader(texShader)
+{
+ allContexts()->add(this);
+ Extensions3D* extensions = m_context->getExtensions();
+ m_bgraSupported = extensions->supports("GL_EXT_texture_format_BGRA8888") && extensions->supports("GL_EXT_read_format_bgra");
+ if (m_bgraSupported) {
+ extensions->ensureEnabled("GL_EXT_texture_format_BGRA8888");
+ extensions->ensureEnabled("GL_EXT_read_format_bgra");
+ }
+}
+
+SharedGraphicsContext3D::~SharedGraphicsContext3D()
+{
+ m_context->deleteBuffer(m_quadVertices);
+ allContexts()->remove(this);
+}
+
+void SharedGraphicsContext3D::makeContextCurrent()
+{
+ m_context->makeContextCurrent();
+}
+
+void SharedGraphicsContext3D::scissor(const FloatRect& rect)
+{
+ m_context->scissor(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+void SharedGraphicsContext3D::enable(GC3Denum capacity)
+{
+ m_context->enable(capacity);
+}
+
+void SharedGraphicsContext3D::disable(GC3Denum capacity)
+{
+ m_context->disable(capacity);
+}
+
+void SharedGraphicsContext3D::clearColor(const Color& color)
+{
+ float rgba[4];
+ color.getRGBA(rgba[0], rgba[1], rgba[2], rgba[3]);
+ m_context->clearColor(rgba[0], rgba[1], rgba[2], rgba[3]);
+}
+
+void SharedGraphicsContext3D::clear(GC3Dbitfield mask)
+{
+ m_context->clear(mask);
+}
+
+void SharedGraphicsContext3D::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count)
+{
+ m_context->drawArrays(mode, first, count);
+}
+
+GC3Denum SharedGraphicsContext3D::getError()
+{
+ return m_context->getError();
+}
+
+void SharedGraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value)
+{
+ m_context->getIntegerv(pname, value);
+}
+
+void SharedGraphicsContext3D::flush()
+{
+ m_context->flush();
+}
+
+Platform3DObject SharedGraphicsContext3D::createFramebuffer()
+{
+ return m_context->createFramebuffer();
+}
+
+Platform3DObject SharedGraphicsContext3D::createTexture()
+{
+ return m_context->createTexture();
+}
+
+void SharedGraphicsContext3D::deleteFramebuffer(Platform3DObject framebuffer)
+{
+ m_context->deleteFramebuffer(framebuffer);
+}
+
+void SharedGraphicsContext3D::deleteTexture(Platform3DObject texture)
+{
+ m_context->deleteTexture(texture);
+}
+
+void SharedGraphicsContext3D::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject texture, GC3Dint level)
+{
+ m_context->framebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+void SharedGraphicsContext3D::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
+{
+ m_context->texParameteri(target, pname, param);
+}
+
+bool SharedGraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels)
+{
+ if (!pixels)
+ return m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border, format, type);
+ return m_context->texImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+}
+
+void SharedGraphicsContext3D::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels)
+{
+ m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+
+void SharedGraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data)
+{
+ m_context->readPixels(x, y, width, height, format, type, data);
+}
+
+bool SharedGraphicsContext3D::supportsBGRA()
+{
+ return m_bgraSupported;
+}
+
+Texture* SharedGraphicsContext3D::createTexture(NativeImagePtr ptr, Texture::Format format, int width, int height)
+{
+ RefPtr<Texture> texture = m_textures.get(ptr);
+ if (texture)
+ return texture.get();
+
+ texture = Texture::create(m_context.get(), format, width, height);
+ Texture* t = texture.get();
+ m_textures.set(ptr, texture);
+ return t;
+}
+
+Texture* SharedGraphicsContext3D::getTexture(NativeImagePtr ptr)
+{
+ RefPtr<Texture> texture = m_textures.get(ptr);
+ return texture ? texture.get() : 0;
+}
+
+void SharedGraphicsContext3D::removeTextureFor(NativeImagePtr ptr)
+{
+ TextureHashMap::iterator it = m_textures.find(ptr);
+ if (it != m_textures.end())
+ m_textures.remove(it);
+}
+
+// static
+void SharedGraphicsContext3D::removeTexturesFor(NativeImagePtr ptr)
+{
+ for (HashSet<SharedGraphicsContext3D*>::iterator it = allContexts()->begin(); it != allContexts()->end(); ++it)
+ (*it)->removeTextureFor(ptr);
+}
+
+// static
+HashSet<SharedGraphicsContext3D*>* SharedGraphicsContext3D::allContexts()
+{
+ DEFINE_STATIC_LOCAL(HashSet<SharedGraphicsContext3D*>, allContextsSet, ());
+ return &allContextsSet;
+}
+
+
+PassRefPtr<Texture> SharedGraphicsContext3D::createTexture(Texture::Format format, int width, int height)
+{
+ return Texture::create(m_context.get(), format, width, height);
+}
+
+void SharedGraphicsContext3D::applyCompositeOperator(CompositeOperator op)
+{
+ switch (op) {
+ case CompositeClear:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::ZERO);
+ break;
+ case CompositeCopy:
+ m_context->disable(GraphicsContext3D::BLEND);
+ break;
+ case CompositeSourceOver:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA);
+ break;
+ case CompositeSourceIn:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::DST_ALPHA, GraphicsContext3D::ZERO);
+ break;
+ case CompositeSourceOut:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ZERO);
+ break;
+ case CompositeSourceAtop:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::DST_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA);
+ break;
+ case CompositeDestinationOver:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ONE);
+ break;
+ case CompositeDestinationIn:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::SRC_ALPHA);
+ break;
+ case CompositeDestinationOut:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::ONE_MINUS_SRC_ALPHA);
+ break;
+ case CompositeDestinationAtop:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::SRC_ALPHA);
+ break;
+ case CompositeXOR:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA);
+ break;
+ case CompositePlusDarker:
+ case CompositeHighlight:
+ // unsupported
+ m_context->disable(GraphicsContext3D::BLEND);
+ break;
+ case CompositePlusLighter:
+ m_context->enable(GraphicsContext3D::BLEND);
+ m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE);
+ break;
+ }
+}
+
+void SharedGraphicsContext3D::useQuadVertices()
+{
+ if (!m_quadVertices) {
+ float vertices[] = { 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f };
+ m_quadVertices = m_context->createBuffer();
+ m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices);
+ m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, sizeof(vertices), vertices, GraphicsContext3D::STATIC_DRAW);
+ } else {
+ m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices);
+ }
+}
+
+void SharedGraphicsContext3D::setActiveTexture(GC3Denum textureUnit)
+{
+ m_context->activeTexture(textureUnit);
+}
+
+void SharedGraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture)
+{
+ m_context->bindTexture(target, texture);
+}
+
+void SharedGraphicsContext3D::useFillSolidProgram(const AffineTransform& transform, const Color& color)
+{
+ m_solidFillShader->use(transform, color);
+}
+
+void SharedGraphicsContext3D::useTextureProgram(const AffineTransform& transform, const AffineTransform& texTransform, float alpha)
+{
+ m_texShader->use(transform, texTransform, 0, alpha);
+}
+
+void SharedGraphicsContext3D::bindFramebuffer(Platform3DObject framebuffer)
+{
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, framebuffer);
+}
+
+void SharedGraphicsContext3D::setViewport(const IntSize& size)
+{
+ m_context->viewport(0, 0, size.width(), size.height());
+}
+
+bool SharedGraphicsContext3D::paintsIntoCanvasBuffer() const
+{
+ return m_context->paintsIntoCanvasBuffer();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h
new file mode 100644
index 0000000..ea1810d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 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 SharedGraphicsContext3D_h
+#define SharedGraphicsContext3D_h
+
+#include "GraphicsContext3D.h"
+#include "GraphicsTypes.h"
+#include "ImageSource.h"
+#include "Texture.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class AffineTransform;
+class Color;
+class FloatRect;
+class HostWindow;
+class IntSize;
+class SolidFillShader;
+class TexShader;
+
+typedef HashMap<NativeImagePtr, RefPtr<Texture> > TextureHashMap;
+
+class SharedGraphicsContext3D : public RefCounted<SharedGraphicsContext3D> {
+public:
+ static PassRefPtr<SharedGraphicsContext3D> create(HostWindow*);
+ ~SharedGraphicsContext3D();
+
+ // Functions that delegate directly to GraphicsContext3D, with caching
+ void makeContextCurrent();
+ void bindFramebuffer(Platform3DObject framebuffer);
+ void setViewport(const IntSize&);
+ void scissor(const FloatRect&);
+ void enable(GC3Denum capacity);
+ void disable(GC3Denum capacity);
+ void clearColor(const Color&);
+ void clear(GC3Dbitfield mask);
+ void drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count);
+ GC3Denum getError();
+ void getIntegerv(GC3Denum pname, GC3Dint* value);
+ void flush();
+
+ Platform3DObject createFramebuffer();
+ Platform3DObject createTexture();
+
+ void deleteFramebuffer(Platform3DObject framebuffer);
+ void deleteTexture(Platform3DObject texture);
+
+ void framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject, GC3Dint level);
+ void texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param);
+ bool texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels);
+ void texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels);
+
+ void readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data);
+
+ bool paintsIntoCanvasBuffer() const;
+
+ // Shared logic for canvas 2d
+ void applyCompositeOperator(CompositeOperator);
+ void useQuadVertices();
+
+ void useFillSolidProgram(const AffineTransform&, const Color&);
+ void useTextureProgram(const AffineTransform&, const AffineTransform&, float alpha);
+
+ void setActiveTexture(GC3Denum textureUnit);
+ void bindTexture(GC3Denum target, Platform3DObject texture);
+
+ bool supportsBGRA();
+
+ // Creates a texture associated with the given image. Is owned by this context's
+ // TextureHashMap.
+ Texture* createTexture(NativeImagePtr, Texture::Format, int width, int height);
+ Texture* getTexture(NativeImagePtr);
+
+ // Multiple SharedGraphicsContext3D can exist in a single process (one per compositing context) and the same
+ // NativeImagePtr may be uploaded as a texture into all of them. This function removes uploaded textures
+ // for a given NativeImagePtr in all contexts.
+ static void removeTexturesFor(NativeImagePtr);
+
+ // Creates a texture that is not associated with any image. The caller takes ownership of
+ // the texture.
+ PassRefPtr<Texture> createTexture(Texture::Format, int width, int height);
+
+ GraphicsContext3D* graphicsContext3D() const { return m_context.get(); }
+
+private:
+ SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D>, PassOwnPtr<SolidFillShader>, PassOwnPtr<TexShader>);
+
+ // Used to implement removeTexturesFor(), see the comment above.
+ static HashSet<SharedGraphicsContext3D*>* allContexts();
+ void removeTextureFor(NativeImagePtr);
+
+ RefPtr<GraphicsContext3D> m_context;
+ bool m_bgraSupported;
+
+ unsigned m_quadVertices;
+
+ OwnPtr<SolidFillShader> m_solidFillShader;
+ OwnPtr<TexShader> m_texShader;
+
+ TextureHashMap m_textures;
+};
+
+} // namespace WebCore
+
+#endif // SharedGraphicsContext3D_h
diff --git a/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp b/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp
new file mode 100644
index 0000000..86079be
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "SolidFillShader.h"
+
+#include "Color.h"
+#include "GraphicsContext3D.h"
+
+namespace WebCore {
+
+SolidFillShader::SolidFillShader(GraphicsContext3D* context, unsigned program)
+ : Shader(context, program)
+{
+ m_matrixLocation = context->getUniformLocation(program, "matrix");
+ m_colorLocation = context->getUniformLocation(program, "color");
+ m_positionLocation = context->getAttribLocation(program, "position");
+}
+
+PassOwnPtr<SolidFillShader> SolidFillShader::create(GraphicsContext3D* context)
+{
+ static const char* vertexShaderSource =
+ "uniform mat3 matrix;\n"
+ "uniform vec4 color;\n"
+ "attribute vec3 position;\n"
+ "void main() {\n"
+ " gl_Position = vec4(matrix * position, 1.0);\n"
+ "}\n";
+ static const char* fragmentShaderSource =
+ "#ifdef GL_ES\n"
+ "precision mediump float;\n"
+ "#endif\n"
+ "uniform mat3 matrix;\n"
+ "uniform vec4 color;\n"
+ "void main() {\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+ unsigned program = loadProgram(context, vertexShaderSource, fragmentShaderSource);
+ if (!program)
+ return 0;
+ return new SolidFillShader(context, program);
+}
+
+void SolidFillShader::use(const AffineTransform& transform, const Color& color)
+{
+ m_context->useProgram(m_program);
+
+ float rgba[4];
+ color.getRGBA(rgba[0], rgba[1], rgba[2], rgba[3]);
+ m_context->uniform4f(m_colorLocation, rgba[0] * rgba[3], rgba[1] * rgba[3], rgba[2] * rgba[3], rgba[3]);
+
+ float matrix[9];
+ affineTo3x3(transform, matrix);
+ m_context->uniformMatrix3fv(m_matrixLocation, false /*transpose*/, matrix, 1 /*count*/);
+
+ m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0);
+
+ m_context->enableVertexAttribArray(m_positionLocation);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/SolidFillShader.h b/Source/WebCore/platform/graphics/gpu/SolidFillShader.h
new file mode 100644
index 0000000..1071e73
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/SolidFillShader.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 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 SolidFillShader_h
+#define SolidFillShader_h
+
+#include "Shader.h"
+
+namespace WebCore {
+
+class SolidFillShader : public Shader {
+public:
+ static PassOwnPtr<SolidFillShader> create(GraphicsContext3D* context);
+ void use(const AffineTransform& transform, const Color& color);
+
+private:
+ SolidFillShader(GraphicsContext3D* context, unsigned program);
+
+ int m_matrixLocation;
+ int m_colorLocation;
+ int m_positionLocation;
+};
+
+}
+
+#endif // SolidFillShader_h
diff --git a/Source/WebCore/platform/graphics/gpu/TexShader.cpp b/Source/WebCore/platform/graphics/gpu/TexShader.cpp
new file mode 100644
index 0000000..d7ffa17
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/TexShader.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "TexShader.h"
+
+#include "GraphicsContext3D.h"
+
+namespace WebCore {
+
+TexShader::TexShader(GraphicsContext3D* context, unsigned program)
+ : Shader(context, program)
+{
+ m_matrixLocation = context->getUniformLocation(program, "matrix");
+ m_texMatrixLocation = context->getUniformLocation(program, "texMatrix");
+ m_alphaLocation = context->getUniformLocation(program, "alpha");
+ m_positionLocation = context->getAttribLocation(program, "position");
+ m_samplerLocation = context->getUniformLocation(program, "sampler");
+}
+
+PassOwnPtr<TexShader> TexShader::create(GraphicsContext3D* context)
+{
+ static const char* vertexShaderSource =
+ "uniform mat3 matrix;\n"
+ "uniform mat3 texMatrix;\n"
+ "attribute vec3 position;\n"
+ "varying vec3 texCoord;\n"
+ "void main() {\n"
+ " texCoord = texMatrix * position;\n"
+ " gl_Position = vec4(matrix * position, 1.0);\n"
+ "}\n";
+ static const char* fragmentShaderSource =
+ "#ifdef GL_ES\n"
+ "precision mediump float;\n"
+ "#endif\n"
+ "uniform sampler2D sampler;\n"
+ "uniform float alpha;\n"
+ "varying vec3 texCoord;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(sampler, texCoord.xy)* vec4(alpha);\n"
+ "}\n";
+ unsigned program = loadProgram(context, vertexShaderSource, fragmentShaderSource);
+ if (!program)
+ return 0;
+ return new TexShader(context, program);
+}
+
+void TexShader::use(const AffineTransform& transform, const AffineTransform& texTransform, int sampler, float alpha)
+{
+ m_context->useProgram(m_program);
+ float matrix[9];
+ affineTo3x3(transform, matrix);
+ m_context->uniformMatrix3fv(m_matrixLocation, false /*transpose*/, matrix, 1 /*count*/);
+
+ float texMatrix[9];
+ affineTo3x3(texTransform, texMatrix);
+ m_context->uniformMatrix3fv(m_texMatrixLocation, false /*transpose*/, texMatrix, 1 /*count*/);
+
+ m_context->uniform1i(m_samplerLocation, sampler);
+ m_context->uniform1f(m_alphaLocation, alpha);
+
+ m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0);
+
+ m_context->enableVertexAttribArray(m_positionLocation);
+
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/TexShader.h b/Source/WebCore/platform/graphics/gpu/TexShader.h
new file mode 100644
index 0000000..535997d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/TexShader.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 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 TexShader_h
+#define TexShader_h
+
+#include "Shader.h"
+
+namespace WebCore {
+
+class TexShader : public Shader {
+public:
+ static PassOwnPtr<TexShader> create(GraphicsContext3D* context);
+ void use(const AffineTransform& transform, const AffineTransform& texTransform, int sampler, float alpha);
+
+private:
+ TexShader(GraphicsContext3D* context, unsigned program);
+
+ int m_matrixLocation;
+ int m_texMatrixLocation;
+ int m_samplerLocation;
+ int m_alphaLocation;
+ int m_positionLocation;
+};
+
+}
+
+#endif // TexShader_h
diff --git a/Source/WebCore/platform/graphics/gpu/Texture.cpp b/Source/WebCore/platform/graphics/gpu/Texture.cpp
new file mode 100644
index 0000000..e1f8114
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/Texture.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "Texture.h"
+
+#include "Extensions3D.h"
+#include "FloatRect.h"
+#include "GraphicsContext3D.h"
+#include "IntRect.h"
+
+#include <algorithm>
+#include <wtf/OwnArrayPtr.h>
+
+using namespace std;
+
+namespace WebCore {
+
+
+Texture::Texture(GraphicsContext3D* context, PassOwnPtr<Vector<unsigned int> > tileTextureIds, Format format, int width, int height, int maxTextureSize)
+ : m_context(context)
+ , m_format(format)
+ , m_tiles(maxTextureSize, width, height, true)
+ , m_tileTextureIds(tileTextureIds)
+{
+}
+
+Texture::~Texture()
+{
+ for (unsigned int i = 0; i < m_tileTextureIds->size(); i++)
+ m_context->deleteTexture(m_tileTextureIds->at(i));
+}
+
+static void convertFormat(GraphicsContext3D* context, Texture::Format format, unsigned int* glFormat, unsigned int* glType, bool* swizzle)
+{
+ *swizzle = false;
+ switch (format) {
+ case Texture::RGBA8:
+ *glFormat = GraphicsContext3D::RGBA;
+ *glType = GraphicsContext3D::UNSIGNED_BYTE;
+ break;
+ case Texture::BGRA8:
+ if (context->getExtensions()->supports("GL_EXT_texture_format_BGRA8888")) {
+ *glFormat = Extensions3D::BGRA_EXT;
+ *glType = GraphicsContext3D::UNSIGNED_BYTE;
+ } else {
+ *glFormat = GraphicsContext3D::RGBA;
+ *glType = GraphicsContext3D::UNSIGNED_BYTE;
+ *swizzle = true;
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+PassRefPtr<Texture> Texture::create(GraphicsContext3D* context, Format format, int width, int height)
+{
+ int maxTextureSize = 0;
+ context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize);
+ TilingData tiling(maxTextureSize, width, height, true);
+ int numTiles = tiling.numTiles();
+
+ OwnPtr<Vector<unsigned int> > textureIds(new Vector<unsigned int>(numTiles));
+ textureIds->fill(0, numTiles);
+
+ for (int i = 0; i < numTiles; i++) {
+ int textureId = context->createTexture();
+ if (!textureId) {
+ for (int i = 0; i < numTiles; i++)
+ context->deleteTexture(textureIds->at(i));
+ return 0;
+ }
+ textureIds->at(i) = textureId;
+
+ IntRect tileBoundsWithBorder = tiling.tileBoundsWithBorder(i);
+
+ unsigned int glFormat = 0;
+ unsigned int glType = 0;
+ bool swizzle;
+ convertFormat(context, format, &glFormat, &glType, &swizzle);
+ context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId);
+ context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, glFormat,
+ tileBoundsWithBorder.width(),
+ tileBoundsWithBorder.height(),
+ 0, glFormat, glType);
+ }
+ return adoptRef(new Texture(context, textureIds.leakPtr(), format, width, height, maxTextureSize));
+}
+
+template <bool swizzle>
+static uint32_t* copySubRect(uint32_t* src, int srcX, int srcY, uint32_t* dst, int width, int height, int srcStride)
+{
+ uint32_t* srcOffset = src + srcX + srcY * srcStride;
+
+ if (!swizzle && width == srcStride)
+ return srcOffset;
+
+ if (swizzle) {
+ uint32_t* dstPixel = dst;
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width ; ++x) {
+ uint32_t pixel = srcOffset[x + y * srcStride];
+ *dstPixel = (pixel & 0xFF00FF00) | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16);
+ dstPixel++;
+ }
+ }
+ } else {
+ for (int y = 0; y < height; ++y) {
+ memcpy(dst + y * width, srcOffset + y * srcStride, 4 * width);
+ }
+ }
+ return dst;
+}
+
+void Texture::load(void* pixels)
+{
+ updateSubRect(pixels, IntRect(0, 0, m_tiles.totalSizeX(), m_tiles.totalSizeY()));
+}
+
+void Texture::updateSubRect(void* pixels, const IntRect& updateRect)
+{
+ IntRect updateRectSanitized(updateRect);
+ updateRectSanitized.intersect(IntRect(0, 0, m_tiles.totalSizeX(), m_tiles.totalSizeY()));
+
+ uint32_t* pixels32 = static_cast<uint32_t*>(pixels);
+ unsigned int glFormat = 0;
+ unsigned int glType = 0;
+ bool swizzle;
+ convertFormat(m_context, m_format, &glFormat, &glType, &swizzle);
+ if (swizzle) {
+ ASSERT(glFormat == GraphicsContext3D::RGBA && glType == GraphicsContext3D::UNSIGNED_BYTE);
+ // FIXME: This could use PBO's to save doing an extra copy here.
+ }
+ int tempBuffSize = // Temporary buffer size is the smaller of the max texture size or the updateRectSanitized
+ min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRectSanitized.width()) *
+ min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRectSanitized.height());
+ OwnArrayPtr<uint32_t> tempBuff(new uint32_t[tempBuffSize]);
+
+ for (int tile = 0; tile < m_tiles.numTiles(); tile++) {
+ // Intersect with tile
+ IntRect tileBoundsWithBorder = m_tiles.tileBoundsWithBorder(tile);
+
+ IntRect updateRectIntersected = updateRectSanitized;
+ updateRectIntersected.intersect(tileBoundsWithBorder);
+
+ IntRect dstRect = updateRectIntersected;
+ dstRect.move(-tileBoundsWithBorder.x(), -tileBoundsWithBorder.y());
+
+ if (updateRectIntersected.isEmpty())
+ continue;
+
+ // Copy sub rectangle out of larger pixel data
+ uint32_t* uploadBuff = 0;
+ if (swizzle) {
+ uploadBuff = copySubRect<true>(
+ pixels32, updateRectIntersected.x(), updateRectIntersected.y(),
+ tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSizeX());
+ } else {
+ uploadBuff = copySubRect<false>(
+ pixels32, updateRectIntersected.x(), updateRectIntersected.y(),
+ tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSizeX());
+ }
+
+ m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_tileTextureIds->at(tile));
+ m_context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0 /* level */,
+ dstRect.x(),
+ dstRect.y(),
+ updateRectIntersected.width(),
+ updateRectIntersected.height(), glFormat, glType, uploadBuff);
+ }
+}
+
+void Texture::bindTile(int tile)
+{
+ m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_tileTextureIds->at(tile));
+ m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
+ m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
+ m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
+ m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/Texture.h b/Source/WebCore/platform/graphics/gpu/Texture.h
new file mode 100644
index 0000000..1f35006
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/Texture.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 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 Texture_h
+#define Texture_h
+
+#include "TilingData.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+class GraphicsContext3D;
+
+class IntRect;
+
+class Texture : public RefCounted<Texture> {
+public:
+ ~Texture();
+ enum Format { RGBA8, BGRA8 };
+ static PassRefPtr<Texture> create(GraphicsContext3D*, Format, int width, int height);
+ void bindTile(int tile);
+ void load(void* pixels);
+ void updateSubRect(void* pixels, const IntRect&);
+ Format format() const { return m_format; }
+ const TilingData& tiles() const { return m_tiles; }
+private:
+ Texture(GraphicsContext3D*, PassOwnPtr<Vector<unsigned int> > tileTextureIds, Format format, int width, int height, int maxTextureSize);
+ GraphicsContext3D* m_context;
+ Format m_format;
+ TilingData m_tiles;
+ OwnPtr<Vector<unsigned int> > m_tileTextureIds;
+};
+
+}
+
+#endif // Texture_h
diff --git a/Source/WebCore/platform/graphics/gpu/TilingData.cpp b/Source/WebCore/platform/graphics/gpu/TilingData.cpp
new file mode 100644
index 0000000..a98add7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/TilingData.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+#include "TilingData.h"
+
+#include "FloatRect.h"
+#include "IntRect.h"
+#include <algorithm>
+
+using namespace std;
+
+namespace WebCore {
+
+static int computeNumTiles(int maxTextureSize, int totalSize, int borderTexels)
+{
+ return max(1, 1 + (totalSize - 1 - 2 * borderTexels) / (maxTextureSize - 2 * borderTexels));
+}
+
+TilingData::TilingData(int maxTextureSize, int totalSizeX, int totalSizeY, bool hasBorderTexels)
+ : m_maxTextureSize(maxTextureSize)
+ , m_totalSizeX(totalSizeX)
+ , m_totalSizeY(totalSizeY)
+ , m_borderTexels(hasBorderTexels ? 1 : 0)
+{
+ m_numTilesX = computeNumTiles(maxTextureSize, m_totalSizeX, m_borderTexels);
+ m_numTilesY = computeNumTiles(maxTextureSize, m_totalSizeY, m_borderTexels);
+}
+
+int TilingData::tileXIndexFromSrcCoord(int srcPos) const
+{
+ int x = (srcPos - m_borderTexels) / (m_maxTextureSize - 2 * m_borderTexels);
+ return min(max(x, 0), numTilesX() - 1);
+}
+
+int TilingData::tileYIndexFromSrcCoord(int srcPos) const
+{
+ int y = (srcPos - m_borderTexels) / (m_maxTextureSize - 2 * m_borderTexels);
+ return min(max(y, 0), numTilesY() - 1);
+}
+
+IntRect TilingData::tileBounds(int tile) const
+{
+ assertTile(tile);
+ int ix = tileXIndex(tile);
+ int iy = tileYIndex(tile);
+ int x = tilePositionX(ix);
+ int y = tilePositionY(iy);
+ int width = tileSizeX(ix);
+ int height = tileSizeY(iy);
+ ASSERT(x >= 0 && y >= 0 && width >= 0 && height >= 0);
+ ASSERT(x <= totalSizeX() && y <= totalSizeY());
+ return IntRect(x, y, width, height);
+}
+
+IntRect TilingData::tileBoundsWithBorder(int tile) const
+{
+ IntRect bounds = tileBounds(tile);
+
+ if (m_borderTexels) {
+ int x1 = bounds.x();
+ int x2 = bounds.right();
+ int y1 = bounds.y();
+ int y2 = bounds.bottom();
+
+ if (tileXIndex(tile) > 0)
+ x1--;
+ if (tileXIndex(tile) < (numTilesX() - 1))
+ x2++;
+ if (tileYIndex(tile) > 0)
+ y1--;
+ if (tileYIndex(tile) < (numTilesY() - 1))
+ y2++;
+
+ bounds = IntRect(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ return bounds;
+}
+
+FloatRect TilingData::tileBoundsNormalized(int tile) const
+{
+ assertTile(tile);
+ FloatRect bounds(tileBounds(tile));
+ bounds.scale(1.0f / m_totalSizeX, 1.0f / m_totalSizeY);
+ return bounds;
+}
+
+int TilingData::tilePositionX(int xIndex) const
+{
+ ASSERT(xIndex >= 0 && xIndex < numTilesX());
+
+ int pos = 0;
+ for (int i = 0; i < xIndex; i++)
+ pos += tileSizeX(i);
+
+ return pos;
+}
+
+int TilingData::tilePositionY(int yIndex) const
+{
+ ASSERT(yIndex >= 0 && yIndex < numTilesY());
+
+ int pos = 0;
+ for (int i = 0; i < yIndex; i++)
+ pos += tileSizeY(i);
+
+ return pos;
+}
+
+int TilingData::tileSizeX(int xIndex) const
+{
+ ASSERT(xIndex >= 0 && xIndex < numTilesX());
+
+ int size = maxTextureSize();
+ size = min(size, totalSizeX());
+
+ if (!xIndex && m_numTilesX == 1)
+ return m_totalSizeX;
+ if (!xIndex && m_numTilesX > 1)
+ return m_maxTextureSize - m_borderTexels;
+ if (xIndex < numTilesX() - 1)
+ return m_maxTextureSize - 2 * m_borderTexels;
+ if (xIndex == numTilesX() - 1)
+ return m_totalSizeX - tilePositionX(xIndex);
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+int TilingData::tileSizeY(int yIndex) const
+{
+ ASSERT(yIndex >= 0 && yIndex < numTilesY());
+
+ int size = maxTextureSize();
+ size = min(size, totalSizeY());
+
+ if (!yIndex && m_numTilesY == 1)
+ return m_totalSizeY;
+ if (!yIndex && m_numTilesY > 1)
+ return m_maxTextureSize - m_borderTexels;
+ if (yIndex < numTilesY() - 1)
+ return m_maxTextureSize - 2 * m_borderTexels;
+ if (yIndex == numTilesY() - 1)
+ return m_totalSizeY - tilePositionY(yIndex);
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+IntRect TilingData::overlappedTileIndices(const WebCore::IntRect &srcRect) const
+{
+ int x = tileXIndexFromSrcCoord(srcRect.x());
+ int y = tileYIndexFromSrcCoord(srcRect.y());
+ int r = tileXIndexFromSrcCoord(srcRect.right());
+ int b = tileYIndexFromSrcCoord(srcRect.bottom());
+ return IntRect(x, y, r - x, b - y);
+}
+
+IntRect TilingData::overlappedTileIndices(const WebCore::FloatRect &srcRect) const
+{
+ return overlappedTileIndices(enclosingIntRect(srcRect));
+}
+
+void TilingData::intersectDrawQuad(const FloatRect& srcRect, const FloatRect& dstRect, int tile,
+ FloatRect* newSrc, FloatRect* newDst) const
+{
+ // Intersect with tile
+ FloatRect tileBounds = this->tileBounds(tile);
+ FloatRect srcRectIntersected = srcRect;
+ srcRectIntersected.intersect(tileBounds);
+
+ if (srcRectIntersected.isEmpty()) {
+ *newSrc = *newDst = FloatRect(0, 0, 0, 0);
+ return;
+ }
+
+ float srcRectIntersectedNormX = (srcRectIntersected.x() - srcRect.x()) / srcRect.width();
+ float srcRectIntersectedNormY = (srcRectIntersected.y() - srcRect.y()) / srcRect.height();
+ float srcRectIntersectedNormW = srcRectIntersected.width() / srcRect.width();
+ float srcRectIntersectedNormH = srcRectIntersected.height() / srcRect.height();
+
+ *newSrc = srcRectIntersected;
+ newSrc->move(
+ -tileBounds.x() + ((tileXIndex(tile) > 0) ? m_borderTexels : 0),
+ -tileBounds.y() + ((tileYIndex(tile) > 0) ? m_borderTexels : 0));
+
+ *newDst = FloatRect(
+ srcRectIntersectedNormX * dstRect.width() + dstRect.x(),
+ srcRectIntersectedNormY * dstRect.height() + dstRect.y(),
+ srcRectIntersectedNormW * dstRect.width(),
+ srcRectIntersectedNormH * dstRect.height());
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gpu/TilingData.h b/Source/WebCore/platform/graphics/gpu/TilingData.h
new file mode 100644
index 0000000..1bdc51a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/TilingData.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 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 TilingData_h
+#define TilingData_h
+
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class FloatRect;
+class IntRect;
+
+class TilingData : public Noncopyable {
+public:
+ TilingData(int maxTextureSize, int totalSizeX, int totalSizeY, bool hasBorderTexels);
+ int maxTextureSize() const { return m_maxTextureSize; }
+ int totalSizeX() const { return m_totalSizeX; }
+ int totalSizeY() const { return m_totalSizeY; }
+ int borderTexels() const { return m_borderTexels; }
+
+ int numTiles() const { return numTilesX() * numTilesY(); }
+ int numTilesX() const { return m_numTilesX; }
+ int numTilesY() const { return m_numTilesY; }
+ int tileIndex(int x, int y) const { return x + y * numTilesX(); }
+ int tileXIndex(int tile) const { assertTile(tile); return tile % numTilesX(); }
+ int tileYIndex(int tile) const { assertTile(tile); return tile / numTilesX(); }
+ int tileXIndexFromSrcCoord(int) const;
+ int tileYIndexFromSrcCoord(int) const;
+
+ IntRect tileBounds(int tile) const;
+ IntRect tileBoundsWithBorder(int tile) const;
+ FloatRect tileBoundsNormalized(int tile) const;
+ int tilePositionX(int xIndex) const;
+ int tilePositionY(int yIndex) const;
+ int tileSizeX(int xIndex) const;
+ int tileSizeY(int yIndex) const;
+ IntRect overlappedTileIndices(const IntRect& srcRect) const;
+ IntRect overlappedTileIndices(const FloatRect& srcRect) const;
+
+ // Given a set of source and destination coordinates for a drawing quad
+ // in texel units, returns adjusted data to render just the one tile.
+ void intersectDrawQuad(const FloatRect& srcRect, const FloatRect& dstRect, int tile, FloatRect* newSrc, FloatRect* newDst) const;
+
+private:
+ TilingData() : m_maxTextureSize(0), m_totalSizeX(0), m_totalSizeY(0) {}
+ void assertTile(int tile) const { ASSERT(tile >= 0 && tile < numTiles()); }
+
+ int m_maxTextureSize;
+ int m_totalSizeX;
+ int m_totalSizeY;
+ int m_borderTexels; // 0 or 1
+
+ // computed values:
+ int m_numTilesX;
+ int m_numTilesY;
+};
+
+}
+
+#endif // TilingData_h
diff --git a/Source/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm b/Source/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm
new file mode 100644
index 0000000..89dcb9c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(3D_CANVAS)
+
+#include "DrawingBuffer.h"
+
+#include "Extensions3D.h"
+#include "WebGLLayer.h"
+
+#import "BlockExceptions.h"
+
+namespace WebCore {
+
+DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, const IntSize& size)
+ : m_context(context)
+ , m_size(size)
+ , m_fbo(context->createFramebuffer())
+ , m_colorBuffer(0)
+ , m_depthStencilBuffer(0)
+ , m_multisampleFBO(0)
+ , m_multisampleColorBuffer(0)
+ , m_multisampleDepthStencilBuffer(0)
+{
+ ASSERT(m_fbo);
+ if (!m_fbo) {
+ clear();
+ return;
+ }
+
+ // Create the WebGLLayer
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ m_platformLayer.adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:m_context.get()]);
+#ifndef NDEBUG
+ [m_platformLayer.get() setName:@"DrawingBuffer Layer"];
+#endif
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ // create a texture to render into
+ m_colorBuffer = context->createTexture();
+ context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer);
+ context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
+ context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
+ context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
+ context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
+
+ // Create the FBO
+ m_fbo = context->createFramebuffer();
+ ASSERT(m_fbo);
+ if (!m_fbo) {
+ clear();
+ return;
+ }
+
+ const GraphicsContext3D::Attributes& attributes = context->getContextAttributes();
+
+ // Create the stencil and depth buffer if needed
+ if (!multisample() && (attributes.stencil || attributes.depth))
+ m_depthStencilBuffer = context->createRenderbuffer();
+
+ // create a multisample FBO
+ if (multisample()) {
+ m_multisampleFBO = context->createFramebuffer();
+ context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO);
+ m_multisampleColorBuffer = context->createRenderbuffer();
+ if (attributes.stencil || attributes.depth)
+ m_multisampleDepthStencilBuffer = context->createRenderbuffer();
+ }
+
+ reset(size);
+}
+
+DrawingBuffer::~DrawingBuffer()
+{
+ clear();
+}
+
+void DrawingBuffer::didReset()
+{
+}
+
+PlatformLayer* DrawingBuffer::platformLayer()
+{
+ return m_platformLayer.get();
+}
+
+Platform3DObject DrawingBuffer::platformColorBuffer() const
+{
+ return m_colorBuffer;
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp
new file mode 100644
index 0000000..06eec14
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "config.h"
+#include "GOwnPtrGStreamer.h"
+
+#if USE(GSTREAMER)
+#include <gst/gstelement.h>
+
+namespace WTF {
+
+template <> void freeOwnedGPtr<GstElement>(GstElement* ptr)
+{
+ if (ptr)
+ gst_object_unref(ptr);
+}
+
+}
+#endif // USE(GSTREAMER)
diff --git a/Source/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h
new file mode 100644
index 0000000..672a23d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GOwnPtrGStreamer_h
+#define GOwnPtrGStreamer_h
+#if USE(GSTREAMER)
+
+#include "GOwnPtr.h"
+
+typedef struct _GstElement GstElement;
+
+namespace WTF {
+
+template<> void freeOwnedGPtr<GstElement>(GstElement* ptr);
+
+}
+
+#endif // USE(GSTREAMER)
+#endif
diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp b/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp
new file mode 100644
index 0000000..d179601
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "GStreamerGWorld.h"
+#if USE(GSTREAMER)
+
+#include "GOwnPtrGStreamer.h"
+#include <gst/gst.h>
+#include <gst/interfaces/xoverlay.h>
+#include <gst/pbutils/pbutils.h>
+
+#if PLATFORM(GTK)
+#include <gtk/gtk.h>
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h> // for GDK_WINDOW_XID
+#endif
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+gboolean gstGWorldSyncMessageCallback(GstBus* bus, GstMessage* message, gpointer data)
+{
+ ASSERT(GST_MESSAGE_TYPE(message) == GST_MESSAGE_ELEMENT);
+
+ GStreamerGWorld* gstGWorld = static_cast<GStreamerGWorld*>(data);
+
+ if (gst_structure_has_name(message->structure, "prepare-xwindow-id"))
+ gstGWorld->setWindowOverlay(message);
+ return TRUE;
+}
+
+PassRefPtr<GStreamerGWorld> GStreamerGWorld::createGWorld(GstElement* pipeline)
+{
+ return adoptRef(new GStreamerGWorld(pipeline));
+}
+
+GStreamerGWorld::GStreamerGWorld(GstElement* pipeline)
+ : m_pipeline(pipeline)
+ , m_dynamicPadName(0)
+{
+ // XOverlay messages need to be handled synchronously.
+ GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline));
+ gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, this);
+ g_signal_connect(bus, "sync-message::element", G_CALLBACK(gstGWorldSyncMessageCallback), this);
+ gst_object_unref(bus);
+}
+
+GStreamerGWorld::~GStreamerGWorld()
+{
+ exitFullscreen();
+
+ m_pipeline = 0;
+}
+
+bool GStreamerGWorld::enterFullscreen()
+{
+ if (m_dynamicPadName)
+ return false;
+
+ if (!m_videoWindow)
+ m_videoWindow = PlatformVideoWindow::createWindow();
+
+ GstElement* platformVideoSink = gst_element_factory_make("autovideosink", "platformVideoSink");
+ GstElement* colorspace = gst_element_factory_make("ffmpegcolorspace", "colorspace");
+ GstElement* queue = gst_element_factory_make("queue", "queue");
+ GstElement* videoScale = gst_element_factory_make("videoscale", "videoScale");
+
+ // Get video sink bin and the tee inside.
+ GOwnPtr<GstElement> videoSink;
+ g_object_get(m_pipeline, "video-sink", &videoSink.outPtr(), NULL);
+ GstElement* tee = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoTee");
+ GstElement* valve = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoValve");
+
+ g_object_set(valve, "drop-probability", 1.0, NULL);
+
+ // Add and link a queue, ffmpegcolorspace, videoscale and sink in the bin.
+ gst_bin_add_many(GST_BIN(videoSink.get()), platformVideoSink, videoScale, colorspace, queue, NULL);
+#if GST_CHECK_VERSION(0, 10, 30)
+ // Faster elements linking, if possible.
+ gst_element_link_pads_full(queue, "src", colorspace, "sink", GST_PAD_LINK_CHECK_NOTHING);
+ gst_element_link_pads_full(colorspace, "src", videoScale, "sink", GST_PAD_LINK_CHECK_NOTHING);
+ gst_element_link_pads_full(videoScale, "src", platformVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING);
+#else
+ gst_element_link_many(queue, colorspace, videoScale, platformVideoSink, NULL);
+#endif
+
+ // Link a new src pad from tee to queue.
+ GstPad* srcPad = gst_element_get_request_pad(tee, "src%d");
+ GstPad* sinkPad = gst_element_get_static_pad(queue, "sink");
+ gst_pad_link(srcPad, sinkPad);
+ gst_object_unref(GST_OBJECT(sinkPad));
+
+ m_dynamicPadName = gst_pad_get_name(srcPad);
+
+ // Roll new elements to pipeline state.
+ gst_element_sync_state_with_parent(queue);
+ gst_element_sync_state_with_parent(colorspace);
+ gst_element_sync_state_with_parent(videoScale);
+ gst_element_sync_state_with_parent(platformVideoSink);
+
+ gst_object_unref(tee);
+
+ // Query the current media segment informations and send them towards
+ // the new tee branch downstream.
+
+ GstQuery* query = gst_query_new_segment(GST_FORMAT_TIME);
+ gboolean queryResult = gst_element_query(m_pipeline, query);
+
+#if GST_CHECK_VERSION(0, 10, 30)
+ if (!queryResult) {
+ gst_query_unref(query);
+ gst_object_unref(GST_OBJECT(srcPad));
+ return true;
+ }
+#else
+ // GStreamer < 0.10.30 doesn't set the query result correctly, so
+ // just ignore it to avoid a compilation warning.
+ // See https://bugzilla.gnome.org/show_bug.cgi?id=620490.
+ (void) queryResult;
+#endif
+
+ GstFormat format;
+ gint64 position;
+ if (!gst_element_query_position(m_pipeline, &format, &position))
+ position = 0;
+
+ gdouble rate;
+ gint64 startValue, stopValue;
+ gst_query_parse_segment(query, &rate, &format, &startValue, &stopValue);
+
+ GstEvent* event = gst_event_new_new_segment(FALSE, rate, format, startValue, stopValue, position);
+ gst_pad_push_event(srcPad, event);
+
+ gst_query_unref(query);
+ gst_object_unref(GST_OBJECT(srcPad));
+ return true;
+}
+
+void GStreamerGWorld::exitFullscreen()
+{
+ if (!m_dynamicPadName)
+ return;
+
+ // Get video sink bin and the elements to remove.
+ GOwnPtr<GstElement> videoSink;
+ g_object_get(m_pipeline, "video-sink", &videoSink.outPtr(), NULL);
+ GstElement* tee = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoTee");
+ GstElement* platformVideoSink = gst_bin_get_by_name(GST_BIN(videoSink.get()), "platformVideoSink");
+ GstElement* queue = gst_bin_get_by_name(GST_BIN(videoSink.get()), "queue");
+ GstElement* colorspace = gst_bin_get_by_name(GST_BIN(videoSink.get()), "colorspace");
+ GstElement* videoScale = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoScale");
+
+ GstElement* valve = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoValve");
+
+ g_object_set(valve, "drop-probability", 0.0, NULL);
+
+ // Get pads to unlink and remove.
+ GstPad* srcPad = gst_element_get_static_pad(tee, m_dynamicPadName);
+ GstPad* sinkPad = gst_element_get_static_pad(queue, "sink");
+
+ // Unlink and release request pad.
+ gst_pad_unlink(srcPad, sinkPad);
+ gst_element_release_request_pad(tee, srcPad);
+ gst_object_unref(GST_OBJECT(srcPad));
+ gst_object_unref(GST_OBJECT(sinkPad));
+
+ // Unlink, remove and cleanup queue, ffmpegcolorspace, videoScale and sink.
+ gst_element_unlink_many(queue, colorspace, videoScale, platformVideoSink, NULL);
+ gst_bin_remove_many(GST_BIN(videoSink.get()), queue, colorspace, videoScale, platformVideoSink, NULL);
+ gst_element_set_state(queue, GST_STATE_NULL);
+ gst_element_set_state(colorspace, GST_STATE_NULL);
+ gst_element_set_state(videoScale, GST_STATE_NULL);
+ gst_element_set_state(platformVideoSink, GST_STATE_NULL);
+ gst_object_unref(queue);
+ gst_object_unref(colorspace);
+ gst_object_unref(videoScale);
+ gst_object_unref(platformVideoSink);
+
+ gst_object_unref(tee);
+ m_dynamicPadName = 0;
+}
+
+void GStreamerGWorld::setWindowOverlay(GstMessage* message)
+{
+ GstObject* sink = GST_MESSAGE_SRC(message);
+
+ if (!GST_IS_X_OVERLAY(sink))
+ return;
+
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(sink), "force-aspect-ratio"))
+ g_object_set(sink, "force-aspect-ratio", TRUE, NULL);
+
+ if (m_videoWindow) {
+ m_videoWindow->prepareForOverlay(message);
+
+// gst_x_overlay_set_window_handle was introduced in -plugins-base
+// 0.10.31, just like the macro for checking the version.
+#ifdef GST_CHECK_PLUGINS_BASE_VERSION
+ gst_x_overlay_set_window_handle(GST_X_OVERLAY(sink), m_videoWindow->videoWindowId());
+#else
+ gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(sink), m_videoWindow->videoWindowId());
+#endif
+ }
+}
+
+}
+#endif // USE(GSTREAMER)
diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h b/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h
new file mode 100644
index 0000000..f519911
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef GStreamerGWorld_h
+#define GStreamerGWorld_h
+#if USE(GSTREAMER)
+
+#include "PlatformVideoWindow.h"
+#include "RefCounted.h"
+#include "RefPtr.h"
+#include <glib.h>
+
+typedef struct _GstElement GstElement;
+typedef struct _GstMessage GstMessage;
+typedef struct _GstBus GstBus;
+typedef struct _GstBin GstBin;
+
+namespace WebCore {
+
+class MediaPlayerPrivateGStreamer;
+
+gboolean gstGWorldSyncMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
+
+class GStreamerGWorld : public RefCounted<GStreamerGWorld> {
+ friend gboolean gstGWorldSyncMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
+
+public:
+ static PassRefPtr<GStreamerGWorld> createGWorld(GstElement*);
+ ~GStreamerGWorld();
+
+ GstElement* pipeline() const { return m_pipeline; }
+
+ // Returns the full-screen window created
+ bool enterFullscreen();
+ void exitFullscreen();
+
+ void setWindowOverlay(GstMessage* message);
+ PlatformVideoWindow* platformVideoWindow() const { return m_videoWindow.get(); }
+
+private:
+ GStreamerGWorld(GstElement*);
+ GstElement* m_pipeline;
+ RefPtr<PlatformVideoWindow> m_videoWindow;
+ gchar* m_dynamicPadName;
+};
+
+}
+#endif // USE(GSTREAMER)
+#endif
diff --git a/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h
new file mode 100644
index 0000000..6e53cfc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef ImageGStreamer_h
+#define ImageGStreamer_h
+
+#if USE(GSTREAMER)
+
+#include "BitmapImage.h"
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <wtf/PassRefPtr.h>
+
+#if PLATFORM(CAIRO)
+#include <cairo.h>
+#endif
+
+namespace WebCore {
+class IntSize;
+
+class ImageGStreamer : public RefCounted<ImageGStreamer> {
+ public:
+ static PassRefPtr<ImageGStreamer> createImage(GstBuffer*);
+ ~ImageGStreamer();
+
+ PassRefPtr<BitmapImage> image()
+ {
+ ASSERT(m_image);
+ return m_image.get();
+ }
+
+ private:
+ RefPtr<BitmapImage> m_image;
+
+#if PLATFORM(CAIRO)
+ ImageGStreamer(GstBuffer*&, IntSize, cairo_format_t&);
+#endif
+
+#if PLATFORM(QT)
+ ImageGStreamer(GstBuffer*&, IntSize, QImage::Format);
+#endif
+
+#if PLATFORM(MAC)
+ ImageGStreamer(GstBuffer*&, IntSize);
+#endif
+
+ };
+}
+
+#endif // USE(GSTREAMER)
+#endif
diff --git a/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm
new file mode 100644
index 0000000..c9a6ca8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "GraphicsContextCG.h"
+#include "ImageGStreamer.h"
+#if USE(GSTREAMER)
+
+using namespace WebCore;
+
+PassRefPtr<ImageGStreamer> ImageGStreamer::createImage(GstBuffer* buffer)
+{
+ int width = 0, height = 0;
+ GstCaps* caps = gst_buffer_get_caps(buffer);
+ GstVideoFormat format;
+ if (!gst_video_format_parse_caps(caps, &format, &width, &height)) {
+ gst_caps_unref(caps);
+ return NULL;
+ }
+
+ return adoptRef(new ImageGStreamer(buffer, IntSize(width, height)));
+}
+
+ImageGStreamer::ImageGStreamer(GstBuffer*& buffer, IntSize size)
+ : m_image(0)
+{
+ ASSERT(GST_BUFFER_SIZE(buffer));
+
+ RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, static_cast<UInt8*>(GST_BUFFER_DATA(buffer)), GST_BUFFER_SIZE(buffer), kCFAllocatorNull));
+ RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithCFData(data.get()));
+ CGImageRef frameImage = CGImageCreate(size.width(), size.height(), 8, 32, size.width()*4, deviceRGBColorSpaceRef(),
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst, provider.get(), 0, false, kCGRenderingIntentDefault);
+ m_image = BitmapImage::create(frameImage);
+}
+
+ImageGStreamer::~ImageGStreamer()
+{
+ if (m_image)
+ m_image.clear();
+
+ m_image = 0;
+}
+
+#endif // USE(GSTREAMER)
diff --git a/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp
new file mode 100644
index 0000000..6a9d068
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ImageGStreamer.h"
+
+#if USE(GSTREAMER)
+
+#include "GOwnPtr.h"
+
+using namespace std;
+using namespace WebCore;
+
+PassRefPtr<ImageGStreamer> ImageGStreamer::createImage(GstBuffer* buffer)
+{
+ int width = 0, height = 0;
+ GstCaps* caps = gst_buffer_get_caps(buffer);
+ GstVideoFormat format;
+ if (!gst_video_format_parse_caps(caps, &format, &width, &height)) {
+ gst_caps_unref(caps);
+ return 0;
+ }
+
+ gst_caps_unref(caps);
+
+ cairo_format_t cairoFormat;
+ if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA)
+ cairoFormat = CAIRO_FORMAT_ARGB32;
+ else
+ cairoFormat = CAIRO_FORMAT_RGB24;
+
+ return adoptRef(new ImageGStreamer(buffer, IntSize(width, height), cairoFormat));
+}
+
+ImageGStreamer::ImageGStreamer(GstBuffer*& buffer, IntSize size, cairo_format_t& cairoFormat)
+ : m_image(0)
+{
+ cairo_surface_t* surface = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), cairoFormat,
+ size.width(), size.height(),
+ cairo_format_stride_for_width(cairoFormat, size.width()));
+ ASSERT(cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS);
+ m_image = BitmapImage::create(surface);
+}
+
+ImageGStreamer::~ImageGStreamer()
+{
+ if (m_image)
+ m_image.clear();
+
+ m_image = 0;
+}
+#endif // USE(GSTREAMER)
diff --git a/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerQt.cpp b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerQt.cpp
new file mode 100644
index 0000000..cf46f02
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerQt.cpp
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "ImageGStreamer.h"
+
+#if USE(GSTREAMER)
+#include "GOwnPtr.h"
+
+using namespace std;
+using namespace WebCore;
+
+PassRefPtr<ImageGStreamer> ImageGStreamer::createImage(GstBuffer* buffer)
+{
+ int width = 0, height = 0;
+ GstCaps* caps = gst_buffer_get_caps(buffer);
+ GstVideoFormat format;
+ if (!gst_video_format_parse_caps(caps, &format, &width, &height)) {
+ gst_caps_unref(caps);
+ return 0;
+ }
+
+ gst_caps_unref(caps);
+
+ QImage::Format imageFormat;
+ if (format == GST_VIDEO_FORMAT_RGB)
+ imageFormat = QImage::Format_RGB888;
+ else
+ imageFormat = QImage::Format_RGB32;
+
+ return adoptRef(new ImageGStreamer(buffer, IntSize(width, height), imageFormat));
+}
+
+ImageGStreamer::ImageGStreamer(GstBuffer*& buffer, IntSize size, QImage::Format imageFormat)
+ : m_image(0)
+{
+ QPixmap* surface = new QPixmap;
+ QImage image(GST_BUFFER_DATA(buffer), size.width(), size.height(), imageFormat);
+ surface->convertFromImage(image);
+ m_image = BitmapImage::create(surface);
+}
+
+ImageGStreamer::~ImageGStreamer()
+{
+ if (m_image)
+ m_image.clear();
+
+ m_image = 0;
+}
+#endif // USE(GSTREAMER)
+
diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
new file mode 100644
index 0000000..c113c69
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
@@ -0,0 +1,1630 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
+ * Copyright (C) 2009, 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * aint with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "MediaPlayerPrivateGStreamer.h"
+
+#if USE(GSTREAMER)
+
+#include "ColorSpace.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GOwnPtrGStreamer.h"
+#include "GStreamerGWorld.h"
+#include "GraphicsContext.h"
+#include "GraphicsTypes.h"
+#include "ImageGStreamer.h"
+#include "IntRect.h"
+#include "KURL.h"
+#include "MIMETypeRegistry.h"
+#include "MediaPlayer.h"
+#include "NotImplemented.h"
+#include "SecurityOrigin.h"
+#include "TimeRanges.h"
+#include "VideoSinkGStreamer.h"
+#include "WebKitWebSourceGStreamer.h"
+#include <GOwnPtr.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <limits>
+#include <math.h>
+
+// GstPlayFlags flags from playbin2. It is the policy of GStreamer to
+// not publicly expose element-specific enums. That's why this
+// GstPlayFlags enum has been copied here.
+typedef enum {
+ GST_PLAY_FLAG_VIDEO = 0x00000001,
+ GST_PLAY_FLAG_AUDIO = 0x00000002,
+ GST_PLAY_FLAG_TEXT = 0x00000004,
+ GST_PLAY_FLAG_VIS = 0x00000008,
+ GST_PLAY_FLAG_SOFT_VOLUME = 0x00000010,
+ GST_PLAY_FLAG_NATIVE_AUDIO = 0x00000020,
+ GST_PLAY_FLAG_NATIVE_VIDEO = 0x00000040,
+ GST_PLAY_FLAG_DOWNLOAD = 0x00000080,
+ GST_PLAY_FLAG_BUFFERING = 0x000000100
+} GstPlayFlags;
+
+using namespace std;
+
+namespace WebCore {
+
+static int greatestCommonDivisor(int a, int b)
+{
+ while (b) {
+ int temp = a;
+ a = b;
+ b = temp % b;
+ }
+
+ return ABS(a);
+}
+
+gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data)
+{
+ GOwnPtr<GError> err;
+ GOwnPtr<gchar> debug;
+ MediaPlayer::NetworkState error;
+ MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data);
+ bool issueError = true;
+ bool attemptNextLocation = false;
+ GstElement* pipeline = mp->pipeline();
+
+ if (message->structure) {
+ const gchar* messageTypeName = gst_structure_get_name(message->structure);
+
+ // Redirect messages are sent from elements, like qtdemux, to
+ // notify of the new location(s) of the media.
+ if (!g_strcmp0(messageTypeName, "redirect")) {
+ mp->mediaLocationChanged(message);
+ return true;
+ }
+ }
+
+ switch (GST_MESSAGE_TYPE(message)) {
+ case GST_MESSAGE_ERROR:
+ if (mp && mp->pipelineReset())
+ break;
+ gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
+ LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message);
+
+ error = MediaPlayer::Empty;
+ if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND
+ || err->code == GST_STREAM_ERROR_WRONG_TYPE
+ || err->code == GST_STREAM_ERROR_FAILED
+ || err->code == GST_CORE_ERROR_MISSING_PLUGIN
+ || err->code == GST_RESOURCE_ERROR_NOT_FOUND)
+ error = MediaPlayer::FormatError;
+ else if (err->domain == GST_STREAM_ERROR) {
+ error = MediaPlayer::DecodeError;
+ attemptNextLocation = true;
+ } else if (err->domain == GST_RESOURCE_ERROR)
+ error = MediaPlayer::NetworkError;
+
+ if (mp) {
+ if (attemptNextLocation)
+ issueError = !mp->loadNextLocation();
+ if (issueError)
+ mp->loadingFailed(error);
+ }
+ break;
+ case GST_MESSAGE_EOS:
+ LOG_VERBOSE(Media, "End of Stream");
+ mp->didEnd();
+ break;
+ case GST_MESSAGE_STATE_CHANGED:
+ // Ignore state changes if load is delayed (preload=none). The
+ // player state will be updated once commitLoad() is called.
+ if (mp->loadDelayed()) {
+ LOG_VERBOSE(Media, "Media load has been delayed. Ignoring state changes for now");
+ break;
+ }
+
+ // Ignore state changes from internal elements. They are
+ // forwarded to playbin2 anyway.
+ if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(pipeline))
+ mp->updateStates();
+ break;
+ case GST_MESSAGE_BUFFERING:
+ mp->processBufferingStats(message);
+ break;
+ case GST_MESSAGE_DURATION:
+ LOG_VERBOSE(Media, "Duration changed");
+ mp->durationChanged();
+ break;
+ default:
+ LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s",
+ GST_MESSAGE_TYPE_NAME(message));
+ break;
+ }
+ return true;
+}
+
+void mediaPlayerPrivateSourceChangedCallback(GObject *object, GParamSpec *pspec, gpointer data)
+{
+ MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data);
+ GOwnPtr<GstElement> element;
+
+ g_object_get(mp->m_playBin, "source", &element.outPtr(), NULL);
+ gst_object_replace((GstObject**) &mp->m_source, (GstObject*) element.get());
+
+ if (WEBKIT_IS_WEB_SRC(element.get())) {
+ Frame* frame = mp->m_player->frameView() ? mp->m_player->frameView()->frame() : 0;
+
+ if (frame)
+ webKitWebSrcSetFrame(WEBKIT_WEB_SRC(element.get()), frame);
+ }
+}
+
+void mediaPlayerPrivateVolumeChangedCallback(GObject *element, GParamSpec *pspec, gpointer data)
+{
+ // This is called when playbin receives the notify::volume signal.
+ MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data);
+ mp->volumeChanged();
+}
+
+gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+{
+ // This is the callback of the timeout source created in ::volumeChanged.
+ player->notifyPlayerOfVolumeChange();
+ return FALSE;
+}
+
+void mediaPlayerPrivateMuteChangedCallback(GObject *element, GParamSpec *pspec, gpointer data)
+{
+ // This is called when playbin receives the notify::mute signal.
+ MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data);
+ mp->muteChanged();
+}
+
+gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+{
+ // This is the callback of the timeout source created in ::muteChanged.
+ player->notifyPlayerOfMute();
+ return FALSE;
+}
+
+void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player)
+{
+ player->videoTagsChanged(streamId);
+}
+
+void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player)
+{
+ player->audioTagsChanged(streamId);
+}
+
+gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+{
+ // This is the callback of the timeout source created in ::audioTagsChanged.
+ player->notifyPlayerOfAudioTags();
+ return FALSE;
+}
+
+gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+{
+ // This is the callback of the timeout source created in ::videoTagsChanged.
+ player->notifyPlayerOfVideoTags();
+ return FALSE;
+}
+
+static float playbackPosition(GstElement* playbin)
+{
+
+ float ret = 0.0f;
+
+ GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
+ if (!gst_element_query(playbin, query)) {
+ LOG_VERBOSE(Media, "Position query failed...");
+ gst_query_unref(query);
+ return ret;
+ }
+
+ gint64 position;
+ gst_query_parse_position(query, 0, &position);
+
+ // Position is available only if the pipeline is not in GST_STATE_NULL or
+ // GST_STATE_READY state.
+ if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE))
+ ret = static_cast<float>(position) / static_cast<float>(GST_SECOND);
+
+ LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
+
+ gst_query_unref(query);
+
+ return ret;
+}
+
+
+void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamer* playerPrivate)
+{
+ g_return_if_fail(GST_IS_BUFFER(buffer));
+ gst_buffer_replace(&playerPrivate->m_buffer, buffer);
+ playerPrivate->repaint();
+}
+
+MediaPlayerPrivateInterface* MediaPlayerPrivateGStreamer::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivateGStreamer(player);
+}
+
+void MediaPlayerPrivateGStreamer::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+static bool gstInitialized = false;
+
+static bool doGstInit()
+{
+ // FIXME: We should pass the arguments from the command line
+ if (!gstInitialized) {
+ GOwnPtr<GError> error;
+ gstInitialized = gst_init_check(0, 0, &error.outPtr());
+ if (!gstInitialized)
+ LOG_VERBOSE(Media, "Could not initialize GStreamer: %s",
+ error ? error->message : "unknown error occurred");
+ else
+ gst_element_register(0, "webkitwebsrc", GST_RANK_PRIMARY + 100,
+ WEBKIT_TYPE_WEB_SRC);
+ }
+ return gstInitialized;
+}
+
+bool MediaPlayerPrivateGStreamer::isAvailable()
+{
+ if (!doGstInit())
+ return false;
+
+ GstElementFactory* factory = gst_element_factory_find("playbin2");
+ if (factory) {
+ gst_object_unref(GST_OBJECT(factory));
+ return true;
+ }
+ return false;
+}
+
+MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
+ : m_player(player)
+ , m_playBin(0)
+ , m_webkitVideoSink(0)
+ , m_fpsSink(0)
+ , m_source(0)
+ , m_seekTime(0)
+ , m_changingRate(false)
+ , m_endTime(numeric_limits<float>::infinity())
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_isStreaming(false)
+ , m_size(IntSize())
+ , m_buffer(0)
+ , m_mediaLocations(0)
+ , m_mediaLocationCurrentIndex(0)
+ , m_resetPipeline(false)
+ , m_paused(true)
+ , m_seeking(false)
+ , m_buffering(false)
+ , m_playbackRate(1)
+ , m_errorOccured(false)
+ , m_mediaDuration(0)
+ , m_startedBuffering(false)
+ , m_fillTimer(this, &MediaPlayerPrivateGStreamer::fillTimerFired)
+ , m_maxTimeLoaded(0)
+ , m_bufferingPercentage(0)
+ , m_preload(MediaPlayer::Auto)
+ , m_delayingLoad(false)
+ , m_mediaDurationKnown(true)
+ , m_volumeTimerHandler(0)
+ , m_muteTimerHandler(0)
+ , m_hasVideo(false)
+ , m_hasAudio(false)
+ , m_audioTagsTimerHandler(0)
+ , m_videoTagsTimerHandler(0)
+{
+ if (doGstInit())
+ createGSTPlayBin();
+}
+
+MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
+{
+ if (m_fillTimer.isActive())
+ m_fillTimer.stop();
+
+ if (m_buffer)
+ gst_buffer_unref(m_buffer);
+ m_buffer = 0;
+
+ if (m_mediaLocations) {
+ gst_structure_free(m_mediaLocations);
+ m_mediaLocations = 0;
+ }
+
+ if (m_source) {
+ gst_object_unref(m_source);
+ m_source = 0;
+ }
+
+ if (m_videoSinkBin) {
+ gst_object_unref(m_videoSinkBin);
+ m_videoSinkBin = 0;
+ }
+
+ if (m_playBin) {
+ gst_element_set_state(m_playBin, GST_STATE_NULL);
+ gst_object_unref(GST_OBJECT(m_playBin));
+ m_playBin = 0;
+ }
+
+ m_player = 0;
+
+ if (m_muteTimerHandler)
+ g_source_remove(m_muteTimerHandler);
+
+ if (m_volumeTimerHandler)
+ g_source_remove(m_volumeTimerHandler);
+
+ if (m_videoTagsTimerHandler)
+ g_source_remove(m_videoTagsTimerHandler);
+
+ if (m_audioTagsTimerHandler)
+ g_source_remove(m_audioTagsTimerHandler);
+}
+
+void MediaPlayerPrivateGStreamer::load(const String& url)
+{
+ g_object_set(m_playBin, "uri", url.utf8().data(), NULL);
+
+ LOG_VERBOSE(Media, "Load %s", url.utf8().data());
+
+ if (m_preload == MediaPlayer::None) {
+ LOG_VERBOSE(Media, "Delaying load.");
+ m_delayingLoad = true;
+ }
+
+ // GStreamer needs to have the pipeline set to a paused state to
+ // start providing anything useful.
+ gst_element_set_state(m_playBin, GST_STATE_PAUSED);
+
+ if (!m_delayingLoad)
+ commitLoad();
+}
+
+void MediaPlayerPrivateGStreamer::commitLoad()
+{
+ ASSERT(!m_delayingLoad);
+ LOG_VERBOSE(Media, "Committing load.");
+ updateStates();
+}
+
+bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
+{
+ ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED);
+
+ GstState currentState;
+ GstState pending;
+
+ gst_element_get_state(m_playBin, &currentState, &pending, 0);
+ if (currentState != newState && pending != newState) {
+ GstStateChangeReturn ret = gst_element_set_state(m_playBin, newState);
+ GstState pausedOrPlaying = newState == GST_STATE_PLAYING ? GST_STATE_PAUSED : GST_STATE_PLAYING;
+ if (currentState != pausedOrPlaying && ret == GST_STATE_CHANGE_FAILURE) {
+ loadingFailed(MediaPlayer::Empty);
+ return false;
+ }
+ }
+ return true;
+}
+
+void MediaPlayerPrivateGStreamer::prepareToPlay()
+{
+ if (m_delayingLoad) {
+ m_delayingLoad = false;
+ commitLoad();
+ }
+}
+
+void MediaPlayerPrivateGStreamer::play()
+{
+ if (changePipelineState(GST_STATE_PLAYING))
+ LOG_VERBOSE(Media, "Play");
+}
+
+void MediaPlayerPrivateGStreamer::pause()
+{
+ if (changePipelineState(GST_STATE_PAUSED))
+ LOG_VERBOSE(Media, "Pause");
+}
+
+float MediaPlayerPrivateGStreamer::duration() const
+{
+ if (!m_playBin)
+ return 0.0f;
+
+ if (m_errorOccured)
+ return 0.0f;
+
+ // Media duration query failed already, don't attempt new useless queries.
+ if (!m_mediaDurationKnown)
+ return numeric_limits<float>::infinity();
+
+ if (m_mediaDuration)
+ return m_mediaDuration;
+
+ GstFormat timeFormat = GST_FORMAT_TIME;
+ gint64 timeLength = 0;
+
+ if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE) {
+ LOG_VERBOSE(Media, "Time duration query failed.");
+ return numeric_limits<float>::infinity();
+ }
+
+ LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
+
+ return (float) ((guint64) timeLength / 1000000000.0);
+ // FIXME: handle 3.14.9.5 properly
+}
+
+float MediaPlayerPrivateGStreamer::currentTime() const
+{
+ if (!m_playBin)
+ return 0.0f;
+
+ if (m_errorOccured)
+ return 0.0f;
+
+ if (m_seeking)
+ return static_cast<float>(m_seekTime);
+
+ return playbackPosition(m_playBin);
+
+}
+
+void MediaPlayerPrivateGStreamer::seek(float time)
+{
+ // Avoid useless seeking.
+ if (time == playbackPosition(m_playBin))
+ return;
+
+ if (!m_playBin)
+ return;
+
+ if (m_errorOccured)
+ return;
+
+ GstClockTime sec = (GstClockTime)(static_cast<float>(time * GST_SECOND));
+ LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec));
+ if (!gst_element_seek(m_playBin, m_player->rate(),
+ GST_FORMAT_TIME,
+ (GstSeekFlags)(GST_SEEK_FLAG_FLUSH),
+ GST_SEEK_TYPE_SET, sec,
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
+ LOG_VERBOSE(Media, "Seek to %f failed", time);
+ else {
+ m_seeking = true;
+ m_seekTime = sec;
+ }
+}
+
+bool MediaPlayerPrivateGStreamer::paused() const
+{
+ return m_paused;
+}
+
+bool MediaPlayerPrivateGStreamer::seeking() const
+{
+ return m_seeking;
+}
+
+// Returns the size of the video
+IntSize MediaPlayerPrivateGStreamer::naturalSize() const
+{
+ if (!hasVideo())
+ return IntSize();
+
+ GstPad* pad = gst_element_get_static_pad(m_webkitVideoSink, "sink");
+ if (!pad)
+ return IntSize();
+
+ guint64 width = 0, height = 0;
+ GstCaps* caps = GST_PAD_CAPS(pad);
+ int pixelAspectRatioNumerator, pixelAspectRatioDenominator;
+ int displayWidth, displayHeight, displayAspectRatioGCD;
+ int originalWidth = 0, originalHeight = 0;
+
+ // TODO: handle possible clean aperture data. See
+ // https://bugzilla.gnome.org/show_bug.cgi?id=596571
+ // TODO: handle possible transformation matrix. See
+ // https://bugzilla.gnome.org/show_bug.cgi?id=596326
+
+ // Get the video PAR and original size.
+ if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps)
+ || !gst_video_format_parse_caps(caps, 0, &originalWidth, &originalHeight)
+ || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator,
+ &pixelAspectRatioDenominator)) {
+ gst_object_unref(GST_OBJECT(pad));
+ return IntSize();
+ }
+
+ gst_object_unref(GST_OBJECT(pad));
+
+ LOG_VERBOSE(Media, "Original video size: %dx%d", originalWidth, originalHeight);
+ LOG_VERBOSE(Media, "Pixel aspect ratio: %d/%d", pixelAspectRatioNumerator, pixelAspectRatioDenominator);
+
+ // Calculate DAR based on PAR and video size.
+ displayWidth = originalWidth * pixelAspectRatioNumerator;
+ displayHeight = originalHeight * pixelAspectRatioDenominator;
+
+ // Divide display width and height by their GCD to avoid possible overflows.
+ displayAspectRatioGCD = greatestCommonDivisor(displayWidth, displayHeight);
+ displayWidth /= displayAspectRatioGCD;
+ displayHeight /= displayAspectRatioGCD;
+
+ // Apply DAR to original video size. This is the same behavior as in xvimagesink's setcaps function.
+ if (!(originalHeight % displayHeight)) {
+ LOG_VERBOSE(Media, "Keeping video original height");
+ width = gst_util_uint64_scale_int(originalHeight, displayWidth, displayHeight);
+ height = static_cast<guint64>(originalHeight);
+ } else if (!(originalWidth % displayWidth)) {
+ LOG_VERBOSE(Media, "Keeping video original width");
+ height = gst_util_uint64_scale_int(originalWidth, displayHeight, displayWidth);
+ width = static_cast<guint64>(originalWidth);
+ } else {
+ LOG_VERBOSE(Media, "Approximating while keeping original video height");
+ width = gst_util_uint64_scale_int(originalHeight, displayWidth, displayHeight);
+ height = static_cast<guint64>(originalHeight);
+ }
+
+ LOG_VERBOSE(Media, "Natural size: %" G_GUINT64_FORMAT "x%" G_GUINT64_FORMAT, width, height);
+ return IntSize(static_cast<int>(width), static_cast<int>(height));
+}
+
+void MediaPlayerPrivateGStreamer::videoTagsChanged(gint streamId)
+{
+ if (m_videoTagsTimerHandler)
+ g_source_remove(m_videoTagsTimerHandler);
+ m_videoTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoTagsChangeTimeoutCallback), this);
+}
+
+void MediaPlayerPrivateGStreamer::notifyPlayerOfVideoTags()
+{
+ m_videoTagsTimerHandler = 0;
+
+ gint currentVideo = -1;
+ if (m_playBin)
+ g_object_get(m_playBin, "current-video", &currentVideo, NULL);
+ m_hasVideo = currentVideo > -1;
+ m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
+}
+
+void MediaPlayerPrivateGStreamer::audioTagsChanged(gint streamId)
+{
+ if (m_audioTagsTimerHandler)
+ g_source_remove(m_audioTagsTimerHandler);
+ m_audioTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioTagsChangeTimeoutCallback), this);
+}
+
+void MediaPlayerPrivateGStreamer::notifyPlayerOfAudioTags()
+{
+ m_audioTagsTimerHandler = 0;
+
+ gint currentAudio = -1;
+ if (m_playBin)
+ g_object_get(m_playBin, "current-audio", &currentAudio, NULL);
+ m_hasAudio = currentAudio > -1;
+ m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
+}
+
+void MediaPlayerPrivateGStreamer::setVolume(float volume)
+{
+ if (!m_playBin)
+ return;
+
+ g_object_set(m_playBin, "volume", static_cast<double>(volume), NULL);
+}
+
+void MediaPlayerPrivateGStreamer::notifyPlayerOfVolumeChange()
+{
+ m_volumeTimerHandler = 0;
+
+ if (!m_player || !m_playBin)
+ return;
+ double volume;
+ g_object_get(m_playBin, "volume", &volume, NULL);
+ m_player->volumeChanged(static_cast<float>(volume));
+}
+
+void MediaPlayerPrivateGStreamer::volumeChanged()
+{
+ if (m_volumeTimerHandler)
+ g_source_remove(m_volumeTimerHandler);
+ m_volumeTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVolumeChangeTimeoutCallback), this);
+}
+
+void MediaPlayerPrivateGStreamer::setRate(float rate)
+{
+ // Avoid useless playback rate update.
+ if (m_playbackRate == rate)
+ return;
+
+ GstState state;
+ GstState pending;
+
+ gst_element_get_state(m_playBin, &state, &pending, 0);
+ if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED)
+ || (pending == GST_STATE_PAUSED))
+ return;
+
+ if (m_isStreaming)
+ return;
+
+ m_playbackRate = rate;
+ m_changingRate = true;
+ float currentPosition = static_cast<float>(playbackPosition(m_playBin) * GST_SECOND);
+ GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH);
+ gint64 start, end;
+ bool mute = false;
+
+ LOG_VERBOSE(Media, "Set Rate to %f", rate);
+ if (rate >= 0) {
+ // Mute the sound if the playback rate is too extreme.
+ // TODO: in other cases we should perform pitch adjustments.
+ mute = (bool) (rate < 0.8 || rate > 2);
+ start = currentPosition;
+ end = GST_CLOCK_TIME_NONE;
+ } else {
+ start = 0;
+ mute = true;
+
+ // If we are at beginning of media, start from the end to
+ // avoid immediate EOS.
+ if (currentPosition <= 0)
+ end = static_cast<gint64>(duration() * GST_SECOND);
+ else
+ end = currentPosition;
+ }
+
+ LOG_VERBOSE(Media, "Need to mute audio: %d", (int) mute);
+
+ if (!gst_element_seek(m_playBin, rate, GST_FORMAT_TIME, flags,
+ GST_SEEK_TYPE_SET, start,
+ GST_SEEK_TYPE_SET, end))
+ LOG_VERBOSE(Media, "Set rate to %f failed", rate);
+ else
+ g_object_set(m_playBin, "mute", mute, NULL);
+}
+
+MediaPlayer::NetworkState MediaPlayerPrivateGStreamer::networkState() const
+{
+ return m_networkState;
+}
+
+MediaPlayer::ReadyState MediaPlayerPrivateGStreamer::readyState() const
+{
+ return m_readyState;
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const
+{
+ RefPtr<TimeRanges> timeRanges = TimeRanges::create();
+ if (m_errorOccured || m_isStreaming)
+ return timeRanges.release();
+
+#if GST_CHECK_VERSION(0, 10, 31)
+ float mediaDuration(duration());
+ if (!mediaDuration || isinf(mediaDuration))
+ return timeRanges.release();
+
+ GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
+
+ if (!gst_element_query(m_playBin, query)) {
+ gst_query_unref(query);
+ return timeRanges.release();
+ }
+
+ gint64 rangeStart = 0, rangeStop = 0;
+ for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) {
+ if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop))
+ timeRanges->add(static_cast<float>((rangeStart * mediaDuration) / 100),
+ static_cast<float>((rangeStop * mediaDuration) / 100));
+ }
+
+ // Fallback to the more general maxTimeLoaded() if no range has
+ // been found.
+ if (!timeRanges->length())
+ if (float loaded = maxTimeLoaded())
+ timeRanges->add(0, loaded);
+
+ gst_query_unref(query);
+#else
+ float loaded = maxTimeLoaded();
+ if (!m_errorOccured && !m_isStreaming && loaded > 0)
+ timeRanges->add(0, loaded);
+#endif
+ return timeRanges.release();
+}
+
+void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message)
+{
+ // This is the immediate buffering that needs to happen so we have
+ // enough to play right now.
+ m_buffering = true;
+ const GstStructure *structure = gst_message_get_structure(message);
+ gst_structure_get_int(structure, "buffer-percent", &m_bufferingPercentage);
+
+ LOG_VERBOSE(Media, "[Buffering] Buffering: %d%%.", m_bufferingPercentage);
+
+ GstBufferingMode mode;
+ gst_message_parse_buffering_stats(message, &mode, 0, 0, 0);
+ if (mode != GST_BUFFERING_DOWNLOAD) {
+ updateStates();
+ return;
+ }
+
+ // This is on-disk buffering, that allows us to download much more
+ // than needed for right now.
+ if (!m_startedBuffering) {
+ LOG_VERBOSE(Media, "[Buffering] Starting on-disk buffering.");
+
+ m_startedBuffering = true;
+
+ if (m_fillTimer.isActive())
+ m_fillTimer.stop();
+
+ m_fillTimer.startRepeating(0.2);
+ }
+}
+
+void MediaPlayerPrivateGStreamer::fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*)
+{
+ GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
+
+ if (!gst_element_query(m_playBin, query)) {
+ gst_query_unref(query);
+ return;
+ }
+
+ gint64 start, stop;
+ gdouble fillStatus = 100.0;
+
+ gst_query_parse_buffering_range(query, 0, &start, &stop, 0);
+ gst_query_unref(query);
+
+ if (stop != -1)
+ fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
+
+ LOG_VERBOSE(Media, "[Buffering] Download buffer filled up to %f%%", fillStatus);
+
+ if (!m_mediaDuration)
+ durationChanged();
+
+ // Update maxTimeLoaded only if the media duration is
+ // available. Otherwise we can't compute it.
+ if (m_mediaDuration) {
+ if (fillStatus == 100.0)
+ m_maxTimeLoaded = m_mediaDuration;
+ else
+ m_maxTimeLoaded = static_cast<float>((fillStatus * m_mediaDuration) / 100.0);
+ LOG_VERBOSE(Media, "[Buffering] Updated maxTimeLoaded: %f", m_maxTimeLoaded);
+ }
+
+ if (fillStatus != 100.0) {
+ updateStates();
+ return;
+ }
+
+ // Media is now fully loaded. It will play even if network
+ // connection is cut. Buffering is done, remove the fill source
+ // from the main loop.
+ m_fillTimer.stop();
+ m_startedBuffering = false;
+ updateStates();
+}
+
+float MediaPlayerPrivateGStreamer::maxTimeSeekable() const
+{
+ if (m_errorOccured)
+ return 0.0f;
+
+ LOG_VERBOSE(Media, "maxTimeSeekable");
+ // infinite duration means live stream
+ if (isinf(duration()))
+ return 0.0f;
+
+ return duration();
+}
+
+float MediaPlayerPrivateGStreamer::maxTimeLoaded() const
+{
+ if (m_errorOccured)
+ return 0.0f;
+
+ float loaded = m_maxTimeLoaded;
+ if (!loaded && !m_fillTimer.isActive())
+ loaded = duration();
+ LOG_VERBOSE(Media, "maxTimeLoaded: %f", loaded);
+ return loaded;
+}
+
+unsigned MediaPlayerPrivateGStreamer::bytesLoaded() const
+{
+ if (!m_playBin)
+ return 0;
+
+ if (!m_mediaDuration)
+ return 0;
+
+ unsigned loaded = totalBytes() * maxTimeLoaded() / m_mediaDuration;
+ LOG_VERBOSE(Media, "bytesLoaded: %d", loaded);
+ return loaded;
+}
+
+unsigned MediaPlayerPrivateGStreamer::totalBytes() const
+{
+ if (!m_source)
+ return 0;
+
+ if (m_errorOccured)
+ return 0;
+
+ GstFormat fmt = GST_FORMAT_BYTES;
+ gint64 length = 0;
+ if (gst_element_query_duration(m_source, &fmt, &length)) {
+ LOG_VERBOSE(Media, "totalBytes %" G_GINT64_FORMAT, length);
+ return static_cast<unsigned>(length);
+ }
+
+ // Fall back to querying the source pads manually.
+ // See also https://bugzilla.gnome.org/show_bug.cgi?id=638749
+ GstIterator* iter = gst_element_iterate_src_pads(m_source);
+ bool done = false;
+ while (!done) {
+ gpointer data;
+
+ switch (gst_iterator_next(iter, &data)) {
+ case GST_ITERATOR_OK: {
+ GstPad* pad = GST_PAD_CAST(data);
+ gint64 padLength = 0;
+ if (gst_pad_query_duration(pad, &fmt, &padLength)
+ && padLength > length)
+ length = padLength;
+ gst_object_unref(pad);
+ break;
+ }
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync(iter);
+ break;
+ case GST_ITERATOR_ERROR:
+ // Fall through.
+ case GST_ITERATOR_DONE:
+ done = true;
+ break;
+ }
+ }
+ gst_iterator_free(iter);
+
+ LOG_VERBOSE(Media, "totalBytes %" G_GINT64_FORMAT, length);
+
+ return static_cast<unsigned>(length);
+}
+
+void MediaPlayerPrivateGStreamer::cancelLoad()
+{
+ if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
+ return;
+
+ if (m_playBin)
+ gst_element_set_state(m_playBin, GST_STATE_NULL);
+}
+
+void MediaPlayerPrivateGStreamer::updateStates()
+{
+ if (!m_playBin)
+ return;
+
+ if (m_errorOccured)
+ return;
+
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+ GstState state;
+ GstState pending;
+
+ GstStateChangeReturn ret = gst_element_get_state(m_playBin,
+ &state, &pending, 250 * GST_NSECOND);
+
+ bool shouldUpdateAfterSeek = false;
+ switch (ret) {
+ case GST_STATE_CHANGE_SUCCESS:
+ LOG_VERBOSE(Media, "State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
+
+ m_resetPipeline = state <= GST_STATE_READY;
+
+ // Try to figure out ready and network states.
+ if (state == GST_STATE_READY) {
+ m_readyState = MediaPlayer::HaveMetadata;
+ m_networkState = MediaPlayer::Empty;
+ // Cache the duration without emiting the durationchange
+ // event because it's taken care of by the media element
+ // in this precise case.
+ cacheDuration();
+ } else if (maxTimeLoaded() == duration()) {
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else {
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+ m_networkState = MediaPlayer::Loading;
+ }
+
+ if (m_buffering && state != GST_STATE_READY) {
+ m_readyState = MediaPlayer::HaveCurrentData;
+ m_networkState = MediaPlayer::Loading;
+ }
+
+ // Now let's try to get the states in more detail using
+ // information from GStreamer, while we sync states where
+ // needed.
+ if (state == GST_STATE_PAUSED) {
+ if (m_buffering && m_bufferingPercentage == 100) {
+ m_buffering = false;
+ m_bufferingPercentage = 0;
+ m_readyState = MediaPlayer::HaveEnoughData;
+
+ LOG_VERBOSE(Media, "[Buffering] Complete.");
+
+ if (!m_paused) {
+ LOG_VERBOSE(Media, "[Buffering] Restarting playback.");
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ }
+ } else if (!m_buffering && (currentTime() < duration())) {
+ m_paused = true;
+ }
+ } else if (state == GST_STATE_PLAYING) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ m_paused = false;
+
+ if (m_buffering) {
+ m_readyState = MediaPlayer::HaveCurrentData;
+ m_networkState = MediaPlayer::Loading;
+
+ LOG_VERBOSE(Media, "[Buffering] Pausing stream for buffering.");
+
+ gst_element_set_state(m_playBin, GST_STATE_PAUSED);
+ }
+ } else
+ m_paused = true;
+
+ // Is on-disk buffering in progress?
+ if (m_fillTimer.isActive())
+ m_networkState = MediaPlayer::Loading;
+
+ if (m_changingRate) {
+ m_player->rateChanged();
+ m_changingRate = false;
+ }
+
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ }
+
+ break;
+ case GST_STATE_CHANGE_ASYNC:
+ LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
+ // Change in progress
+
+ if (!m_isStreaming && !m_buffering)
+ return;
+
+ // Resume playback if a seek was performed in a live pipeline
+ // or during progressive download. That second use-case
+ // happens when the seek is performed to a region of the media
+ // that hasn't been downloaded yet.
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ if (m_paused)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ }
+ break;
+ case GST_STATE_CHANGE_FAILURE:
+ LOG_VERBOSE(Media, "Failure: State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
+ // Change failed
+ return;
+ case GST_STATE_CHANGE_NO_PREROLL:
+ LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
+
+ if (state == GST_STATE_READY)
+ m_readyState = MediaPlayer::HaveNothing;
+ else if (state == GST_STATE_PAUSED) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ m_paused = true;
+ // Live pipelines go in PAUSED without prerolling.
+ m_isStreaming = true;
+ } else if (state == GST_STATE_PLAYING)
+ m_paused = false;
+
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ if (!m_paused)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ } else if (!m_paused)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+
+ m_networkState = MediaPlayer::Loading;
+ break;
+ default:
+ LOG_VERBOSE(Media, "Else : %d", ret);
+ break;
+ }
+
+ if (seeking())
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (shouldUpdateAfterSeek)
+ timeChanged();
+
+ if (m_networkState != oldNetworkState) {
+ LOG_VERBOSE(Media, "Network State Changed from %u to %u",
+ oldNetworkState, m_networkState);
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != oldReadyState) {
+ LOG_VERBOSE(Media, "Ready State Changed from %u to %u",
+ oldReadyState, m_readyState);
+ m_player->readyStateChanged();
+ }
+}
+
+void MediaPlayerPrivateGStreamer::mediaLocationChanged(GstMessage* message)
+{
+ if (m_mediaLocations)
+ gst_structure_free(m_mediaLocations);
+
+ if (message->structure) {
+ // This structure can contain:
+ // - both a new-location string and embedded locations structure
+ // - or only a new-location string.
+ m_mediaLocations = gst_structure_copy(message->structure);
+ const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
+
+ if (locations)
+ m_mediaLocationCurrentIndex = static_cast<int>(gst_value_list_get_size(locations)) -1;
+
+ loadNextLocation();
+ }
+}
+
+bool MediaPlayerPrivateGStreamer::loadNextLocation()
+{
+ if (!m_mediaLocations)
+ return false;
+
+ const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
+ const gchar* newLocation = 0;
+
+ if (!locations) {
+ // Fallback on new-location string.
+ newLocation = gst_structure_get_string(m_mediaLocations, "new-location");
+ if (!newLocation)
+ return false;
+ }
+
+ if (!newLocation) {
+ if (m_mediaLocationCurrentIndex < 0) {
+ m_mediaLocations = 0;
+ return false;
+ }
+
+ const GValue* location = gst_value_list_get_value(locations,
+ m_mediaLocationCurrentIndex);
+ const GstStructure* structure = gst_value_get_structure(location);
+
+ if (!structure) {
+ m_mediaLocationCurrentIndex--;
+ return false;
+ }
+
+ newLocation = gst_structure_get_string(structure, "new-location");
+ }
+
+ if (newLocation) {
+ // Found a candidate. new-location is not always an absolute url
+ // though. We need to take the base of the current url and
+ // append the value of new-location to it.
+
+ gchar* currentLocation = 0;
+ g_object_get(m_playBin, "uri", &currentLocation, NULL);
+
+ KURL currentUrl(KURL(), currentLocation);
+ g_free(currentLocation);
+
+ KURL newUrl;
+
+ if (gst_uri_is_valid(newLocation))
+ newUrl = KURL(KURL(), newLocation);
+ else
+ newUrl = KURL(KURL(), currentUrl.baseAsString() + newLocation);
+
+ RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(currentUrl);
+ if (securityOrigin->canRequest(newUrl)) {
+ LOG_VERBOSE(Media, "New media url: %s", newUrl.string().utf8().data());
+
+ // Reset player states.
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+
+ // Reset pipeline state.
+ m_resetPipeline = true;
+ gst_element_set_state(m_playBin, GST_STATE_READY);
+
+ GstState state;
+ gst_element_get_state(m_playBin, &state, 0, 0);
+ if (state <= GST_STATE_READY) {
+ // Set the new uri and start playing.
+ g_object_set(m_playBin, "uri", newUrl.string().utf8().data(), NULL);
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ return true;
+ }
+ }
+ }
+ m_mediaLocationCurrentIndex--;
+ return false;
+
+}
+
+void MediaPlayerPrivateGStreamer::loadStateChanged()
+{
+ updateStates();
+}
+
+void MediaPlayerPrivateGStreamer::sizeChanged()
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivateGStreamer::timeChanged()
+{
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivateGStreamer::didEnd()
+{
+ // EOS was reached but in case of reverse playback the position is
+ // not always 0. So to not confuse the HTMLMediaElement we
+ // synchronize position and duration values.
+ float now = currentTime();
+ if (now > 0) {
+ m_mediaDuration = now;
+ m_mediaDurationKnown = true;
+ m_player->durationChanged();
+ }
+
+ gst_element_set_state(m_playBin, GST_STATE_PAUSED);
+
+ timeChanged();
+}
+
+void MediaPlayerPrivateGStreamer::cacheDuration()
+{
+ // Reset cached media duration
+ m_mediaDuration = 0;
+
+ // And re-cache it if possible.
+ GstState state;
+ gst_element_get_state(m_playBin, &state, 0, 0);
+ float newDuration = duration();
+
+ if (state <= GST_STATE_READY) {
+ // Don't set m_mediaDurationKnown yet if the pipeline is not
+ // paused. This allows duration() query to fail at least once
+ // before playback starts and duration becomes known.
+ if (!isinf(newDuration))
+ m_mediaDuration = newDuration;
+ } else {
+ m_mediaDurationKnown = !isinf(newDuration);
+ if (m_mediaDurationKnown)
+ m_mediaDuration = newDuration;
+ }
+
+ if (!isinf(newDuration))
+ m_mediaDuration = newDuration;
+}
+
+void MediaPlayerPrivateGStreamer::durationChanged()
+{
+ float previousDuration = m_mediaDuration;
+
+ cacheDuration();
+ // Avoid emiting durationchanged in the case where the previous
+ // duration was 0 because that case is already handled by the
+ // HTMLMediaElement.
+ if (previousDuration && m_mediaDuration != previousDuration)
+ m_player->durationChanged();
+}
+
+bool MediaPlayerPrivateGStreamer::supportsMuting() const
+{
+ return true;
+}
+
+void MediaPlayerPrivateGStreamer::setMuted(bool muted)
+{
+ if (!m_playBin)
+ return;
+
+ g_object_set(m_playBin, "mute", muted, NULL);
+}
+
+void MediaPlayerPrivateGStreamer::notifyPlayerOfMute()
+{
+ m_muteTimerHandler = 0;
+
+ if (!m_player || !m_playBin)
+ return;
+
+ gboolean muted;
+ g_object_get(m_playBin, "mute", &muted, NULL);
+ m_player->muteChanged(static_cast<bool>(muted));
+}
+
+void MediaPlayerPrivateGStreamer::muteChanged()
+{
+ if (m_muteTimerHandler)
+ g_source_remove(m_muteTimerHandler);
+ m_muteTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateMuteChangeTimeoutCallback), this);
+}
+
+void MediaPlayerPrivateGStreamer::loadingFailed(MediaPlayer::NetworkState error)
+{
+ m_errorOccured = true;
+ if (m_networkState != error) {
+ m_networkState = error;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+ }
+}
+
+void MediaPlayerPrivateGStreamer::setSize(const IntSize& size)
+{
+ m_size = size;
+}
+
+void MediaPlayerPrivateGStreamer::setVisible(bool visible)
+{
+}
+
+void MediaPlayerPrivateGStreamer::repaint()
+{
+ m_player->repaint();
+}
+
+void MediaPlayerPrivateGStreamer::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (context->paintingDisabled())
+ return;
+
+ if (!m_player->visible())
+ return;
+ if (!m_buffer)
+ return;
+
+ RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_buffer);
+ if (!gstImage)
+ return;
+
+ context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), ColorSpaceSRGB,
+ rect, CompositeCopy, false);
+}
+
+static HashSet<String> mimeTypeCache()
+{
+
+ doGstInit();
+
+ DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ // Build a whitelist of mime-types known to be supported by
+ // GStreamer.
+ HashSet<String> handledApplicationSubtypes;
+ handledApplicationSubtypes.add(String("ogg"));
+ handledApplicationSubtypes.add(String("vnd.rn-realmedia"));
+ handledApplicationSubtypes.add(String("x-pn-realaudio"));
+
+ GList* factories = gst_type_find_factory_get_list();
+ for (GList* iterator = factories; iterator; iterator = iterator->next) {
+ GstTypeFindFactory* factory = GST_TYPE_FIND_FACTORY(iterator->data);
+ GstCaps* caps = gst_type_find_factory_get_caps(factory);
+ gchar** extensions;
+
+ if (!caps)
+ continue;
+
+ for (guint structureIndex = 0; structureIndex < gst_caps_get_size(caps); structureIndex++) {
+ GstStructure* structure = gst_caps_get_structure(caps, structureIndex);
+ const gchar* name = gst_structure_get_name(structure);
+ bool cached = false;
+
+ // These formats are supported by GStreamer, but not
+ // correctly advertised.
+ if (g_str_equal(name, "video/x-h264")
+ || g_str_equal(name, "audio/x-m4a")) {
+ cache.add(String("video/mp4"));
+ cache.add(String("audio/aac"));
+ cache.add(String("audio/mp4"));
+ cached = true;
+ }
+
+ if (g_str_equal(name, "application/x-3gp")) {
+ cache.add(String("audio/3gpp"));
+ cache.add(String("video/3gpp"));
+ cache.add(String("application/x-3gp"));
+ cached = true;
+ }
+
+ if (g_str_equal(name, "video/x-theora")) {
+ cache.add(String("video/ogg"));
+ cached = true;
+ }
+
+ if (g_str_equal(name, "audio/x-vorbis")) {
+ cache.add(String("audio/ogg"));
+ cache.add(String("audio/x-vorbis+ogg"));
+ cached = true;
+ }
+
+ if (g_str_equal(name, "audio/x-wav")) {
+ cache.add(String("audio/wav"));
+ cache.add(String("audio/x-wav"));
+ cached = true;
+ }
+
+ if (g_str_equal(name, "audio/mpeg")) {
+ cache.add(String(name));
+ cache.add(String("audio/x-mpeg"));
+ cached = true;
+
+ // This is what we are handling:
+ // mpegversion=(int)1, layer=(int)[ 1, 3 ]
+ gint mpegVersion = 0;
+ if (gst_structure_get_int(structure, "mpegversion", &mpegVersion) && (mpegVersion == 1)) {
+ const GValue* layer = gst_structure_get_value(structure, "layer");
+ if (G_VALUE_TYPE(layer) == GST_TYPE_INT_RANGE) {
+ gint minLayer = gst_value_get_int_range_min(layer);
+ gint maxLayer = gst_value_get_int_range_max(layer);
+ if (minLayer <= 1 && 1 <= maxLayer)
+ cache.add(String("audio/mp1"));
+ if (minLayer <= 2 && 2 <= maxLayer)
+ cache.add(String("audio/mp2"));
+ if (minLayer <= 3 && 3 <= maxLayer) {
+ cache.add(String("audio/x-mp3"));
+ cache.add(String("audio/mp3"));
+ }
+ }
+ }
+ }
+
+ if (!cached) {
+ // GStreamer plugins can be capable of supporting
+ // types which WebKit supports by default. In that
+ // case, we should not consider these types
+ // supportable by GStreamer. Examples of what
+ // GStreamer can support but should not be added:
+ // text/plain, text/html, image/jpeg,
+ // application/xml
+ gchar** mimetype = g_strsplit(name, "/", 2);
+ if (g_str_equal(mimetype[0], "audio")
+ || g_str_equal(mimetype[0], "video")
+ || (g_str_equal(mimetype[0], "application")
+ && handledApplicationSubtypes.contains(String(mimetype[1]))))
+ cache.add(String(name));
+
+ g_strfreev(mimetype);
+ }
+
+ // As a last resort try some special cases depending
+ // on the file extensions registered with the typefind
+ // factory.
+ if (!cached && (extensions = gst_type_find_factory_get_extensions(factory))) {
+ for (int index = 0; extensions[index]; index++) {
+ if (g_str_equal(extensions[index], "m4v"))
+ cache.add(String("video/x-m4v"));
+ }
+ }
+ }
+ }
+
+ gst_plugin_feature_list_free(factories);
+ typeListInitialized = true;
+ }
+
+ return cache;
+}
+
+void MediaPlayerPrivateGStreamer::getSupportedTypes(HashSet<String>& types)
+{
+ types = mimeTypeCache();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivateGStreamer::supportsType(const String& type, const String& codecs)
+{
+ if (type.isNull() || type.isEmpty())
+ return MediaPlayer::IsNotSupported;
+
+ // spec says we should not return "probably" if the codecs string is empty
+ if (mimeTypeCache().contains(type))
+ return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
+ return MediaPlayer::IsNotSupported;
+}
+
+bool MediaPlayerPrivateGStreamer::hasSingleSecurityOrigin() const
+{
+ return true;
+}
+
+bool MediaPlayerPrivateGStreamer::supportsFullscreen() const
+{
+#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
+ // See <rdar://problem/7389945>
+ return false;
+#else
+ return true;
+#endif
+}
+
+PlatformMedia MediaPlayerPrivateGStreamer::platformMedia() const
+{
+ PlatformMedia p;
+ p.type = PlatformMedia::GStreamerGWorldType;
+ p.media.gstreamerGWorld = m_gstGWorld.get();
+ return p;
+}
+
+void MediaPlayerPrivateGStreamer::setPreload(MediaPlayer::Preload preload)
+{
+ ASSERT(m_playBin);
+
+ m_preload = preload;
+
+ GstPlayFlags flags;
+ g_object_get(m_playBin, "flags", &flags, NULL);
+ if (preload == MediaPlayer::None)
+ g_object_set(m_playBin, "flags", flags & ~GST_PLAY_FLAG_DOWNLOAD, NULL);
+ else
+ g_object_set(m_playBin, "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL);
+
+ if (m_delayingLoad && m_preload != MediaPlayer::None) {
+ m_delayingLoad = false;
+ commitLoad();
+ }
+}
+
+void MediaPlayerPrivateGStreamer::createGSTPlayBin()
+{
+ ASSERT(!m_playBin);
+ m_playBin = gst_element_factory_make("playbin2", "play");
+
+ m_gstGWorld = GStreamerGWorld::createGWorld(m_playBin);
+
+ GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
+ gst_bus_add_signal_watch(bus);
+ g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
+ gst_object_unref(bus);
+
+ g_object_set(m_playBin, "mute", m_player->muted(), "volume", m_player->volume(), NULL);
+
+ g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
+ g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
+ g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
+ g_signal_connect(m_playBin, "video-tags-changed", G_CALLBACK(mediaPlayerPrivateVideoTagsChangedCallback), this);
+ g_signal_connect(m_playBin, "audio-tags-changed", G_CALLBACK(mediaPlayerPrivateAudioTagsChangedCallback), this);
+
+ m_webkitVideoSink = webkit_video_sink_new();
+
+ g_signal_connect(m_webkitVideoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
+
+ m_videoSinkBin = gst_bin_new("sink");
+ GstElement* videoTee = gst_element_factory_make("tee", "videoTee");
+ GstElement* queue = gst_element_factory_make("queue", 0);
+ GstElement* identity = gst_element_factory_make("identity", "videoValve");
+
+ // Take ownership.
+ gst_object_ref_sink(m_videoSinkBin);
+
+ // Build a new video sink consisting of a bin containing a tee
+ // (meant to distribute data to multiple video sinks) and our
+ // internal video sink. For fullscreen we create an autovideosink
+ // and initially block the data flow towards it and configure it
+
+ gst_bin_add_many(GST_BIN(m_videoSinkBin), videoTee, queue, identity, NULL);
+
+ // Link a new src pad from tee to queue1.
+ GstPad* srcPad = gst_element_get_request_pad(videoTee, "src%d");
+ GstPad* sinkPad = gst_element_get_static_pad(queue, "sink");
+ gst_pad_link(srcPad, sinkPad);
+ gst_object_unref(GST_OBJECT(srcPad));
+ gst_object_unref(GST_OBJECT(sinkPad));
+
+ WTFLogChannel* channel = getChannelFromName("Media");
+ if (channel->state == WTFLogChannelOn) {
+ m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink");
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) {
+ g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink, NULL);
+ gst_bin_add(GST_BIN(m_videoSinkBin), m_fpsSink);
+#if GST_CHECK_VERSION(0, 10, 30)
+ // Faster elements linking, if possible.
+ gst_element_link_pads_full(queue, "src", m_fpsSink, "sink", GST_PAD_LINK_CHECK_NOTHING);
+#else
+ gst_element_link(queue, m_fpsSink);
+#endif
+ } else {
+ m_fpsSink = 0;
+ gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink);
+#if GST_CHECK_VERSION(0, 10, 30)
+ // Faster elements linking, if possible.
+ gst_element_link_pads_full(queue, "src", m_webkitVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING);
+#else
+ gst_element_link(queue, m_webkitVideoSink);
+#endif
+ LOG_VERBOSE(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18");
+ }
+ } else {
+ gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink);
+#if GST_CHECK_VERSION(0, 10, 30)
+ // Faster elements linking, if possible.
+ gst_element_link_pads_full(queue, "src", identity, "sink", GST_PAD_LINK_CHECK_NOTHING);
+ gst_element_link_pads_full(identity, "src", m_webkitVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING);
+#else
+ gst_element_link_many(queue, identity, m_webkitVideoSink, NULL);
+#endif
+ }
+
+ // Add a ghostpad to the bin so it can proxy to tee.
+ GstPad* pad = gst_element_get_static_pad(videoTee, "sink");
+ gst_element_add_pad(m_videoSinkBin, gst_ghost_pad_new("sink", pad));
+ gst_object_unref(GST_OBJECT(pad));
+
+ // Set the bin as video sink of playbin.
+ g_object_set(m_playBin, "video-sink", m_videoSinkBin, NULL);
+}
+
+}
+
+#endif // USE(GSTREAMER)
diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h
new file mode 100644
index 0000000..11eb81b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009, 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * aint with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef MediaPlayerPrivateGStreamer_h
+#define MediaPlayerPrivateGStreamer_h
+#if USE(GSTREAMER)
+
+#include <wtf/Forward.h>
+#include "MediaPlayerPrivate.h"
+#include "Timer.h"
+
+#include <glib.h>
+#include <gst/gst.h>
+
+typedef struct _WebKitVideoSink WebKitVideoSink;
+typedef struct _GstBuffer GstBuffer;
+typedef struct _GstMessage GstMessage;
+typedef struct _GstElement GstElement;
+typedef struct _GstBus GstBus;
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntSize;
+class IntRect;
+class GStreamerGWorld;
+class MediaPlayerPrivateGStreamer;
+
+gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
+void mediaPlayerPrivateVolumeChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
+void mediaPlayerPrivateMuteChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
+void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
+void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*);
+void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*);
+gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player);
+gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player);
+
+gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer*);
+gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer*);
+
+class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface {
+ friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
+ friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer* buffer, MediaPlayerPrivateGStreamer* playerPrivate);
+ friend void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
+
+ public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+
+ IntSize naturalSize() const;
+ bool hasVideo() const { return m_hasVideo; }
+ bool hasAudio() const { return m_hasAudio; }
+
+ void load(const String &url);
+ void commitLoad();
+ void cancelLoad();
+ bool loadNextLocation();
+
+ void prepareToPlay();
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float);
+
+ void setRate(float);
+
+ void setVolume(float);
+ void volumeChanged();
+ void notifyPlayerOfVolumeChange();
+
+ bool supportsMuting() const;
+ void setMuted(bool);
+ void muteChanged();
+ void notifyPlayerOfMute();
+
+ bool loadDelayed() const { return m_delayingLoad; }
+ void setPreload(MediaPlayer::Preload);
+ void fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*);
+
+ MediaPlayer::NetworkState networkState() const;
+ MediaPlayer::ReadyState readyState() const;
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setSize(const IntSize&);
+
+ void mediaLocationChanged(GstMessage*);
+ void loadStateChanged();
+ void sizeChanged();
+ void timeChanged();
+ void didEnd();
+ void durationChanged();
+ void loadingFailed(MediaPlayer::NetworkState);
+
+ void repaint();
+ void paint(GraphicsContext*, const IntRect&);
+
+ bool hasSingleSecurityOrigin() const;
+
+ bool supportsFullscreen() const;
+ PlatformMedia platformMedia() const;
+
+ GstElement* pipeline() const { return m_playBin; }
+ bool pipelineReset() const { return m_resetPipeline; }
+
+ void videoTagsChanged(gint);
+ void audioTagsChanged(gint);
+ void notifyPlayerOfVideoTags();
+ void notifyPlayerOfAudioTags();
+
+ private:
+ MediaPlayerPrivateGStreamer(MediaPlayer*);
+ ~MediaPlayerPrivateGStreamer();
+
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
+ void cacheDuration();
+ void updateStates();
+ float maxTimeLoaded() const;
+
+ void createGSTPlayBin();
+ bool changePipelineState(GstState state);
+
+ void processBufferingStats(GstMessage* message);
+
+ private:
+ MediaPlayer* m_player;
+ GstElement* m_playBin;
+ GstElement* m_webkitVideoSink;
+ GstElement* m_videoSinkBin;
+ GstElement* m_fpsSink;
+ GstElement* m_source;
+ GstClockTime m_seekTime;
+ bool m_changingRate;
+ float m_endTime;
+ bool m_isEndReached;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ mutable bool m_isStreaming;
+ IntSize m_size;
+ GstBuffer* m_buffer;
+ GstStructure* m_mediaLocations;
+ int m_mediaLocationCurrentIndex;
+ bool m_resetPipeline;
+ bool m_paused;
+ bool m_seeking;
+ bool m_buffering;
+ float m_playbackRate;
+ bool m_errorOccured;
+ gfloat m_mediaDuration;
+ bool m_startedBuffering;
+ Timer<MediaPlayerPrivateGStreamer> m_fillTimer;
+ float m_maxTimeLoaded;
+ int m_bufferingPercentage;
+ MediaPlayer::Preload m_preload;
+ bool m_delayingLoad;
+ bool m_mediaDurationKnown;
+ RefPtr<GStreamerGWorld> m_gstGWorld;
+ guint m_volumeTimerHandler;
+ guint m_muteTimerHandler;
+ bool m_hasVideo;
+ bool m_hasAudio;
+ guint m_audioTagsTimerHandler;
+ guint m_videoTagsTimerHandler;
+ };
+}
+
+#endif // USE(GSTREAMER)
+#endif
diff --git a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h
new file mode 100644
index 0000000..f2a3ff2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PlatformVideoWindow_h
+#define PlatformVideoWindow_h
+#if USE(GSTREAMER)
+
+#include "Widget.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+typedef struct _GstMessage GstMessage;
+
+namespace WebCore {
+
+class PlatformVideoWindow : public RefCounted<PlatformVideoWindow> {
+ public:
+ static PassRefPtr<PlatformVideoWindow> createWindow() { return adoptRef(new PlatformVideoWindow()); }
+
+ PlatformVideoWindow();
+ ~PlatformVideoWindow();
+
+
+ void prepareForOverlay(GstMessage*);
+ PlatformWidget window() const { return m_window; }
+ unsigned long videoWindowId() const { return m_videoWindowId; }
+
+ private:
+ unsigned long m_videoWindowId;
+ PlatformWidget m_videoWindow;
+ PlatformWidget m_window;
+ };
+}
+
+#endif // USE(GSTREAMER)
+#endif
diff --git a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp
new file mode 100644
index 0000000..0097716
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "PlatformVideoWindow.h"
+#if USE(GSTREAMER)
+
+#include "NotImplemented.h"
+
+using namespace WebCore;
+
+PlatformVideoWindow::PlatformVideoWindow()
+{
+ notImplemented();
+}
+
+PlatformVideoWindow::~PlatformVideoWindow()
+{
+ notImplemented();
+}
+
+void PlatformVideoWindow::prepareForOverlay(GstMessage*)
+{
+}
+
+#endif // USE(GSTREAMER)
diff --git a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp
new file mode 100644
index 0000000..c2f76cd
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "PlatformVideoWindow.h"
+#if USE(GSTREAMER)
+
+#include <gtk/gtk.h>
+
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h> // for GDK_WINDOW_XID
+#endif
+
+using namespace WebCore;
+
+PlatformVideoWindow::PlatformVideoWindow()
+{
+ m_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_events(m_window, GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK | GDK_FOCUS_CHANGE_MASK);
+
+ m_videoWindow = gtk_drawing_area_new();
+ gtk_widget_set_double_buffered(m_videoWindow, FALSE);
+ gtk_container_add(GTK_CONTAINER(m_window), m_videoWindow);
+
+ gtk_widget_realize(m_window);
+
+#ifdef GDK_WINDOWING_X11
+ m_videoWindowId = GDK_WINDOW_XID(gtk_widget_get_window(m_window));
+#endif
+
+}
+
+PlatformVideoWindow::~PlatformVideoWindow()
+{
+ if (m_videoWindow && m_window) {
+ gtk_container_remove(GTK_CONTAINER(m_window), m_videoWindow);
+ gtk_widget_destroy(m_videoWindow);
+ m_videoWindow = 0;
+ }
+
+ if (m_window) {
+ gtk_widget_destroy(m_window);
+ m_window = 0;
+ }
+
+ m_videoWindowId = 0;
+}
+
+void PlatformVideoWindow::prepareForOverlay(GstMessage*)
+{
+}
+#endif // USE(GSTREAMER)
+
diff --git a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h
new file mode 100644
index 0000000..0ae4587
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h
@@ -0,0 +1,44 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PlatformVideoWindowPrivate_h
+#define PlatformVideoWindowPrivate_h
+
+#include <QWidget>
+
+class QKeyEvent;
+
+namespace WebCore {
+
+class FullScreenVideoWindow: public QWidget {
+Q_OBJECT
+public:
+ FullScreenVideoWindow();
+signals:
+ void closed();
+protected:
+ void keyPressEvent(QKeyEvent* ev);
+ bool event(QEvent* ev);
+};
+
+
+} // namespace WebCore
+
+
+#endif // PlatformVideoWindowPrivate_h
diff --git a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp
new file mode 100644
index 0000000..872d055
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp
@@ -0,0 +1,82 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "PlatformVideoWindow.h"
+
+#include "PlatformVideoWindowPrivate.h"
+
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QKeyEvent>
+#include <QPalette>
+using namespace WebCore;
+
+FullScreenVideoWindow::FullScreenVideoWindow()
+ : QWidget(0, Qt::Window)
+{
+ setAttribute(Qt::WA_NativeWindow);
+ // Setting these values ensures smooth resizing since it
+ // will prevent the system from clearing the background.
+ setAttribute(Qt::WA_NoSystemBackground, true);
+ setAttribute(Qt::WA_PaintOnScreen, true);
+}
+
+void FullScreenVideoWindow::keyPressEvent(QKeyEvent* ev)
+{
+ if (ev->key() == Qt::Key_Escape) {
+ close();
+ emit closed();
+ }
+}
+
+bool FullScreenVideoWindow::event(QEvent* ev)
+{
+ switch (ev->type()) {
+ case QEvent::MouseButtonDblClick:
+ close();
+ ev->accept();
+ return true;
+ default:
+ return QWidget::event(ev);
+ }
+}
+
+
+PlatformVideoWindow::PlatformVideoWindow()
+{
+ m_window = new FullScreenVideoWindow();
+ m_window->setWindowFlags(m_window->windowFlags() | Qt::FramelessWindowHint);
+ QPalette p;
+ p.setColor(QPalette::Base, Qt::black);
+ p.setColor(QPalette::Window, Qt::black);
+ m_window->setPalette(p);
+ m_window->showFullScreen();
+ m_videoWindowId = m_window->winId();
+}
+
+PlatformVideoWindow::~PlatformVideoWindow()
+{
+ delete m_window;
+ m_videoWindowId = 0;
+}
+
+void PlatformVideoWindow::prepareForOverlay(GstMessage*)
+{
+}
diff --git a/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp
new file mode 100644
index 0000000..4319f6c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2007 OpenedHand
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:webkit-video-sink
+ * @short_description: GStreamer video sink
+ *
+ * #WebKitVideoSink is a GStreamer sink element that triggers
+ * repaints in the WebKit GStreamer media player for the
+ * current video buffer.
+ */
+
+#include "config.h"
+#include "VideoSinkGStreamer.h"
+#if USE(GSTREAMER)
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink",
+ GST_PAD_SINK, GST_PAD_ALWAYS,
+// CAIRO_FORMAT_RGB24 used to render the video buffers is little/big endian dependant.
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ GST_STATIC_CAPS(GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_BGRA)
+#else
+ GST_STATIC_CAPS(GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_ARGB)
+#endif
+);
+
+GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug);
+#define GST_CAT_DEFAULT webkit_video_sink_debug
+
+enum {
+ REPAINT_REQUESTED,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0
+};
+
+static guint webkit_video_sink_signals[LAST_SIGNAL] = { 0, };
+
+struct _WebKitVideoSinkPrivate {
+ GstBuffer* buffer;
+ guint timeout_id;
+ GMutex* buffer_mutex;
+ GCond* data_cond;
+
+ // If this is TRUE all processing should finish ASAP
+ // This is necessary because there could be a race between
+ // unlock() and render(), where unlock() wins, signals the
+ // GCond, then render() tries to render a frame although
+ // everything else isn't running anymore. This will lead
+ // to deadlocks because render() holds the stream lock.
+ //
+ // Protected by the buffer mutex
+ gboolean unlocked;
+};
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT(webkit_video_sink_debug, \
+ "webkitsink", \
+ 0, \
+ "webkit video sink")
+
+GST_BOILERPLATE_FULL(WebKitVideoSink,
+ webkit_video_sink,
+ GstVideoSink,
+ GST_TYPE_VIDEO_SINK,
+ _do_init);
+
+static void
+webkit_video_sink_base_init(gpointer g_class)
+{
+ GstElementClass* element_class = GST_ELEMENT_CLASS(g_class);
+
+ gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sinktemplate));
+ gst_element_class_set_details_simple(element_class, "WebKit video sink",
+ "Sink/Video", "Sends video data from a GStreamer pipeline to a Cairo surface",
+ "Alp Toker <alp@atoker.com>");
+}
+
+static void
+webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass)
+{
+ WebKitVideoSinkPrivate* priv;
+
+ sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
+ priv->data_cond = g_cond_new();
+ priv->buffer_mutex = g_mutex_new();
+}
+
+static gboolean
+webkit_video_sink_timeout_func(gpointer data)
+{
+ WebKitVideoSink* sink = reinterpret_cast<WebKitVideoSink*>(data);
+ WebKitVideoSinkPrivate* priv = sink->priv;
+ GstBuffer* buffer;
+
+ g_mutex_lock(priv->buffer_mutex);
+ buffer = priv->buffer;
+ priv->buffer = 0;
+ priv->timeout_id = 0;
+
+ if (!buffer || priv->unlocked || G_UNLIKELY(!GST_IS_BUFFER(buffer))) {
+ g_cond_signal(priv->data_cond);
+ g_mutex_unlock(priv->buffer_mutex);
+ return FALSE;
+ }
+
+ g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0, buffer);
+ gst_buffer_unref(buffer);
+ g_cond_signal(priv->data_cond);
+ g_mutex_unlock(priv->buffer_mutex);
+
+ return FALSE;
+}
+
+static GstFlowReturn
+webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
+{
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink);
+ WebKitVideoSinkPrivate* priv = sink->priv;
+
+ g_mutex_lock(priv->buffer_mutex);
+
+ if (priv->unlocked) {
+ g_mutex_unlock(priv->buffer_mutex);
+ return GST_FLOW_OK;
+ }
+
+ priv->buffer = gst_buffer_ref(buffer);
+
+ // For the unlikely case where the buffer has no caps, the caps
+ // are implicitely the caps of the pad. This shouldn't happen.
+ if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) {
+ buffer = priv->buffer = gst_buffer_make_metadata_writable(priv->buffer);
+ gst_buffer_set_caps(priv->buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(bsink)));
+ }
+
+ GstCaps *caps = GST_BUFFER_CAPS(buffer);
+ GstVideoFormat format;
+ int width, height;
+ if (G_UNLIKELY(!gst_video_format_parse_caps(caps, &format, &width, &height))) {
+ gst_buffer_unref(buffer);
+ g_mutex_unlock(priv->buffer_mutex);
+ return GST_FLOW_ERROR;
+ }
+
+ // Cairo's ARGB has pre-multiplied alpha while GStreamer's doesn't.
+ // Here we convert to Cairo's ARGB.
+ if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) {
+ // Because GstBaseSink::render() only owns the buffer reference in the
+ // method scope we can't use gst_buffer_make_writable() here. Also
+ // The buffer content should not be changed here because the same buffer
+ // could be passed multiple times to this method (in theory)
+ GstBuffer *newBuffer = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(buffer));
+
+ // Check if allocation failed
+ if (G_UNLIKELY(!newBuffer)) {
+ gst_buffer_unref(buffer);
+ g_mutex_unlock(priv->buffer_mutex);
+ return GST_FLOW_ERROR;
+ }
+
+ gst_buffer_copy_metadata(newBuffer, buffer, (GstBufferCopyFlags) GST_BUFFER_COPY_ALL);
+
+ // We don't use Color::premultipliedARGBFromColor() here because
+ // one function call per video pixel is just too expensive:
+ // For 720p/PAL for example this means 1280*720*25=23040000
+ // function calls per second!
+ unsigned short alpha;
+ const guint8 *source = GST_BUFFER_DATA(buffer);
+ guint8 *destination = GST_BUFFER_DATA(newBuffer);
+
+ for (int x = 0; x < height; x++) {
+ for (int y = 0; y < width; y++) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ alpha = source[3];
+ destination[0] = (source[0] * alpha + 128) / 255;
+ destination[1] = (source[1] * alpha + 128) / 255;
+ destination[2] = (source[2] * alpha + 128) / 255;
+ destination[3] = alpha;
+#else
+ alpha = source[0];
+ destination[0] = alpha;
+ destination[1] = (source[1] * alpha + 128) / 255;
+ destination[2] = (source[2] * alpha + 128) / 255;
+ destination[3] = (source[3] * alpha + 128) / 255;
+#endif
+ source += 4;
+ destination += 4;
+ }
+ }
+ gst_buffer_unref(buffer);
+ buffer = priv->buffer = newBuffer;
+ }
+
+ // This should likely use a lower priority, but glib currently starves
+ // lower priority sources.
+ // See: https://bugzilla.gnome.org/show_bug.cgi?id=610830.
+ priv->timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT, 0,
+ webkit_video_sink_timeout_func,
+ gst_object_ref(sink),
+ (GDestroyNotify)gst_object_unref);
+
+ g_cond_wait(priv->data_cond, priv->buffer_mutex);
+ g_mutex_unlock(priv->buffer_mutex);
+ return GST_FLOW_OK;
+}
+
+static void
+webkit_video_sink_dispose(GObject* object)
+{
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
+ WebKitVideoSinkPrivate* priv = sink->priv;
+
+ if (priv->data_cond) {
+ g_cond_free(priv->data_cond);
+ priv->data_cond = 0;
+ }
+
+ if (priv->buffer_mutex) {
+ g_mutex_free(priv->buffer_mutex);
+ priv->buffer_mutex = 0;
+ }
+
+ G_OBJECT_CLASS(parent_class)->dispose(object);
+}
+
+static void
+unlock_buffer_mutex(WebKitVideoSinkPrivate* priv)
+{
+ g_mutex_lock(priv->buffer_mutex);
+
+ if (priv->buffer) {
+ gst_buffer_unref(priv->buffer);
+ priv->buffer = 0;
+ }
+
+ priv->unlocked = TRUE;
+
+ g_cond_signal(priv->data_cond);
+ g_mutex_unlock(priv->buffer_mutex);
+}
+
+static gboolean
+webkit_video_sink_unlock(GstBaseSink* object)
+{
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
+
+ unlock_buffer_mutex(sink->priv);
+
+ return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock,
+ (object), TRUE);
+}
+
+static gboolean
+webkit_video_sink_unlock_stop(GstBaseSink* object)
+{
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
+ WebKitVideoSinkPrivate* priv = sink->priv;
+
+ g_mutex_lock(priv->buffer_mutex);
+ priv->unlocked = FALSE;
+ g_mutex_unlock(priv->buffer_mutex);
+
+ return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock_stop,
+ (object), TRUE);
+}
+
+static gboolean
+webkit_video_sink_stop(GstBaseSink* base_sink)
+{
+ WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv;
+
+ unlock_buffer_mutex(priv);
+ return TRUE;
+}
+
+static gboolean
+webkit_video_sink_start(GstBaseSink* base_sink)
+{
+ WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv;
+
+ g_mutex_lock(priv->buffer_mutex);
+ priv->unlocked = FALSE;
+ g_mutex_unlock(priv->buffer_mutex);
+ return TRUE;
+}
+
+static void
+marshal_VOID__MINIOBJECT(GClosure * closure, GValue * return_value,
+ guint n_param_values, const GValue * param_values,
+ gpointer invocation_hint, gpointer marshal_data)
+{
+ typedef void (*marshalfunc_VOID__MINIOBJECT) (gpointer obj, gpointer arg1, gpointer data2);
+ marshalfunc_VOID__MINIOBJECT callback;
+ GCClosure *cc = (GCClosure *) closure;
+ gpointer data1, data2;
+
+ g_return_if_fail(n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA(closure)) {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer(param_values + 0);
+ } else {
+ data1 = g_value_peek_pointer(param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (marshalfunc_VOID__MINIOBJECT) (marshal_data ? marshal_data : cc->callback);
+
+ callback(data1, gst_value_get_mini_object(param_values + 1), data2);
+}
+
+static void
+webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
+{
+ GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
+ GstBaseSinkClass* gstbase_sink_class = GST_BASE_SINK_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate));
+
+ gobject_class->dispose = webkit_video_sink_dispose;
+
+ gstbase_sink_class->unlock = webkit_video_sink_unlock;
+ gstbase_sink_class->unlock_stop = webkit_video_sink_unlock_stop;
+ gstbase_sink_class->render = webkit_video_sink_render;
+ gstbase_sink_class->preroll = webkit_video_sink_render;
+ gstbase_sink_class->stop = webkit_video_sink_stop;
+ gstbase_sink_class->start = webkit_video_sink_start;
+
+ webkit_video_sink_signals[REPAINT_REQUESTED] = g_signal_new("repaint-requested",
+ G_TYPE_FROM_CLASS(klass),
+ (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+ 0,
+ 0,
+ 0,
+ marshal_VOID__MINIOBJECT,
+ G_TYPE_NONE, 1, GST_TYPE_BUFFER);
+}
+
+/**
+ * webkit_video_sink_new:
+ *
+ * Creates a new GStreamer video sink.
+ *
+ * Return value: a #GstElement for the newly created video sink
+ */
+GstElement*
+webkit_video_sink_new(void)
+{
+ return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, 0);
+}
+
+#endif // USE(GSTREAMER)
diff --git a/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h
new file mode 100644
index 0000000..6cd86c2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2007 OpenedHand
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef VideoSinkGStreamer_h
+#define VideoSinkGStreamer_h
+
+#if USE(GSTREAMER)
+
+#include <glib-object.h>
+#include <gst/video/gstvideosink.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_VIDEO_SINK webkit_video_sink_get_type()
+
+#define WEBKIT_VIDEO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSink))
+
+#define WEBKIT_VIDEO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass))
+
+#define WEBKIT_IS_VIDEO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ WEBKIT_TYPE_VIDEO_SINK))
+
+#define WEBKIT_IS_VIDEO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ WEBKIT_TYPE_VIDEO_SINK))
+
+#define WEBKIT_VIDEO_SINK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass))
+
+typedef struct _WebKitVideoSink WebKitVideoSink;
+typedef struct _WebKitVideoSinkClass WebKitVideoSinkClass;
+typedef struct _WebKitVideoSinkPrivate WebKitVideoSinkPrivate;
+
+struct _WebKitVideoSink {
+ /*< private >*/
+ GstVideoSink parent;
+ WebKitVideoSinkPrivate *priv;
+};
+
+struct _WebKitVideoSinkClass {
+ /*< private >*/
+ GstVideoSinkClass parent_class;
+
+ /* Future padding */
+ void (* _webkit_reserved1)(void);
+ void (* _webkit_reserved2)(void);
+ void (* _webkit_reserved3)(void);
+ void (* _webkit_reserved4)(void);
+ void (* _webkit_reserved5)(void);
+ void (* _webkit_reserved6)(void);
+};
+
+GType webkit_video_sink_get_type(void) G_GNUC_CONST;
+GstElement *webkit_video_sink_new(void);
+
+G_END_DECLS
+
+#endif // USE(GSTREAMER)
+#endif
diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
new file mode 100644
index 0000000..e10e61f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
@@ -0,0 +1,820 @@
+/*
+ * Copyright (C) 2009, 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "WebKitWebSourceGStreamer.h"
+#if USE(GSTREAMER)
+
+#include "Document.h"
+#include "GOwnPtr.h"
+#include "GRefPtr.h"
+#include "NetworkingContext.h"
+#include "Noncopyable.h"
+#include "NotImplemented.h"
+#include "ResourceHandleClient.h"
+#include "ResourceHandleInternal.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include <wtf/text/CString.h>
+#include <gst/app/gstappsrc.h>
+#include <gst/pbutils/missing-plugins.h>
+
+using namespace WebCore;
+
+class StreamingClient : public Noncopyable, public ResourceHandleClient {
+ public:
+ StreamingClient(WebKitWebSrc*);
+ virtual ~StreamingClient();
+
+ virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&);
+ virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
+ virtual void didReceiveData(ResourceHandle*, const char*, int, int);
+ virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
+ virtual void didFail(ResourceHandle*, const ResourceError&);
+ virtual void wasBlocked(ResourceHandle*);
+ virtual void cannotShowURL(ResourceHandle*);
+
+ private:
+ WebKitWebSrc* m_src;
+};
+
+#define WEBKIT_WEB_SRC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_WEB_SRC, WebKitWebSrcPrivate))
+struct _WebKitWebSrcPrivate {
+ GstAppSrc* appsrc;
+ GstPad* srcpad;
+ gchar* uri;
+
+ RefPtr<WebCore::Frame> frame;
+
+ StreamingClient* client;
+ RefPtr<ResourceHandle> resourceHandle;
+
+ guint64 offset;
+ guint64 size;
+ gboolean seekable;
+ gboolean paused;
+
+ guint64 requestedOffset;
+
+ guint needDataID;
+ guint enoughDataID;
+ guint seekID;
+
+ // icecast stuff
+ gboolean iradioMode;
+ gchar* iradioName;
+ gchar* iradioGenre;
+ gchar* iradioUrl;
+ gchar* iradioTitle;
+
+ // TRUE if appsrc's version is >= 0.10.27, see
+ // https://bugzilla.gnome.org/show_bug.cgi?id=609423
+ gboolean haveAppSrc27;
+};
+
+enum {
+ PROP_IRADIO_MODE = 1,
+ PROP_IRADIO_NAME,
+ PROP_IRADIO_GENRE,
+ PROP_IRADIO_URL,
+ PROP_IRADIO_TITLE
+};
+
+static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC(webkit_web_src_debug);
+#define GST_CAT_DEFAULT webkit_web_src_debug
+
+static void webKitWebSrcUriHandlerInit(gpointer gIface,
+ gpointer ifaceData);
+
+static void webKitWebSrcFinalize(GObject* object);
+static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec);
+static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* pspec);
+static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition);
+static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query);
+
+static void webKitWebSrcNeedDataCb(GstAppSrc* appsrc, guint length, gpointer userData);
+static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData);
+static gboolean webKitWebSrcSeekDataCb(GstAppSrc* appsrc, guint64 offset, gpointer userData);
+
+static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking);
+
+static GstAppSrcCallbacks appsrcCallbacks = {
+ webKitWebSrcNeedDataCb,
+ webKitWebSrcEnoughDataCb,
+ webKitWebSrcSeekDataCb,
+ { 0 }
+};
+
+static void doInit(GType gtype)
+{
+ static const GInterfaceInfo uriHandlerInfo = {
+ webKitWebSrcUriHandlerInit,
+ 0, 0
+ };
+
+ GST_DEBUG_CATEGORY_INIT(webkit_web_src_debug, "webkitwebsrc", 0, "websrc element");
+ g_type_add_interface_static(gtype, GST_TYPE_URI_HANDLER,
+ &uriHandlerInfo);
+}
+
+GST_BOILERPLATE_FULL(WebKitWebSrc, webkit_web_src, GstBin, GST_TYPE_BIN, doInit);
+
+static void webkit_web_src_base_init(gpointer klass)
+{
+ GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
+
+ gst_element_class_add_pad_template(eklass,
+ gst_static_pad_template_get(&srcTemplate));
+ gst_element_class_set_details_simple(eklass,
+ (gchar*) "WebKit Web source element",
+ (gchar*) "Source",
+ (gchar*) "Handles HTTP/HTTPS uris",
+ (gchar*) "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+}
+
+static void webkit_web_src_class_init(WebKitWebSrcClass* klass)
+{
+ GObjectClass* oklass = G_OBJECT_CLASS(klass);
+ GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
+
+ oklass->finalize = webKitWebSrcFinalize;
+ oklass->set_property = webKitWebSrcSetProperty;
+ oklass->get_property = webKitWebSrcGetProperty;
+
+ // icecast stuff
+ g_object_class_install_property(oklass,
+ PROP_IRADIO_MODE,
+ g_param_spec_boolean("iradio-mode",
+ "iradio-mode",
+ "Enable internet radio mode (extraction of shoutcast/icecast metadata)",
+ FALSE,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+ g_object_class_install_property(oklass,
+ PROP_IRADIO_NAME,
+ g_param_spec_string("iradio-name",
+ "iradio-name",
+ "Name of the stream",
+ 0,
+ (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+ g_object_class_install_property(oklass,
+ PROP_IRADIO_GENRE,
+ g_param_spec_string("iradio-genre",
+ "iradio-genre",
+ "Genre of the stream",
+ 0,
+ (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+ g_object_class_install_property(oklass,
+ PROP_IRADIO_URL,
+ g_param_spec_string("iradio-url",
+ "iradio-url",
+ "Homepage URL for radio stream",
+ 0,
+ (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+ g_object_class_install_property(oklass,
+ PROP_IRADIO_TITLE,
+ g_param_spec_string("iradio-title",
+ "iradio-title",
+ "Name of currently playing song",
+ 0,
+ (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+ eklass->change_state = webKitWebSrcChangeState;
+
+ g_type_class_add_private(klass, sizeof(WebKitWebSrcPrivate));
+}
+
+static void webkit_web_src_init(WebKitWebSrc* src,
+ WebKitWebSrcClass* gKlass)
+{
+ GstPadTemplate* padTemplate = gst_static_pad_template_get(&srcTemplate);
+ GstPad* targetpad;
+ WebKitWebSrcPrivate* priv = WEBKIT_WEB_SRC_GET_PRIVATE(src);
+
+ src->priv = priv;
+
+ priv->client = new StreamingClient(src);
+
+ priv->srcpad = gst_ghost_pad_new_no_target_from_template("src",
+ padTemplate);
+
+ gst_element_add_pad(GST_ELEMENT(src), priv->srcpad);
+ gst_pad_set_query_function(priv->srcpad, webKitWebSrcQuery);
+
+ priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", 0));
+ if (!priv->appsrc) {
+ GST_ERROR_OBJECT(src, "Failed to create appsrc");
+ return;
+ }
+
+ GstElementFactory* factory = GST_ELEMENT_FACTORY(GST_ELEMENT_GET_CLASS(priv->appsrc)->elementfactory);
+ priv->haveAppSrc27 = gst_plugin_feature_check_version(GST_PLUGIN_FEATURE(factory), 0, 10, 27);
+
+ gst_bin_add(GST_BIN(src), GST_ELEMENT(priv->appsrc));
+
+ targetpad = gst_element_get_static_pad(GST_ELEMENT(priv->appsrc), "src");
+ gst_ghost_pad_set_target(GST_GHOST_PAD(priv->srcpad), targetpad);
+ gst_object_unref(targetpad);
+
+ gst_app_src_set_callbacks(priv->appsrc, &appsrcCallbacks, src, 0);
+ gst_app_src_set_emit_signals(priv->appsrc, FALSE);
+ gst_app_src_set_stream_type(priv->appsrc, GST_APP_STREAM_TYPE_SEEKABLE);
+
+ // 512k is a abitrary number but we should choose a value
+ // here to not pause/unpause the SoupMessage too often and
+ // to make sure there's always some data available for
+ // GStreamer to handle.
+ gst_app_src_set_max_bytes(priv->appsrc, 512 * 1024);
+
+ // Emit the need-data signal if the queue contains less
+ // than 20% of data. Without this the need-data signal
+ // is emitted when the queue is empty, we then dispatch
+ // the soup message unpausing to the main loop and from
+ // there unpause the soup message. This already takes
+ // quite some time and libsoup even needs some more time
+ // to actually provide data again. If we do all this
+ // already if the queue is 20% empty, it's much more
+ // likely that libsoup already provides new data before
+ // the queue is really empty.
+ // This might need tweaking for ports not using libsoup.
+ if (priv->haveAppSrc27)
+ g_object_set(priv->appsrc, "min-percent", 20, NULL);
+
+ webKitWebSrcStop(src, false);
+}
+
+static void webKitWebSrcFinalize(GObject* object)
+{
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ delete priv->client;
+
+ g_free(priv->uri);
+
+ GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src)));
+}
+
+static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec)
+{
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ switch (propID) {
+ case PROP_IRADIO_MODE:
+ priv->iradioMode = g_value_get_boolean(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec);
+ break;
+ }
+}
+
+static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* pspec)
+{
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ switch (propID) {
+ case PROP_IRADIO_MODE:
+ g_value_set_boolean(value, priv->iradioMode);
+ break;
+ case PROP_IRADIO_NAME:
+ g_value_set_string(value, priv->iradioName);
+ break;
+ case PROP_IRADIO_GENRE:
+ g_value_set_string(value, priv->iradioGenre);
+ break;
+ case PROP_IRADIO_URL:
+ g_value_set_string(value, priv->iradioUrl);
+ break;
+ case PROP_IRADIO_TITLE:
+ g_value_set_string(value, priv->iradioTitle);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec);
+ break;
+ }
+}
+
+
+static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking)
+{
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ if (priv->resourceHandle) {
+ priv->resourceHandle->cancel();
+ priv->resourceHandle.release();
+ }
+ priv->resourceHandle = 0;
+
+ if (priv->frame)
+ priv->frame.release();
+
+ GST_OBJECT_LOCK(src);
+ if (priv->needDataID)
+ g_source_remove(priv->needDataID);
+ priv->needDataID = 0;
+
+ if (priv->enoughDataID)
+ g_source_remove(priv->enoughDataID);
+ priv->enoughDataID = 0;
+
+ if (priv->seekID)
+ g_source_remove(priv->seekID);
+ priv->seekID = 0;
+
+ priv->paused = FALSE;
+ GST_OBJECT_UNLOCK(src);
+
+ g_free(priv->iradioName);
+ priv->iradioName = 0;
+
+ g_free(priv->iradioGenre);
+ priv->iradioGenre = 0;
+
+ g_free(priv->iradioUrl);
+ priv->iradioUrl = 0;
+
+ g_free(priv->iradioTitle);
+ priv->iradioTitle = 0;
+
+ if (priv->appsrc) {
+ gst_app_src_set_caps(priv->appsrc, 0);
+ if (!seeking)
+ gst_app_src_set_size(priv->appsrc, -1);
+ }
+
+ priv->offset = 0;
+ priv->seekable = FALSE;
+
+ if (!seeking) {
+ priv->size = 0;
+ priv->requestedOffset = 0;
+ }
+
+ GST_DEBUG_OBJECT(src, "Stopped request");
+}
+
+static bool webKitWebSrcStart(WebKitWebSrc* src)
+{
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ if (!priv->uri) {
+ GST_ERROR_OBJECT(src, "No URI provided");
+ return false;
+ }
+
+ KURL url = KURL(KURL(), priv->uri);
+
+ ResourceRequest request(url);
+ request.setTargetType(ResourceRequestBase::TargetIsMedia);
+ request.setAllowCookies(true);
+
+ NetworkingContext* context = 0;
+ if (priv->frame) {
+ Document* document = priv->frame->document();
+ if (document)
+ request.setHTTPReferrer(document->documentURI());
+
+ FrameLoader* loader = priv->frame->loader();
+ if (loader) {
+ loader->addExtraFieldsToSubresourceRequest(request);
+ context = loader->networkingContext();
+ }
+ }
+
+ // Let Apple web servers know we want to access their nice movie trailers.
+ if (!g_ascii_strcasecmp("movies.apple.com", url.host().utf8().data())
+ || !g_ascii_strcasecmp("trailers.apple.com", url.host().utf8().data()))
+ request.setHTTPUserAgent("Quicktime/7.6.6");
+
+ if (priv->requestedOffset) {
+ GOwnPtr<gchar> val;
+
+ val.set(g_strdup_printf("bytes=%" G_GUINT64_FORMAT "-", priv->requestedOffset));
+ request.setHTTPHeaderField("Range", val.get());
+ }
+
+ if (priv->iradioMode)
+ request.setHTTPHeaderField("icy-metadata", "1");
+
+ // Needed to use DLNA streaming servers
+ request.setHTTPHeaderField("transferMode.dlna", "Streaming");
+
+ priv->resourceHandle = ResourceHandle::create(context, request, priv->client, false, false);
+ if (!priv->resourceHandle) {
+ GST_ERROR_OBJECT(src, "Failed to create ResourceHandle");
+ return false;
+ }
+
+ GST_DEBUG_OBJECT(src, "Started request");
+
+ return true;
+}
+
+static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(element);
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!priv->appsrc) {
+ gst_element_post_message(element,
+ gst_missing_element_message_new(element, "appsrc"));
+ GST_ELEMENT_ERROR(src, CORE, MISSING_PLUGIN, (0), ("no appsrc"));
+ return GST_STATE_CHANGE_FAILURE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
+ if (G_UNLIKELY(ret == GST_STATE_CHANGE_FAILURE)) {
+ GST_DEBUG_OBJECT(src, "State change failed");
+ return ret;
+ }
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ GST_DEBUG_OBJECT(src, "READY->PAUSED");
+ if (!webKitWebSrcStart(src))
+ ret = GST_STATE_CHANGE_FAILURE;
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ GST_DEBUG_OBJECT(src, "PAUSED->READY");
+ webKitWebSrcStop(src, false);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query)
+{
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(gst_pad_get_parent(pad));
+ gboolean result = FALSE;
+
+ switch (GST_QUERY_TYPE(query)) {
+ case GST_QUERY_DURATION:
+ {
+ GstFormat format;
+
+ gst_query_parse_duration(query, &format, NULL);
+
+ GST_DEBUG_OBJECT(src, "duration query in format %s", gst_format_get_name(format));
+ if ((format == GST_FORMAT_BYTES) && (src->priv->size > 0)) {
+ gst_query_set_duration(query, format, src->priv->size);
+ result = TRUE;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (!result)
+ result = gst_pad_query_default(pad, query);
+
+ gst_object_unref(src);
+ return result;
+}
+
+// uri handler interface
+
+static GstURIType webKitWebSrcUriGetType(void)
+{
+ return GST_URI_SRC;
+}
+
+static gchar** webKitWebSrcGetProtocols(void)
+{
+ static gchar* protocols[] = {(gchar*) "http", (gchar*) "https", 0 };
+
+ return protocols;
+}
+
+static const gchar* webKitWebSrcGetUri(GstURIHandler* handler)
+{
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(handler);
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ return priv->uri;
+}
+
+static gboolean webKitWebSrcSetUri(GstURIHandler* handler, const gchar* uri)
+{
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(handler);
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ if (GST_STATE(src) >= GST_STATE_PAUSED) {
+ GST_ERROR_OBJECT(src, "URI can only be set in states < PAUSED");
+ return FALSE;
+ }
+
+ g_free(priv->uri);
+ priv->uri = 0;
+
+ if (!uri)
+ return TRUE;
+
+ KURL url(KURL(), uri);
+
+ if (!url.isValid() || !url.protocolInHTTPFamily()) {
+ GST_ERROR_OBJECT(src, "Invalid URI '%s'", uri);
+ return FALSE;
+ }
+
+ priv->uri = g_strdup(url.string().utf8().data());
+ return TRUE;
+}
+
+static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer ifaceData)
+{
+ GstURIHandlerInterface* iface = (GstURIHandlerInterface *) gIface;
+
+ iface->get_type = webKitWebSrcUriGetType;
+ iface->get_protocols = webKitWebSrcGetProtocols;
+ iface->get_uri = webKitWebSrcGetUri;
+ iface->set_uri = webKitWebSrcSetUri;
+}
+
+// appsrc callbacks
+
+static gboolean webKitWebSrcNeedDataMainCb(WebKitWebSrc* src)
+{
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ priv->resourceHandle->setDefersLoading(false);
+
+ GST_OBJECT_LOCK(src);
+ priv->paused = FALSE;
+ priv->needDataID = 0;
+ GST_OBJECT_UNLOCK(src);
+ return FALSE;
+}
+
+static void webKitWebSrcNeedDataCb(GstAppSrc* appsrc, guint length, gpointer userData)
+{
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(userData);
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ GST_DEBUG_OBJECT(src, "Need more data: %u", length);
+
+ GST_OBJECT_LOCK(src);
+ if (priv->needDataID || !priv->paused) {
+ GST_OBJECT_UNLOCK(src);
+ return;
+ }
+
+ priv->needDataID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcNeedDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
+ GST_OBJECT_UNLOCK(src);
+}
+
+static gboolean webKitWebSrcEnoughDataMainCb(WebKitWebSrc* src)
+{
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ priv->resourceHandle->setDefersLoading(true);
+
+ GST_OBJECT_LOCK(src);
+ priv->paused = TRUE;
+ priv->enoughDataID = 0;
+ GST_OBJECT_UNLOCK(src);
+
+ return FALSE;
+}
+
+static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData)
+{
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(userData);
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ GST_DEBUG_OBJECT(src, "Have enough data");
+
+ GST_OBJECT_LOCK(src);
+ if (priv->enoughDataID || priv->paused) {
+ GST_OBJECT_UNLOCK(src);
+ return;
+ }
+
+ priv->enoughDataID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcEnoughDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
+ GST_OBJECT_UNLOCK(src);
+}
+
+static gboolean webKitWebSrcSeekMainCb(WebKitWebSrc* src)
+{
+ webKitWebSrcStop(src, true);
+ webKitWebSrcStart(src);
+
+ return FALSE;
+}
+
+static gboolean webKitWebSrcSeekDataCb(GstAppSrc* appsrc, guint64 offset, gpointer userData)
+{
+ WebKitWebSrc* src = WEBKIT_WEB_SRC(userData);
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ GST_DEBUG_OBJECT(src, "Seeking to offset: %" G_GUINT64_FORMAT, offset);
+ if (offset == priv->offset)
+ return TRUE;
+
+ if (!priv->seekable)
+ return FALSE;
+ if (offset > priv->size)
+ return FALSE;
+
+ GST_DEBUG_OBJECT(src, "Doing range-request seek");
+ priv->requestedOffset = offset;
+
+ GST_OBJECT_LOCK(src);
+ if (priv->seekID)
+ g_source_remove(priv->seekID);
+ priv->seekID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcSeekMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
+ GST_OBJECT_UNLOCK(src);
+
+ return TRUE;
+}
+
+void webKitWebSrcSetFrame(WebKitWebSrc* src, WebCore::Frame* frame)
+{
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ priv->frame = frame;
+}
+
+StreamingClient::StreamingClient(WebKitWebSrc* src) : m_src(src)
+{
+
+}
+
+StreamingClient::~StreamingClient()
+{
+
+}
+
+void StreamingClient::willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&)
+{
+}
+
+void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
+{
+ WebKitWebSrcPrivate* priv = m_src->priv;
+
+ GST_DEBUG_OBJECT(m_src, "Received response: %d", response.httpStatusCode());
+
+ // If we seeked we need 206 == PARTIAL_CONTENT
+ if (priv->requestedOffset && response.httpStatusCode() != 206) {
+ GST_ELEMENT_ERROR(m_src, RESOURCE, READ, (0), (0));
+ gst_app_src_end_of_stream(priv->appsrc);
+ webKitWebSrcStop(m_src, false);
+ return;
+ }
+
+ long long length = response.expectedContentLength();
+ if (length > 0) {
+ length += priv->requestedOffset;
+ gst_app_src_set_size(priv->appsrc, length);
+ if (!priv->haveAppSrc27) {
+ gst_segment_set_duration(&GST_BASE_SRC(priv->appsrc)->segment, GST_FORMAT_BYTES, length);
+ gst_element_post_message(GST_ELEMENT(priv->appsrc),
+ gst_message_new_duration(GST_OBJECT(priv->appsrc),
+ GST_FORMAT_BYTES, length));
+ }
+ }
+
+ priv->size = length >= 0 ? length : 0;
+ priv->seekable = length > 0 && g_ascii_strcasecmp("none", response.httpHeaderField("Accept-Ranges").utf8().data());
+
+ // icecast stuff
+ String value = response.httpHeaderField("icy-metaint");
+ if (!value.isEmpty()) {
+ gchar* endptr = 0;
+ gint64 icyMetaInt = g_ascii_strtoll(value.utf8().data(), &endptr, 10);
+
+ if (endptr && *endptr == '\0' && icyMetaInt > 0) {
+ GstCaps* caps = gst_caps_new_simple("application/x-icy", "metadata-interval", G_TYPE_INT, (gint) icyMetaInt, NULL);
+
+ gst_app_src_set_caps(priv->appsrc, caps);
+ gst_caps_unref(caps);
+ }
+ }
+
+ GstTagList* tags = gst_tag_list_new();
+ value = response.httpHeaderField("icy-name");
+ if (!value.isEmpty()) {
+ g_free(priv->iradioName);
+ priv->iradioName = g_strdup(value.utf8().data());
+ g_object_notify(G_OBJECT(m_src), "iradio-name");
+ gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION, priv->iradioName, NULL);
+ }
+ value = response.httpHeaderField("icy-genre");
+ if (!value.isEmpty()) {
+ g_free(priv->iradioGenre);
+ priv->iradioGenre = g_strdup(value.utf8().data());
+ g_object_notify(G_OBJECT(m_src), "iradio-genre");
+ gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE, priv->iradioGenre, NULL);
+ }
+ value = response.httpHeaderField("icy-url");
+ if (!value.isEmpty()) {
+ g_free(priv->iradioUrl);
+ priv->iradioUrl = g_strdup(value.utf8().data());
+ g_object_notify(G_OBJECT(m_src), "iradio-url");
+ gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION, priv->iradioUrl, NULL);
+ }
+ value = response.httpHeaderField("icy-title");
+ if (!value.isEmpty()) {
+ g_free(priv->iradioTitle);
+ priv->iradioTitle = g_strdup(value.utf8().data());
+ g_object_notify(G_OBJECT(m_src), "iradio-title");
+ gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, priv->iradioTitle, NULL);
+ }
+
+ if (gst_tag_list_is_empty(tags))
+ gst_tag_list_free(tags);
+ else
+ gst_element_found_tags_for_pad(GST_ELEMENT(m_src), m_src->priv->srcpad, tags);
+}
+
+void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, int length, int lengthReceived)
+{
+ WebKitWebSrcPrivate* priv = m_src->priv;
+
+ GST_LOG_OBJECT(m_src, "Have %d bytes of data", length);
+
+ if (priv->seekID || handle != priv->resourceHandle) {
+ GST_DEBUG_OBJECT(m_src, "Seek in progress, ignoring data");
+ return;
+ }
+
+ GstBuffer* buffer = gst_buffer_new_and_alloc(length);
+
+ memcpy(GST_BUFFER_DATA(buffer), data, length);
+ GST_BUFFER_OFFSET(buffer) = priv->offset;
+ priv->offset += length;
+ GST_BUFFER_OFFSET_END(buffer) = priv->offset;
+
+ GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, buffer);
+ if (ret != GST_FLOW_OK && ret != GST_FLOW_UNEXPECTED)
+ GST_ELEMENT_ERROR(m_src, CORE, FAILED, (0), (0));
+}
+
+void StreamingClient::didFinishLoading(ResourceHandle*, double)
+{
+ WebKitWebSrcPrivate* priv = m_src->priv;
+
+ GST_DEBUG_OBJECT(m_src, "Have EOS");
+
+ if (!priv->seekID)
+ gst_app_src_end_of_stream(m_src->priv->appsrc);
+}
+
+void StreamingClient::didFail(ResourceHandle*, const ResourceError& error)
+{
+ GST_ERROR_OBJECT(m_src, "Have failure: %s", error.localizedDescription().utf8().data());
+ GST_ELEMENT_ERROR(m_src, RESOURCE, FAILED, ("%s", error.localizedDescription().utf8().data()), (0));
+ gst_app_src_end_of_stream(m_src->priv->appsrc);
+}
+
+void StreamingClient::wasBlocked(ResourceHandle*)
+{
+ GST_ERROR_OBJECT(m_src, "Request was blocked");
+ GST_ELEMENT_ERROR(m_src, RESOURCE, OPEN_READ, ("Access to \"%s\" was blocked", m_src->priv->uri), (0));
+}
+
+void StreamingClient::cannotShowURL(ResourceHandle*)
+{
+ GST_ERROR_OBJECT(m_src, "Cannot show URL");
+ GST_ELEMENT_ERROR(m_src, RESOURCE, OPEN_READ, ("Can't show \"%s\"", m_src->priv->uri), (0));
+}
+
+#endif // USE(GSTREAMER)
+
diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h
new file mode 100644
index 0000000..bdb0833
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2009,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef WebKitWebSourceGStreamer_h
+#define WebKitWebSourceGStreamer_h
+#if USE(GSTREAMER)
+
+#include "Frame.h"
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_WEB_SRC (webkit_web_src_get_type ())
+#define WEBKIT_WEB_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_WEB_SRC, WebKitWebSrc))
+#define WEBKIT_WEB_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_WEB_SRC, WebKitWebSrcClass))
+#define WEBKIT_IS_WEB_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_WEB_SRC))
+#define WEBKIT_IS_WEB_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_WEB_SRC))
+
+typedef struct _WebKitWebSrc WebKitWebSrc;
+typedef struct _WebKitWebSrcClass WebKitWebSrcClass;
+typedef struct _WebKitWebSrcPrivate WebKitWebSrcPrivate;
+
+struct _WebKitWebSrc {
+ GstBin parent;
+
+ WebKitWebSrcPrivate *priv;
+};
+
+struct _WebKitWebSrcClass {
+ GstBinClass parentClass;
+};
+
+GType webkit_web_src_get_type(void);
+void webKitWebSrcSetFrame(WebKitWebSrc* src, WebCore::Frame* frame);
+
+G_END_DECLS
+
+#endif // USE(GSTREAMER)
+#endif
diff --git a/Source/WebCore/platform/graphics/gtk/ColorGtk.cpp b/Source/WebCore/platform/graphics/gtk/ColorGtk.cpp
new file mode 100644
index 0000000..8f56ba6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gtk/ColorGtk.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+Color::Color(const GdkColor& c)
+ : m_color(makeRGB(c.red >> 8, c.green >> 8, c.blue >> 8))
+ , m_valid(true)
+{
+}
+
+#ifndef GTK_API_VERSION_2
+Color::Color(const GdkRGBA& c)
+ : m_color(makeRGBA(static_cast<int>(c.red * 255),
+ static_cast<int>(c.green * 255),
+ static_cast<int>(c.blue * 255),
+ static_cast<int>(c.alpha * 255)))
+ , m_valid(true)
+{
+}
+
+Color::operator GdkRGBA() const
+{
+ double red, green, blue, alpha;
+ getRGBA(red, green, blue, alpha);
+ GdkRGBA rgba = { red, green, blue, alpha };
+ return rgba;
+}
+#endif
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/gtk/FontGtk.cpp b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp
new file mode 100644
index 0000000..fdf91db
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (c) 2007 Hiroyuki Ikezoe
+ * Copyright (c) 2007 Kouhei Sutou
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Xan Lopez <xan@gnome.org>
+ * Copyright (C) 2008 Nuanti Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "CairoUtilities.h"
+#include "ContextShadow.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+#include <cairo.h>
+#include <gdk/gdk.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
+#if defined(USE_FREETYPE)
+#include <pango/pangofc-fontmap.h>
+#endif
+
+namespace WebCore {
+
+#ifdef GTK_API_VERSION_2
+typedef GdkRegion* PangoRegionType;
+
+void destroyPangoRegion(PangoRegionType region)
+{
+ gdk_region_destroy(region);
+}
+
+IntRect getPangoRegionExtents(PangoRegionType region)
+{
+ GdkRectangle rectangle;
+ gdk_region_get_clipbox(region, &rectangle);
+ return IntRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+}
+#else
+typedef cairo_region_t* PangoRegionType;
+
+void destroyPangoRegion(PangoRegionType region)
+{
+ cairo_region_destroy(region);
+}
+
+IntRect getPangoRegionExtents(PangoRegionType region)
+{
+ cairo_rectangle_int_t rectangle;
+ cairo_region_get_extents(region, &rectangle);
+ return IntRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+}
+#endif
+
+#define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff)
+#define IS_LOW_SURROGATE(u) ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff)
+
+static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length)
+{
+ gboolean need_copy = FALSE;
+ int i;
+
+ for (i = 0; i < aLength; i++) {
+ if (!aText[i] || IS_LOW_SURROGATE(aText[i])) {
+ need_copy = TRUE;
+ break;
+ }
+ else if (IS_HIGH_SURROGATE(aText[i])) {
+ if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
+ i++;
+ else {
+ need_copy = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (need_copy) {
+
+ /* Pango doesn't correctly handle nuls. We convert them to 0xff. */
+ /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */
+
+ UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0]));
+
+ /* don't need to reset i */
+ for (i = 0; i < aLength; i++) {
+ if (!p[i] || IS_LOW_SURROGATE(p[i]))
+ p[i] = 0xFFFD;
+ else if (IS_HIGH_SURROGATE(p[i])) {
+ if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
+ i++;
+ else
+ p[i] = 0xFFFD;
+ }
+ }
+
+ aText = p;
+ }
+
+ glong items_written;
+ text = g_utf16_to_utf8(reinterpret_cast<const gunichar2*>(aText), aLength, NULL, &items_written, NULL);
+ length = items_written;
+
+ if (need_copy)
+ g_free((gpointer)aText);
+
+}
+
+static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to)
+{
+ gchar* utf8 = 0;
+ gint new_length = 0;
+ utf16_to_utf8(characters, length, utf8, new_length);
+ if (!utf8)
+ return NULL;
+
+ if (from > 0) {
+ // discard the first 'from' characters
+ // FIXME: we should do this before the conversion probably
+ gchar* str_left = g_utf8_offset_to_pointer(utf8, from);
+ gchar* tmp = g_strdup(str_left);
+ g_free(utf8);
+ utf8 = tmp;
+ }
+
+ gchar* pos = utf8;
+ gint len = strlen(pos);
+ GString* ret = g_string_new_len(NULL, len);
+
+ // replace line break by space
+ while (len > 0) {
+ gint index, start;
+ pango_find_paragraph_boundary(pos, len, &index, &start);
+ g_string_append_len(ret, pos, index);
+ if (index == start)
+ break;
+ g_string_append_c(ret, ' ');
+ pos += start;
+ len -= start;
+ }
+ return g_string_free(ret, FALSE);
+}
+
+static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout)
+{
+#if defined(USE_FREETYPE)
+ if (font->primaryFont()->platformData().m_pattern) {
+ PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->platformData().m_pattern.get(), FALSE);
+ pango_layout_set_font_description(layout, desc);
+ pango_font_description_free(desc);
+ }
+#elif defined(USE_PANGO)
+ if (font->primaryFont()->platformData().m_font) {
+ PangoFontDescription* desc = pango_font_describe(font->primaryFont()->platformData().m_font);
+ pango_layout_set_font_description(layout, desc);
+ pango_font_description_free(desc);
+ }
+#endif
+
+ pango_layout_set_auto_dir(layout, FALSE);
+
+ PangoContext* pangoContext = pango_layout_get_context(layout);
+ PangoDirection direction = run.rtl() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
+ pango_context_set_base_dir(pangoContext, direction);
+ PangoAttrList* list = pango_attr_list_new();
+ PangoAttribute* attr;
+
+ attr = pango_attr_size_new_absolute(font->pixelSize() * PANGO_SCALE);
+ attr->end_index = G_MAXUINT;
+ pango_attr_list_insert_before(list, attr);
+
+ if (!run.spacingDisabled()) {
+ attr = pango_attr_letter_spacing_new(font->letterSpacing() * PANGO_SCALE);
+ attr->end_index = G_MAXUINT;
+ pango_attr_list_insert_before(list, attr);
+ }
+
+ // Pango does not yet support synthesising small caps
+ // See http://bugs.webkit.org/show_bug.cgi?id=15610
+
+ pango_layout_set_attributes(layout, list);
+ pango_attr_list_unref(list);
+}
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point, PangoLayoutLine* layoutLine, PangoRegionType renderRegion)
+{
+ ContextShadow* shadow = graphicsContext->contextShadow();
+ ASSERT(shadow);
+
+ if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow->m_type == ContextShadow::NoShadow)
+ return;
+
+ FloatPoint totalOffset(point + shadow->m_offset);
+
+ // Optimize non-blurry shadows, by just drawing text without the ContextShadow.
+ if (!shadow->mustUseContextShadow(graphicsContext)) {
+ cairo_save(context);
+ cairo_translate(context, totalOffset.x(), totalOffset.y());
+
+ setSourceRGBAFromColor(context, shadow->m_color);
+ gdk_cairo_region(context, renderRegion);
+ cairo_clip(context);
+ pango_cairo_show_layout_line(context, layoutLine);
+
+ cairo_restore(context);
+ return;
+ }
+
+ FloatRect extents(getPangoRegionExtents(renderRegion));
+ extents.setLocation(FloatPoint(point.x(), point.y() - extents.height()));
+ cairo_t* shadowContext = shadow->beginShadowLayer(graphicsContext, extents);
+ if (shadowContext) {
+ cairo_translate(shadowContext, point.x(), point.y());
+ pango_cairo_show_layout_line(shadowContext, layoutLine);
+
+ // We need the clipping region to be active when we blit the blurred shadow back,
+ // because we don't want any bits and pieces of characters out of range to be
+ // drawn. Since ContextShadow expects a consistent transform, we have to undo the
+ // translation before calling endShadowLayer as well.
+ cairo_save(context);
+ cairo_translate(context, totalOffset.x(), totalOffset.y());
+ gdk_cairo_region(context, renderRegion);
+ cairo_clip(context);
+ cairo_translate(context, -totalOffset.x(), -totalOffset.y());
+
+ shadow->endShadowLayer(graphicsContext);
+ cairo_restore(context);
+ }
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+#if defined(USE_FREETYPE)
+ if (!primaryFont()->platformData().m_pattern) {
+ drawSimpleText(context, run, point, from, to);
+ return;
+ }
+#endif
+
+ cairo_t* cr = context->platformContext();
+ PangoLayout* layout = pango_cairo_create_layout(cr);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ // Our layouts are single line
+ PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
+
+ // Get the region where this text will be laid out. We will use it to clip
+ // the Cairo context, for when we are only painting part of the text run and
+ // to calculate the size of the shadow buffer.
+ PangoRegionType partialRegion = 0;
+ char* start = g_utf8_offset_to_pointer(utf8, from);
+ char* end = g_utf8_offset_to_pointer(start, to - from);
+ int ranges[] = {start - utf8, end - utf8};
+ partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1);
+
+ drawGlyphsShadow(context, cr, point, layoutLine, partialRegion);
+
+ cairo_save(cr);
+ cairo_translate(cr, point.x(), point.y());
+
+ float red, green, blue, alpha;
+ context->fillColor().getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+ gdk_cairo_region(cr, partialRegion);
+ cairo_clip(cr);
+
+ pango_cairo_show_layout_line(cr, layoutLine);
+
+ if (context->textDrawingMode() & TextModeStroke) {
+ Color strokeColor = context->strokeColor();
+ strokeColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+ pango_cairo_layout_line_path(cr, layoutLine);
+ cairo_set_line_width(cr, context->strokeThickness());
+ cairo_stroke(cr);
+ }
+
+ // Pango sometimes leaves behind paths we don't want
+ cairo_new_path(cr);
+
+ destroyPangoRegion(partialRegion);
+ g_free(utf8);
+ g_object_unref(layout);
+
+ cairo_restore(cr);
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+// We should create the layout with our actual context but we can't access it from here.
+static PangoLayout* getDefaultPangoLayout(const TextRun& run)
+{
+ static PangoFontMap* map = pango_cairo_font_map_get_default();
+#if PANGO_VERSION_CHECK(1,21,5)
+ static PangoContext* pangoContext = pango_font_map_create_context(map);
+#else
+ // Deprecated in Pango 1.21.
+ static PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(map));
+#endif
+ PangoLayout* layout = pango_layout_new(pangoContext);
+
+ return layout;
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* overflow) const
+{
+#if defined(USE_FREETYPE)
+ if (!primaryFont()->platformData().m_pattern)
+ return floatWidthForSimpleText(run, 0, fallbackFonts, overflow);
+#endif
+
+ if (run.length() == 0)
+ return 0.0f;
+
+ PangoLayout* layout = getDefaultPangoLayout(run);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ int width;
+ pango_layout_get_pixel_size(layout, &width, 0);
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ return width;
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const
+{
+#if defined(USE_FREETYPE)
+ if (!primaryFont()->platformData().m_pattern)
+ return offsetForPositionForSimpleText(run, xFloat, includePartialGlyphs);
+#endif
+ // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
+ // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
+ int x = static_cast<int>(xFloat);
+
+ PangoLayout* layout = getDefaultPangoLayout(run);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ int index, trailing;
+ pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing);
+ glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index);
+ if (includePartialGlyphs)
+ offset += trailing;
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ return offset;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
+{
+#if defined(USE_FREETYPE)
+ if (!primaryFont()->platformData().m_pattern)
+ return selectionRectForSimpleText(run, point, h, from, to);
+#endif
+
+ PangoLayout* layout = getDefaultPangoLayout(run);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ char* start = g_utf8_offset_to_pointer(utf8, from);
+ char* end = g_utf8_offset_to_pointer(start, to - from);
+
+ if (run.ltr()) {
+ from = start - utf8;
+ to = end - utf8;
+ } else {
+ from = end - utf8;
+ to = start - utf8;
+ }
+
+ PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
+ int x_pos;
+
+ x_pos = 0;
+ if (from < layoutLine->length)
+ pango_layout_line_index_to_x(layoutLine, from, FALSE, &x_pos);
+ float beforeWidth = PANGO_PIXELS_FLOOR(x_pos);
+
+ x_pos = 0;
+ if (run.ltr() || to < layoutLine->length)
+ pango_layout_line_index_to_x(layoutLine, to, FALSE, &x_pos);
+ float afterWidth = PANGO_PIXELS(x_pos);
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ return FloatRect(point.x() + beforeWidth, point.y(), afterWidth - beforeWidth, h);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.cpp b/Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.cpp
new file mode 100644
index 0000000..d8018a3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GdkCairoUtilities.h"
+#include "GtkVersioning.h"
+
+#include <cairo.h>
+#include <gtk/gtk.h>
+
+GdkPixbuf* cairoImageSurfaceToGdkPixbuf(cairo_surface_t* surface)
+{
+ return gdk_pixbuf_get_from_surface(surface, 0, 0,
+ cairo_image_surface_get_width(surface),
+ cairo_image_surface_get_height(surface));
+}
+
diff --git a/Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.h b/Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.h
new file mode 100644
index 0000000..ff5b3ed
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 GdkCairoUtilities_h
+#define GdkCairoUtilities_h
+
+GdkPixbuf* cairoImageSurfaceToGdkPixbuf(cairo_surface_t* surface);
+
+#endif // GdkCairoUtilities_h
diff --git a/Source/WebCore/platform/graphics/gtk/IconGtk.cpp b/Source/WebCore/platform/graphics/gtk/IconGtk.cpp
new file mode 100644
index 0000000..d56b52d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gtk/IconGtk.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "MIMETypeRegistry.h"
+#include "PassRefPtr.h"
+#include <wtf/text/CString.h>
+
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+Icon::Icon()
+ : m_icon(0)
+{
+}
+
+Icon::~Icon()
+{
+ if (m_icon)
+ g_object_unref(m_icon);
+}
+
+static String lookupIconName(String MIMEType)
+{
+ /*
+ Lookup an appropriate icon according to either the Icon Naming Spec
+ or conventional Gnome icon names respectively.
+
+ See http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
+
+ The icon theme is probed for the following names:
+ 1. media-subtype
+ 2. gnome-mime-media-subtype
+ 3. media-x-generic
+ 4. gnome-mime-media
+
+ In the worst case it falls back to the stock file icon.
+ */
+ int pos = MIMEType.find('/');
+ if(pos >= 0) {
+ String media = MIMEType.substring(0, pos);
+ String subtype = MIMEType.substring(pos + 1);
+ GtkIconTheme* iconTheme = gtk_icon_theme_get_default();
+ String iconName = media + "-" + subtype;
+ if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data()))
+ return iconName;
+ iconName = "gnome-mime-" + media + "-" + subtype;
+ if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data()))
+ return iconName;
+ iconName = media + "-x-generic";
+ if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data()))
+ return iconName;
+ iconName = media + "gnome-mime-" + media;
+ if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data()))
+ return iconName;
+ }
+ return GTK_STOCK_FILE;
+}
+
+// FIXME: Move the code to ChromeClient::iconForFiles().
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ if (filenames.isEmpty())
+ return 0;
+
+ if (filenames.size() == 1) {
+ if (!g_path_skip_root(filenames[0].utf8().data()))
+ return 0;
+
+ String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filenames[0]);
+ String iconName = lookupIconName(MIMEType);
+
+ RefPtr<Icon> icon = adoptRef(new Icon);
+ icon->m_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), iconName.utf8().data(), 16, GTK_ICON_LOOKUP_USE_BUILTIN, 0);
+ if (!icon->m_icon)
+ return 0;
+ return icon.release();
+ }
+
+ //FIXME: Implement this
+ return 0;
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (context->paintingDisabled())
+ return;
+
+ // TODO: Scale/clip the image if necessary.
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+ gdk_cairo_set_source_pixbuf(cr, m_icon, rect.x(), rect.y());
+ cairo_paint(cr);
+ cairo_restore(cr);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp b/Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp
new file mode 100644
index 0000000..2aa016e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "Base64.h"
+#include "GdkCairoUtilities.h"
+#include "GOwnPtr.h"
+#include "GRefPtrGtk.h"
+#include "MIMETypeRegistry.h"
+#include <cairo.h>
+#include <gtk/gtk.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+
+namespace WebCore {
+
+String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const
+{
+ ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+
+ if (!mimeType.startsWith("image/"))
+ return "data:,";
+
+ // List of supported image types comes from the GdkPixbuf documentation.
+ // http://library.gnome.org/devel/gdk-pixbuf/stable/gdk-pixbuf-file-saving.html#gdk-pixbuf-save-to-bufferv
+ String type = mimeType.substring(sizeof "image");
+ if (type != "jpeg" && type != "png" && type != "tiff" && type != "ico" && type != "bmp")
+ return "data:,";
+
+ GRefPtr<GdkPixbuf> pixbuf = cairoImageSurfaceToGdkPixbuf(m_data.m_surface);
+ if (!pixbuf)
+ return "data:,";
+
+ GOwnPtr<gchar> buffer(0);
+ gsize bufferSize;
+ GError* error = 0;
+ gboolean success = FALSE;
+ if (type == "jpeg" && quality && *quality >= 0.0 && *quality <= 1.0) {
+ String qualityString = String::format("%f", *quality);
+ success = gdk_pixbuf_save_to_buffer(pixbuf.get(), &buffer.outPtr(), &bufferSize,
+ type.utf8().data(), &error, "quality", qualityString.utf8().data(), NULL);
+ } else {
+ success = gdk_pixbuf_save_to_buffer(pixbuf.get(), &buffer.outPtr(), &bufferSize, type.utf8().data(), &error, NULL);
+ }
+
+ if (!success)
+ return "data:,";
+
+ Vector<char> out;
+ base64Encode(reinterpret_cast<const char*>(buffer.get()), bufferSize, out);
+
+ return makeString("data:", mimeType, ";base64,", out);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp b/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp
new file mode 100644
index 0000000..623ace6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#include "BitmapImage.h"
+#include "GdkCairoUtilities.h"
+#include "GOwnPtrGtk.h"
+#include "SharedBuffer.h"
+#include <wtf/text/CString.h>
+#include <cairo.h>
+#include <gtk/gtk.h>
+
+#if PLATFORM(WIN)
+#include <mbstring.h>
+#include <shlobj.h>
+
+static HMODULE hmodule;
+
+extern "C" {
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ hmodule = hinstDLL;
+ return TRUE;
+}
+}
+
+static const char* getWebKitDataDirectory()
+{
+ static char* dataDirectory = 0;
+ if (dataDirectory)
+ return dataDirectory;
+
+ dataDirectory = new char[PATH_MAX];
+ if (!GetModuleFileName(hmodule, static_cast<CHAR*>(dataDirectory), sizeof(dataDirectory) - 10))
+ return DATA_DIR;
+
+ // FIXME: This is pretty ugly. Ideally we should be using Windows API
+ // functions or GLib methods to calculate paths.
+ unsigned char *p;
+ p = _mbsrchr(static_cast<const unsigned char *>(dataDirectory), '\\');
+ *p = '\0';
+ p = _mbsrchr(static_cast<const unsigned char *>(dataDirectory), '\\');
+ if (p) {
+ if (!stricmp((const char *) (p+1), "bin"))
+ *p = '\0';
+ }
+ strcat(dataDirectory, "\\share");
+
+ return dataDirectory;
+}
+
+#else
+
+static const char* getWebKitDataDirectory()
+{
+ return DATA_DIR;
+}
+
+#endif
+
+namespace WebCore {
+
+static CString getThemeIconFileName(const char* name, int size)
+{
+ GtkIconInfo* iconInfo = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(),
+ name, size, GTK_ICON_LOOKUP_NO_SVG);
+ // Try to fallback on MISSING_IMAGE.
+ if (!iconInfo)
+ iconInfo = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(),
+ GTK_STOCK_MISSING_IMAGE, size,
+ GTK_ICON_LOOKUP_NO_SVG);
+ if (iconInfo) {
+ GOwnPtr<GtkIconInfo> info(iconInfo);
+ return CString(gtk_icon_info_get_filename(info.get()));
+ }
+
+ // No icon was found, this can happen if not GTK theme is set. In
+ // that case an empty Image will be created.
+ return CString();
+}
+
+static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(CString name)
+{
+ GOwnPtr<gchar> content;
+ gsize length;
+ if (!g_file_get_contents(name.data(), &content.outPtr(), &length, 0))
+ return SharedBuffer::create();
+
+ return SharedBuffer::create(content.get(), length);
+}
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+PassRefPtr<Image> loadImageFromFile(CString fileName)
+{
+ RefPtr<BitmapImage> img = BitmapImage::create();
+ if (!fileName.isNull()) {
+ RefPtr<SharedBuffer> buffer = loadResourceSharedBuffer(fileName);
+ img->setData(buffer.release(), true);
+ }
+ return img.release();
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+{
+ CString fileName;
+ if (!strcmp("missingImage", name))
+ fileName = getThemeIconFileName(GTK_STOCK_MISSING_IMAGE, 16);
+ if (fileName.isNull()) {
+ GOwnPtr<gchar> imageName(g_strdup_printf("%s.png", name));
+ GOwnPtr<gchar> glibFileName(g_build_filename(getWebKitDataDirectory(), "webkitgtk-"WEBKITGTK_API_VERSION_STRING, "images", imageName.get(), NULL));
+ fileName = glibFileName.get();
+ }
+
+ return loadImageFromFile(fileName);
+}
+
+PassRefPtr<Image> Image::loadPlatformThemeIcon(const char* name, int size)
+{
+ return loadImageFromFile(getThemeIconFileName(name, size));
+}
+
+GdkPixbuf* BitmapImage::getGdkPixbuf()
+{
+ return cairoImageSurfaceToGdkPixbuf(frameAtIndex(currentFrame()));
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/gtk/IntPointGtk.cpp b/Source/WebCore/platform/graphics/gtk/IntPointGtk.cpp
new file mode 100644
index 0000000..c402158
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gtk/IntPointGtk.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const GdkPoint& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator GdkPoint() const
+{
+ GdkPoint p = { x(), y() };
+ return p;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/gtk/IntRectGtk.cpp b/Source/WebCore/platform/graphics/gtk/IntRectGtk.cpp
new file mode 100644
index 0000000..aaa1944
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gtk/IntRectGtk.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+IntRect::IntRect(const GdkRectangle& r)
+ : m_location(IntPoint(r.x, r.y))
+ , m_size(r.width, r.height)
+{
+}
+
+IntRect::operator GdkRectangle() const
+{
+ GdkRectangle r = { x(), y(), width(), height() };
+ return r;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/haiku/ColorHaiku.cpp b/Source/WebCore/platform/graphics/haiku/ColorHaiku.cpp
new file mode 100644
index 0000000..a9ac186
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/ColorHaiku.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#include <InterfaceDefs.h>
+
+
+namespace WebCore {
+
+Color::Color(const rgb_color& color)
+ : m_color(makeRGBA(color.red, color.green, color.blue, color.alpha))
+ , m_valid(true)
+{
+}
+
+Color::operator rgb_color() const
+{
+ return make_color(red(), green(), blue(), alpha());
+}
+
+
+Color focusRingColor()
+{
+ return Color(keyboard_navigation_color());
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp b/Source/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp
new file mode 100644
index 0000000..0f50898
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatPoint.h"
+
+#include <Point.h>
+
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const BPoint& point)
+ : m_x(point.x)
+ , m_y(point.y)
+{
+}
+
+FloatPoint::operator BPoint() const
+{
+ return BPoint(m_x, m_y);
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp b/Source/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp
new file mode 100644
index 0000000..18fd94b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#include <Rect.h>
+
+
+namespace WebCore {
+
+FloatRect::FloatRect(const BRect& rect)
+ : m_location(rect.LeftTop())
+ , m_size(rect.Width() + 1, rect.Height() + 1)
+{
+}
+
+FloatRect::operator BRect() const
+{
+ return BRect(BPoint(x(), y()), BSize(width() - 1, height() - 1));
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp b/Source/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp
new file mode 100644
index 0000000..f8c2aa0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "Font.h"
+#include "FontData.h"
+#include "FontPlatformData.h"
+#include "NotImplemented.h"
+#include <String.h>
+#include <interface/Font.h>
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ FontPlatformData data(font.fontDescription(), font.family().family());
+ return getCachedFontData(&data);
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ notImplemented();
+ return 0;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ font_family family;
+ font_style style;
+ be_plain_font->GetFamilyAndStyle(&family, &style);
+ AtomicString plainFontFamily(family);
+ return getCachedFontData(fontDescription, plainFontFamily);
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ return new FontPlatformData(fontDescription, family);
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..ce7ec46
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode)
+{
+ return FontPlatformData(size, bold, italic);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ // FIXME: We need support in Haiku to read fonts from memory to implement this.
+ return 0;
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& /* format */)
+{
+ return false;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h
new file mode 100644
index 0000000..cc348e3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+ class FontPlatformData;
+ class SharedBuffer;
+
+ struct FontCustomPlatformData : Noncopyable {
+ public:
+ FontCustomPlatformData() { }
+ ~FontCustomPlatformData();
+
+ static bool supportsFormat(const String&);
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+ };
+
+ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/haiku/FontHaiku.cpp b/Source/WebCore/platform/graphics/haiku/FontHaiku.cpp
new file mode 100644
index 0000000..819fecb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/FontHaiku.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "FontData.h"
+#include "FontDescription.h"
+#include "FontSelector.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include <Font.h>
+#include <String.h>
+#include <View.h>
+
+
+// FIXME: Temp routine to convert unicode character to UTF8.
+int charUnicodeToUTF8HACK(unsigned short glyph, char* out)
+{
+ int i = 0;
+
+ if (glyph < 0x0080)
+ out[i++] = static_cast<char>(glyph);
+ else if (glyph < 0x0800) { // 2 bytes
+ out[i++] = 0xc0 | (glyph >> 6);
+ out[i++] = 0x80 | (glyph & 0x3F);
+ } else if (glyph > 0x0800) { // 3 bytes
+ out[i++] = 0xe0 | (glyph >> 12);
+ out[i++] = 0x80 | ((glyph >> 6) & 0x3F);
+ out[i++] = 0x80 | (glyph & 0x3F);
+ }
+
+ out[i] = '\0';
+ return i;
+}
+
+namespace WebCore {
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
+{
+ Color color = graphicsContext->fillColor();
+ BView* view = graphicsContext->platformContext();
+ BFont* m_font = font->platformData().font();
+
+ graphicsContext->setCompositeOperation(CompositeSourceOver);
+ view->SetHighColor(color);
+ view->SetFont(m_font);
+
+ GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
+ float offset = point.x();
+ for (int i = 0; i < numGlyphs; i++) {
+ char out[4];
+ charUnicodeToUTF8HACK(glyphs[i], out);
+
+ view->DrawString(out, sizeof(out), BPoint(offset, point.y()));
+ offset += glyphBuffer.advanceAt(from + i);
+ }
+}
+
+void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point,
+ int from, int to) const
+{
+ notImplemented();
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+ notImplemented();
+ return 0;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun&, const FloatPoint&, int, int, int) const
+{
+ notImplemented();
+ return FloatRect();
+}
+
+int Font::offsetForPositionForComplexText(const TextRun&, float, bool) const
+{
+ notImplemented();
+ return 0;
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/FontPlatformData.h b/Source/WebCore/platform/graphics/haiku/FontPlatformData.h
new file mode 100644
index 0000000..4e86e16
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/FontPlatformData.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+#include "FontDescription.h"
+#include "GlyphBuffer.h"
+#include <interface/Font.h>
+
+namespace WebCore {
+
+ class FontPlatformData {
+ public:
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_font(hashTableDeletedFontValue())
+ { }
+
+ FontPlatformData()
+ : m_font(0)
+ { }
+
+ FontPlatformData(const FontDescription&, const AtomicString& family);
+ FontPlatformData(float size, bool bold, bool oblique);
+ FontPlatformData(const FontPlatformData&);
+
+ ~FontPlatformData();
+
+ BFont* font() const { return m_font; }
+
+ bool isFixedPitch();
+ float size() const { return m_size; }
+ bool bold() const { return m_bold; }
+ bool oblique() const { return m_oblique; }
+
+ unsigned hash() const;
+ bool isHashTableDeletedValue() const;
+
+ bool operator==(const FontPlatformData&) const;
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+ BFont* m_font;
+ float m_size;
+ bool m_bold;
+ bool m_oblique;
+
+ private:
+ static BFont* hashTableDeletedFontValue() { return reinterpret_cast<BFont*>(-1); }
+ };
+
+} // namespace WebCore
+
+#endif
+
diff --git a/Source/WebCore/platform/graphics/haiku/GlyphPageTreeNodeHaiku.cpp b/Source/WebCore/platform/graphics/haiku/GlyphPageTreeNodeHaiku.cpp
new file mode 100644
index 0000000..3ae9aeb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/GlyphPageTreeNodeHaiku.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+#include <wtf/Assertions.h>
+#include <wtf/unicode/Unicode.h>
+
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* characterBuffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ bool isUtf16 = bufferLength != GlyphPage::size;
+ bool haveGlyphs = false;
+
+ for (unsigned i = 0; i < GlyphPage::size; i++) {
+ UChar32 character;
+
+ if (isUtf16) {
+ UChar lead = characterBuffer[i * 2];
+ UChar trail = characterBuffer[i * 2 + 1];
+ character = U16_GET_SUPPLEMENTARY(lead, trail);
+ } else
+ character = characterBuffer[i];
+
+ if (!character)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ haveGlyphs = true;
+ setGlyphDataForIndex(offset + i, character, fontData);
+ }
+ }
+
+ return haveGlyphs;
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/GradientHaiku.cpp b/Source/WebCore/platform/graphics/haiku/GradientHaiku.cpp
new file mode 100644
index 0000000..fdc4690
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/GradientHaiku.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> All rights reserved.
+ * Copyright (C) 2009 Maxime Simon <simon.maxime@theolliviers.com>
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "GraphicsContext.h"
+#include <GradientLinear.h>
+#include <GradientRadial.h>
+#include <View.h>
+
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ delete m_gradient;
+}
+
+PlatformGradient Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ if (m_radial) {
+ // TODO: Support m_r0?
+ m_gradient = new BGradientRadial(m_p0, m_r1);
+ } else
+ m_gradient = new BGradientLinear(m_p0, m_p1);
+ size_t size = m_stops.size();
+ for (size_t i = 0; i < size; i++) {
+ const ColorStop& stop = m_stops[i];
+ rgb_color color;
+ color.red = static_cast<uint8>(stop.red * 255);
+ color.green = static_cast<uint8>(stop.green * 255);
+ color.blue = static_cast<uint8>(stop.blue * 255);
+ color.alpha = static_cast<uint8>(stop.alpha * 255);
+ m_gradient->AddColor(color, stop.stop);
+ }
+ return m_gradient;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ context->platformContext()->FillRect(rect, *platformGradient());
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
new file mode 100644
index 0000000..acd431d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "Color.h"
+#include "Font.h"
+#include "FontData.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "Pen.h"
+#include <wtf/text/CString.h>
+#include <GraphicsDefs.h>
+#include <Region.h>
+#include <View.h>
+#include <Window.h>
+#include <stdio.h>
+
+
+namespace WebCore {
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContextPlatformPrivate(BView* view);
+ ~GraphicsContextPlatformPrivate();
+
+ BView* m_view;
+};
+
+GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(BView* view)
+ : m_view(view)
+{
+}
+
+GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
+{
+}
+
+void GraphicsContext::platformInit(PlatformGraphicsContext* context)
+{
+ m_data = new GraphicsContextPlatformPrivate(context);
+ setPaintingDisabled(!context);
+}
+
+void GraphicsContext::platformDestroy()
+{
+ delete m_data;
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ return m_data->m_view;
+}
+
+void GraphicsContext::savePlatformState()
+{
+ m_data->m_view->PushState();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ m_data->m_view->PopState();
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->m_view->FillRect(rect);
+ if (strokeStyle() != NoStroke)
+ m_data->m_view->StrokeRect(rect, getHaikuStrokeStyle());
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ if (strokeStyle() == NoStroke)
+ return;
+
+ m_data->m_view->StrokeLine(point1, point2, getHaikuStrokeStyle());
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->m_view->FillEllipse(rect);
+ if (strokeStyle() != NoStroke)
+ m_data->m_view->StrokeEllipse(rect, getHaikuStrokeStyle());
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->m_view->StrokeArc(rect, startAngle, angleSpan, getHaikuStrokeStyle());
+}
+
+void GraphicsContext::strokePath(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::drawConvexPolygon(size_t pointsLength, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ BPoint bPoints[pointsLength];
+ for (size_t i = 0; i < pointsLength; i++)
+ bPoints[i] = points[i];
+
+ m_data->m_view->FillPolygon(bPoints, pointsLength);
+ if (strokeStyle() != NoStroke)
+ // Stroke with low color
+ m_data->m_view->StrokePolygon(bPoints, pointsLength, true, getHaikuStrokeStyle());
+}
+
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ // FIXME: IMPLEMENT!!
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ rgb_color oldColor = m_data->m_view->HighColor();
+ m_data->m_view->SetHighColor(color);
+ m_data->m_view->FillRect(rect);
+ m_data->m_view->SetHighColor(oldColor);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !color.alpha())
+ return;
+
+ notImplemented();
+ // FIXME: A simple implementation could just use FillRoundRect if all
+ // the sizes are the same, or even if they are not. Otherwise several
+ // FillRect and FillArc calls are needed.
+}
+
+void GraphicsContext::fillPath(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ BRegion region(rect);
+ m_data->m_view->ConstrainClippingRegion(&region);
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ unsigned rectCount = rects.size();
+
+ // FIXME: maybe we should implement this with BShape?
+
+ if (rects.size() > 1) {
+ BRegion region;
+ for (int i = 0; i < rectCount; ++i)
+ region.Include(BRect(rects[i]));
+
+ m_data->m_view->SetHighColor(color);
+ m_data->m_view->StrokeRect(region.Frame(), B_MIXED_COLORS);
+ }
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ IntPoint endPoint = origin + IntSize(width, 0);
+ drawLine(origin, endPoint);
+}
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint&, int width, TextCheckingLineStyle)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ notImplemented();
+ return rect;
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float width)
+{
+ if (paintingDisabled())
+ return;
+
+ float oldSize = m_data->m_view->PenSize();
+ m_data->m_view->SetPenSize(width);
+ m_data->m_view->StrokeRect(rect, getHaikuStrokeStyle());
+ m_data->m_view->SetPenSize(oldSize);
+}
+
+void GraphicsContext::setLineCap(LineCap lineCap)
+{
+ if (paintingDisabled())
+ return;
+
+ cap_mode mode = B_BUTT_CAP;
+ switch (lineCap) {
+ case RoundCap:
+ mode = B_ROUND_CAP;
+ break;
+ case SquareCap:
+ mode = B_SQUARE_CAP;
+ break;
+ case ButtCap:
+ default:
+ break;
+ }
+
+ m_data->m_view->SetLineMode(mode, m_data->m_view->LineJoinMode(), m_data->m_view->LineMiterLimit());
+}
+
+void GraphicsContext::setLineJoin(LineJoin lineJoin)
+{
+ if (paintingDisabled())
+ return;
+
+ join_mode mode = B_MITER_JOIN;
+ switch (lineJoin) {
+ case RoundJoin:
+ mode = B_ROUND_JOIN;
+ break;
+ case BevelJoin:
+ mode = B_BEVEL_JOIN;
+ break;
+ case MiterJoin:
+ default:
+ break;
+ }
+
+ m_data->m_view->SetLineMode(m_data->m_view->LineCapMode(), mode, m_data->m_view->LineMiterLimit());
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->m_view->SetLineMode(m_data->m_view->LineCapMode(), m_data->m_view->LineJoinMode(), limit);
+}
+
+void GraphicsContext::setAlpha(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ drawing_mode mode = B_OP_COPY;
+ switch (op) {
+ case CompositeClear:
+ case CompositeCopy:
+ // Use the default above
+ break;
+ case CompositeSourceOver:
+ mode = B_OP_OVER;
+ break;
+ default:
+ printf("GraphicsContext::setPlatformCompositeOperation: Unsupported composite operation %s\n",
+ compositeOperatorName(op).utf8().data());
+ }
+ m_data->m_view->SetDrawingMode(mode);
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->m_view->ConstrainClippingRegion(path.platformPath());
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
+{
+ notImplemented();
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ notImplemented();
+ return AffineTransform();
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ notImplemented();
+ return InterpolationDefault;
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformFont(const Font& font)
+{
+ m_data->m_view->SetFont(font.primaryFont()->platformData().font());
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->m_view->SetHighColor(color);
+}
+
+pattern GraphicsContext::getHaikuStrokeStyle()
+{
+ switch (strokeStyle()) {
+ case SolidStroke:
+ return B_SOLID_HIGH;
+ break;
+ case DottedStroke:
+ return B_MIXED_COLORS;
+ break;
+ case DashedStroke:
+ // FIXME: use a better dashed stroke!
+ notImplemented();
+ return B_MIXED_COLORS;
+ break;
+ default:
+ return B_SOLID_LOW;
+ break;
+ }
+}
+
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle)
+{
+ // FIXME: see getHaikuStrokeStyle.
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->m_view->SetPenSize(thickness);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->m_view->SetHighColor(color);
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformShadow(FloatSize const&, float, Color const&, ColorSpace)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/IconHaiku.cpp b/Source/WebCore/platform/graphics/haiku/IconHaiku.cpp
new file mode 100644
index 0000000..3663ee2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/IconHaiku.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+
+
+namespace WebCore {
+
+Icon::~Icon()
+{
+ notImplemented();
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ notImplemented();
+ return 0;
+}
+
+void Icon::paint(GraphicsContext*, const IntRect&)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/ImageBufferData.h b/Source/WebCore/platform/graphics/haiku/ImageBufferData.h
new file mode 100644
index 0000000..7c676cd
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/ImageBufferData.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ImageBufferData_h
+#define ImageBufferData_h
+
+#include <Bitmap.h>
+#include <View.h>
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+ ~ImageBufferData();
+
+ BBitmap m_bitmap;
+ BView m_view;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
+
diff --git a/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp b/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp
new file mode 100644
index 0000000..bdad6a0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "Base64.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "StillImageHaiku.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+#include <BitmapStream.h>
+#include <String.h>
+#include <TranslatorRoster.h>
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_bitmap(BRect(0, 0, size.width() - 1, size.height() - 1), B_RGBA32, true)
+ , m_view(m_bitmap.Bounds(), "WebKit ImageBufferData", 0, 0)
+{
+ // Always keep the bitmap locked, we are the only client.
+ m_bitmap.Lock();
+ m_bitmap.AddChild(&m_view);
+
+ // Fill with completely transparent color.
+ memset(m_bitmap.Bits(), 0, m_bitmap.BitsLength());
+
+ // Since ImageBuffer is used mainly for Canvas, explicitly initialize
+ // its view's graphics state with the corresponding canvas defaults
+ // NOTE: keep in sync with CanvasRenderingContext2D::State
+ m_view.SetLineMode(B_BUTT_CAP, B_MITER_JOIN, 10);
+ m_view.SetDrawingMode(B_OP_ALPHA);
+ m_view.SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
+}
+
+ImageBufferData::~ImageBufferData()
+{
+ // Remove the view from the bitmap, keeping it from being free'd twice.
+ m_view.RemoveSelf();
+ m_bitmap.Unlock();
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, RenderingMode, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ m_context.set(new GraphicsContext(&m_data.m_view));
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ ASSERT(m_data.m_view.Window());
+
+ return m_context.get();
+}
+
+Image* ImageBuffer::image() const
+{
+ if (!m_image) {
+ // It's assumed that if image() is called, the actual rendering to the
+ // GraphicsContext must be done.
+ ASSERT(context());
+ m_data.m_view.Sync();
+ m_image = StillImage::create(m_data.m_bitmap);
+ }
+
+ return m_image.get();
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ uint8* rowData = reinterpret_cast<uint8*>(m_data.m_bitmap.Bits());
+ unsigned bytesPerRow = m_data.m_bitmap.BytesPerRow();
+ unsigned rows = m_size.height();
+ unsigned columns = m_size.width();
+ for (unsigned y = 0; y < rows; y++) {
+ uint8* pixel = rowData;
+ for (unsigned x = 0; x < columns; x++) {
+ // lookUpTable doesn't seem to support a LUT for each color channel
+ // separately (judging from the other ports). We don't need to
+ // convert from/to pre-multiplied color space since BBitmap storage
+ // is not pre-multiplied.
+ pixel[0] = lookUpTable[pixel[0]];
+ pixel[1] = lookUpTable[pixel[1]];
+ pixel[2] = lookUpTable[pixel[2]];
+ // alpha stays unmodified.
+ pixel += 4;
+ }
+ rowData += bytesPerRow;
+ }
+}
+
+static inline void convertFromData(const uint8* sourceRows, unsigned sourceBytesPerRow,
+ uint8* destRows, unsigned destBytesPerRow,
+ unsigned rows, unsigned columns)
+{
+ for (unsigned y = 0; y < rows; y++) {
+ const uint8* sourcePixel = sourceRows;
+ uint8* destPixel = destRows;
+ for (unsigned x = 0; x < columns; x++) {
+ // RGBA -> BGRA or BGRA -> RGBA
+ destPixel[0] = sourcePixel[2];
+ destPixel[1] = sourcePixel[1];
+ destPixel[2] = sourcePixel[0];
+ destPixel[3] = sourcePixel[3];
+ destPixel += 4;
+ sourcePixel += 4;
+ }
+ sourceRows += sourceBytesPerRow;
+ destRows += destBytesPerRow;
+ }
+}
+
+static inline void convertFromInternalData(const uint8* sourceRows, unsigned sourceBytesPerRow,
+ uint8* destRows, unsigned destBytesPerRow,
+ unsigned rows, unsigned columns,
+ bool premultiplied)
+{
+ if (premultiplied) {
+ // Internal storage is not pre-multiplied, pre-multiply on the fly.
+ for (unsigned y = 0; y < rows; y++) {
+ const uint8* sourcePixel = sourceRows;
+ uint8* destPixel = destRows;
+ for (unsigned x = 0; x < columns; x++) {
+ // RGBA -> BGRA or BGRA -> RGBA
+ destPixel[0] = static_cast<uint16>(sourcePixel[2]) * sourcePixel[3] / 255;
+ destPixel[1] = static_cast<uint16>(sourcePixel[1]) * sourcePixel[3] / 255;
+ destPixel[2] = static_cast<uint16>(sourcePixel[0]) * sourcePixel[3] / 255;
+ destPixel[3] = sourcePixel[3];
+ destPixel += 4;
+ sourcePixel += 4;
+ }
+ sourceRows += sourceBytesPerRow;
+ destRows += destBytesPerRow;
+ }
+ } else {
+ convertFromData(sourceRows, sourceBytesPerRow,
+ destRows, destBytesPerRow,
+ rows, columns);
+ }
+}
+
+static inline void convertToInternalData(const uint8* sourceRows, unsigned sourceBytesPerRow,
+ uint8* destRows, unsigned destBytesPerRow,
+ unsigned rows, unsigned columns,
+ bool premultiplied)
+{
+ if (premultiplied) {
+ // Internal storage is not pre-multiplied, de-multiply source data.
+ for (unsigned y = 0; y < rows; y++) {
+ const uint8* sourcePixel = sourceRows;
+ uint8* destPixel = destRows;
+ for (unsigned x = 0; x < columns; x++) {
+ // RGBA -> BGRA or BGRA -> RGBA
+ if (sourcePixel[3]) {
+ destPixel[0] = static_cast<uint16>(sourcePixel[2]) * 255 / sourcePixel[3];
+ destPixel[1] = static_cast<uint16>(sourcePixel[1]) * 255 / sourcePixel[3];
+ destPixel[2] = static_cast<uint16>(sourcePixel[0]) * 255 / sourcePixel[3];
+ destPixel[3] = sourcePixel[3];
+ } else {
+ destPixel[0] = 0;
+ destPixel[1] = 0;
+ destPixel[2] = 0;
+ destPixel[3] = 0;
+ }
+ destPixel += 4;
+ sourcePixel += 4;
+ }
+ sourceRows += sourceBytesPerRow;
+ destRows += destBytesPerRow;
+ }
+ } else {
+ convertFromData(sourceRows, sourceBytesPerRow,
+ destRows, destBytesPerRow,
+ rows, columns);
+ }
+}
+
+static PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size, bool premultiplied)
+{
+ RefPtr<ImageData> result = ImageData::create(IntSize(rect.width(), rect.height()));
+ unsigned char* data = result->data()->data()->data();
+
+ // If the destination image is larger than the source image, the outside
+ // regions need to be transparent. This way is simply, although with a
+ // a slight overhead for the inside region.
+ if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height())
+ memset(data, 0, result->data()->length());
+
+ // If the requested image is outside the source image, we can return at
+ // this point.
+ if (rect.x() > size.width() || rect.y() > size.height() || rect.right() < 0 || rect.bottom() < 0)
+ return result.release();
+
+ // Now we know there must be an intersection rect which we need to extract.
+ BRect sourceRect(0, 0, size.width() - 1, size.height() - 1);
+ sourceRect = BRect(rect) & sourceRect;
+
+ unsigned destBytesPerRow = 4 * rect.width();
+ unsigned char* destRows = data;
+ // Offset the destination pointer to point at the first pixel of the
+ // intersection rect.
+ destRows += (rect.x() - static_cast<int>(sourceRect.left)) * 4
+ + (rect.y() - static_cast<int>(sourceRect.top)) * destBytesPerRow;
+
+ const uint8* sourceRows = reinterpret_cast<const uint8*>(imageData.m_bitmap.Bits());
+ uint32 sourceBytesPerRow = imageData.m_bitmap.BytesPerRow();
+ // Offset the source pointer to point at the first pixel of the
+ // intersection rect.
+ sourceRows += static_cast<int>(sourceRect.left) * 4
+ + static_cast<int>(sourceRect.top) * sourceBytesPerRow;
+
+ unsigned rows = sourceRect.IntegerHeight() + 1;
+ unsigned columns = sourceRect.IntegerWidth() + 1;
+ convertFromInternalData(sourceRows, sourceBytesPerRow, destRows, destBytesPerRow,
+ rows, columns, premultiplied);
+
+ return result.release();
+}
+
+
+PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ // Make sure all asynchronous drawing has finished
+ m_data.m_view.Sync();
+ return getImageData(rect, m_data, m_size, false);
+}
+
+PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ // Make sure all asynchronous drawing has finished
+ m_data.m_view.Sync();
+ return getImageData(rect, m_data, m_size, true);
+}
+
+static void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size, bool premultiplied)
+{
+ // If the source image is outside the destination image, we can return at
+ // this point.
+ // FIXME: Check if this isn't already done in WebCore.
+ if (destPoint.x() > size.width() || destPoint.y() > size.height()
+ || destPoint.x() + sourceRect.width() < 0
+ || destPoint.y() + sourceRect.height() < 0) {
+ return;
+ }
+
+ const unsigned char* sourceRows = source->data()->data()->data();
+ unsigned sourceBytesPerRow = 4 * source->width();
+ // Offset the source pointer to the first pixel of the source rect.
+ sourceRows += sourceRect.x() * 4 + sourceRect.y() * sourceBytesPerRow;
+
+ // We know there must be an intersection rect.
+ BRect destRect(destPoint.x(), destPoint.y(), sourceRect.width() - 1, sourceRect.height() - 1);
+ destRect = destRect & BRect(0, 0, size.width() - 1, size.height() - 1);
+
+ unsigned char* destRows = reinterpret_cast<unsigned char*>(imageData.m_bitmap.Bits());
+ uint32 destBytesPerRow = imageData.m_bitmap.BytesPerRow();
+ // Offset the source pointer to point at the first pixel of the
+ // intersection rect.
+ destRows += static_cast<int>(destRect.left) * 4
+ + static_cast<int>(destRect.top) * destBytesPerRow;
+
+ unsigned rows = sourceRect.height();
+ unsigned columns = sourceRect.width();
+ convertToInternalData(sourceRows, sourceBytesPerRow, destRows, destBytesPerRow,
+ rows, columns, premultiplied);
+}
+
+void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ // Make sure all asynchronous drawing has finished
+ m_data.m_view.Sync();
+ putImageData(source, sourceRect, destPoint, m_data, m_size, false);
+}
+
+void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ // Make sure all asynchronous drawing has finished
+ m_data.m_view.Sync();
+ putImageData(source, sourceRect, destPoint, m_data, m_size, true);
+}
+
+String ImageBuffer::toDataURL(const String& mimeType, const double*) const
+{
+ if (!MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType))
+ return "data:,";
+
+ BString mimeTypeString(mimeType);
+
+ uint32 translatorType = 0;
+
+ BTranslatorRoster* roster = BTranslatorRoster::Default();
+ translator_id* translators;
+ int32 translatorCount;
+ roster->GetAllTranslators(&translators, &translatorCount);
+ for (int32 i = 0; i < translatorCount; i++) {
+ // Skip translators that don't support archived BBitmaps as input data.
+ const translation_format* inputFormats;
+ int32 formatCount;
+ roster->GetInputFormats(translators[i], &inputFormats, &formatCount);
+ bool supportsBitmaps = false;
+ for (int32 j = 0; j < formatCount; j++) {
+ if (inputFormats[j].type == B_TRANSLATOR_BITMAP) {
+ supportsBitmaps = true;
+ break;
+ }
+ }
+ if (!supportsBitmaps)
+ continue;
+
+ const translation_format* outputFormats;
+ roster->GetOutputFormats(translators[i], &outputFormats, &formatCount);
+ for (int32 j = 0; j < formatCount; j++) {
+ if (outputFormats[j].group == B_TRANSLATOR_BITMAP
+ && mimeTypeString == outputFormats[j].MIME) {
+ translatorType = outputFormats[j].type;
+ }
+ }
+ if (translatorType)
+ break;
+ }
+
+
+ BMallocIO translatedStream;
+ BBitmap* bitmap = const_cast<BBitmap*>(&m_data.m_bitmap);
+ // BBitmapStream doesn't take "const Bitmap*"...
+ BBitmapStream bitmapStream(bitmap);
+ if (roster->Translate(&bitmapStream, 0, 0, &translatedStream, translatorType,
+ B_TRANSLATOR_BITMAP, mimeType.utf8().data()) != B_OK) {
+ bitmapStream.DetachBitmap(&bitmap);
+ return "data:,";
+ }
+
+ bitmapStream.DetachBitmap(&bitmap);
+
+ Vector<char> encodedBuffer;
+ base64Encode(reinterpret_cast<const char*>(translatedStream.Buffer()),
+ translatedStream.BufferLength(), encodedBuffer);
+
+ return makeString("data:", mimeType, ";base64,", encodedBuffer);
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/ImageHaiku.cpp b/Source/WebCore/platform/graphics/haiku/ImageHaiku.cpp
new file mode 100644
index 0000000..5a55d7c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/ImageHaiku.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ * Copyright (C) 2008 Andrea Anzani <andrea.anzani@gmail.com>
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "BitmapImage.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageObserver.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+#include "SharedBuffer.h"
+#include "TransformationMatrix.h"
+#include <Application.h>
+#include <Bitmap.h>
+#include <View.h>
+
+// This function loads resources from WebKit
+Vector<char> loadResourceIntoArray(const char*);
+
+
+namespace WebCore {
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ delete m_frame;
+ m_frame = 0;
+ m_duration = 0.0f;
+ m_hasAlpha = true;
+ return true;
+ }
+
+ return false;
+}
+
+WTF::PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+{
+ Vector<char> array = loadResourceIntoArray(name);
+ WTF::PassRefPtr<BitmapImage> image = BitmapImage::create();
+ RefPtr<SharedBuffer> buffer = SharedBuffer::create(array.data(), array.size());
+ image->setData(buffer, true);
+
+ return image;
+}
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+// Drawing Routines
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ if (!m_source.initialized())
+ return;
+
+ // Spin the animation to the correct frame before we try to draw it, so we
+ // don't draw an old frame and then immediately need to draw a newer one,
+ // causing flicker and wasting CPU.
+ startAnimation();
+
+ BBitmap* image = nativeImageForCurrentFrame();
+ if (!image || !image->IsValid()) // If the image hasn't fully loaded.
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+ ctxt->save();
+ ctxt->setCompositeOperation(op);
+
+ BRect srcRect(src);
+ BRect dstRect(dst);
+
+ // Test using example site at
+ // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ ctxt->platformContext()->SetDrawingMode(B_OP_ALPHA);
+ ctxt->platformContext()->DrawBitmapAsync(image, srcRect, dstRect);
+ ctxt->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& dstRect)
+{
+ BBitmap* image = nativeImageForCurrentFrame();
+ if (!image || !image->IsValid()) // If the image hasn't fully loaded.
+ return;
+
+ // Figure out if the image has any alpha transparency, we can use faster drawing if not
+ bool hasAlpha = false;
+
+ uint8* bits = reinterpret_cast<uint8*>(image->Bits());
+ uint32 width = image->Bounds().IntegerWidth() + 1;
+ uint32 height = image->Bounds().IntegerHeight() + 1;
+
+ uint32 bytesPerRow = image->BytesPerRow();
+ for (uint32 y = 0; y < height && !hasAlpha; y++) {
+ uint8* p = bits;
+ for (uint32 x = 0; x < width && !hasAlpha; x++) {
+ hasAlpha = p[3] < 255;
+ p += 4;
+ }
+ bits += bytesPerRow;
+ }
+
+ context->save();
+ if (hasAlpha)
+ context->platformContext()->SetDrawingMode(B_OP_ALPHA);
+ else
+ context->platformContext()->SetDrawingMode(B_OP_COPY);
+ context->clip(enclosingIntRect(dstRect));
+ float currentW = phase.x();
+ BRect bTileRect(tileRect);
+ while (currentW < dstRect.x() + dstRect.width()) {
+ float currentH = phase.y();
+ while (currentH < dstRect.y() + dstRect.height()) {
+ BRect bDstRect(currentW, currentH, currentW + width - 1, currentH + height - 1);
+ context->platformContext()->DrawBitmapAsync(image, bTileRect, bDstRect);
+ currentH += height;
+ }
+ currentW += width;
+ }
+ context->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_isSolidColor = false;
+ m_checkedForSolidColor = true;
+
+ if (frameCount() > 1)
+ return;
+
+ BBitmap* image = getBBitmap();
+ if (!image || !image->Bounds().IsValid()
+ || image->Bounds().IntegerWidth() > 0 || image->Bounds().IntegerHeight() > 0) {
+ return;
+ }
+
+ m_isSolidColor = true;
+ uint8* bits = reinterpret_cast<uint8*>(image->Bits());
+ m_solidColor = Color(bits[2], bits[1], bits[0], bits[3]);
+}
+
+BBitmap* BitmapImage::getBBitmap() const
+{
+ return const_cast<BitmapImage*>(this)->frameAtIndex(0);
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/IntPointHaiku.cpp b/Source/WebCore/platform/graphics/haiku/IntPointHaiku.cpp
new file mode 100644
index 0000000..327e503
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/IntPointHaiku.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include <Point.h>
+
+
+namespace WebCore {
+
+IntPoint::IntPoint(const BPoint& point)
+ : m_x(static_cast<int>(point.x))
+ , m_y(static_cast<int>(point.y))
+{
+}
+
+IntPoint::operator BPoint() const
+{
+ return BPoint(m_x, m_y);
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/IntRectHaiku.cpp b/Source/WebCore/platform/graphics/haiku/IntRectHaiku.cpp
new file mode 100644
index 0000000..5ee7207
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/IntRectHaiku.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include <Rect.h>
+
+
+namespace WebCore {
+
+IntRect::IntRect(const BRect& rect)
+ : m_location(rect.LeftTop())
+ , m_size(rect.IntegerWidth() + 1, rect.IntegerHeight() + 1)
+{
+}
+
+IntRect::operator BRect() const
+{
+ return BRect(BPoint(x(), y()), BSize(width() - 1, height() - 1));
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp b/Source/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp
new file mode 100644
index 0000000..08c3a9d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntSize.h"
+
+#include <Size.h>
+
+
+namespace WebCore {
+
+IntSize::IntSize(const BSize& size)
+ : m_width(size.IntegerWidth())
+ , m_height(size.IntegerHeight())
+{
+}
+
+IntSize::operator BSize() const
+{
+ return BSize(width(), height());
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/PathHaiku.cpp b/Source/WebCore/platform/graphics/haiku/PathHaiku.cpp
new file mode 100644
index 0000000..5377e10
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/PathHaiku.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+#include <Region.h>
+
+
+namespace WebCore {
+
+Path::Path()
+ : m_path(new BRegion())
+{
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path::Path(const Path& other)
+ : m_path(new BRegion(*other.platformPath()))
+{
+}
+
+Path& Path::operator=(const Path& other)
+{
+ if (&other != this)
+ m_path = other.platformPath();
+
+ return *this;
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
+
+FloatPoint Path::currentPoint() const
+{
+ // FIXME: implement safe way to return current point of subpath.
+ notImplemented();
+ float quietNaN = std::numeric_limits<float>::quiet_NaN();
+ return FloatPoint(quietNaN, quietNaN);
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ return m_path->Contains(point);
+}
+
+void Path::translate(const FloatSize& size)
+{
+ notImplemented();
+}
+
+FloatRect Path::boundingRect() const
+{
+ return m_path->Frame();
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ // FIXME: Use OffsetBy?
+ notImplemented();
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ notImplemented();
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
+{
+ notImplemented();
+}
+
+void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
+{
+ notImplemented();
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ notImplemented();
+}
+
+void Path::closeSubpath()
+{
+ notImplemented();
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise)
+{
+ notImplemented();
+}
+
+void Path::addRect(const FloatRect& r)
+{
+ m_path->Include(r);
+}
+
+void Path::addEllipse(const FloatRect& r)
+{
+ notImplemented();
+}
+
+void Path::clear()
+{
+ m_path->MakeEmpty();
+}
+
+bool Path::isEmpty() const
+{
+ return !m_path->Frame().IsValid();
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ notImplemented();
+}
+
+void Path::transform(const AffineTransform& transform)
+{
+ notImplemented();
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ notImplemented();
+ return FloatRect();
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp b/Source/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp
new file mode 100644
index 0000000..b1e7082
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "FloatRect.h"
+#include "FontCache.h"
+#include "FontDescription.h"
+#include "NotImplemented.h"
+#include "TextEncoding.h"
+#include <wtf/text/CString.h>
+
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ const BFont* font = m_platformData.font();
+ if (!font)
+ return;
+
+ font_height height;
+ font->GetHeight(&height);
+ m_ascent = static_cast<int>(height.ascent);
+ m_descent = static_cast<int>(height.descent);
+ m_lineSpacing = m_ascent + m_descent;
+ m_xHeight = height.ascent * 0.56f; // Hack taken from the win port.
+ m_lineGap = height.leading;
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ m_avgCharWidth = 0.f;
+ m_maxCharWidth = 0.f;
+ initCharWidths();
+}
+
+void SimpleFontData::platformDestroy()
+{
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ FontDescription desc = FontDescription(fontDescription);
+ desc.setSpecifiedSize(scaleFactor * fontDescription.computedSize());
+ FontPlatformData fontPlatformData(desc, desc.family().family());
+ return new SimpleFontData(fontPlatformData, isCustomFont(), false);
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ // FIXME: We will need to implement this to load non-ASCII encoding sites
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = m_platformData.font() && m_platformData.font()->IsFixed();
+}
+
+GlyphMetrics SimpleFontData::platformMetricsForGlyph(Glyph glyph, GlyphMetricsMode) const
+{
+ GlyphMetrics metrics;
+ if (!m_platformData.font())
+ return metrics;
+
+ CString encoded = UTF8Encoding().encode(static_cast<UChar*>(&glyph), 1,
+ URLEncodedEntitiesForUnencodables);
+ float escapements[1];
+ m_platformData.font()->GetEscapements(encoded.data(), 1, escapements);
+ metrics.horizontalAdvance = escapements[0] * m_platformData.font()->Size();
+ return metrics;
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/haiku/StillImageHaiku.cpp b/Source/WebCore/platform/graphics/haiku/StillImageHaiku.cpp
new file mode 100644
index 0000000..7f9fb15
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/StillImageHaiku.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "StillImageHaiku.h"
+
+#include "GraphicsContext.h"
+#include "IntSize.h"
+#include <View.h>
+
+namespace WebCore {
+
+StillImage::StillImage(const BBitmap& bitmap)
+ : m_bitmap(&bitmap)
+{
+}
+
+void StillImage::destroyDecodedData(bool destroyAll)
+{
+ // This is used for "large" animations to free image data.
+ // It appears it would not apply to StillImage.
+}
+
+unsigned StillImage::decodedSize() const
+{
+ // FIXME: It could be wise to return 0 here, since we don't want WebCore
+ // to think we eat up memory, since we are not freeing any in
+ // destroyDecodedData() either.
+ return m_bitmap.BitsLength();
+}
+
+IntSize StillImage::size() const
+{
+ return IntSize(m_bitmap.Bounds().IntegerWidth() + 1, m_bitmap.Bounds().IntegerHeight() + 1);
+}
+
+NativeImagePtr StillImage::nativeImageForCurrentFrame()
+{
+ return &m_bitmap;
+}
+
+void StillImage::draw(GraphicsContext* context, const FloatRect& destRect,
+ const FloatRect& sourceRect, ColorSpace, CompositeOperator op)
+{
+ if (!m_bitmap.IsValid())
+ return;
+
+ context->save();
+ context->setCompositeOperation(op);
+ context->platformContext()->DrawBitmap(&m_bitmap, sourceRect, destRect);
+ context->restore();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/haiku/StillImageHaiku.h b/Source/WebCore/platform/graphics/haiku/StillImageHaiku.h
new file mode 100644
index 0000000..f4bcbe1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/StillImageHaiku.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 StillImageHaiku_h
+#define StillImageHaiku_h
+
+#include "Image.h"
+#include <Bitmap.h>
+
+namespace WebCore {
+
+class StillImage : public Image {
+public:
+ static PassRefPtr<StillImage> create(const BBitmap& bitmap)
+ {
+ return adoptRef(new StillImage(bitmap));
+ }
+
+ virtual void destroyDecodedData(bool destroyAll = true);
+ virtual unsigned decodedSize() const;
+
+ virtual IntSize size() const;
+ virtual NativeImagePtr nativeImageForCurrentFrame();
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
+
+private:
+ StillImage(const BBitmap&);
+
+ BBitmap m_bitmap;
+};
+
+} // namespace WebCore
+
+#endif // StillImageHaiku_h
diff --git a/Source/WebCore/platform/graphics/mac/ColorMac.h b/Source/WebCore/platform/graphics/mac/ColorMac.h
new file mode 100644
index 0000000..b68b157
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/ColorMac.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Inc. ("Apple") 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ColorMac_h
+#define ColorMac_h
+
+#include "Color.h"
+
+#ifdef __OBJC__
+@class NSColor;
+#else
+class NSColor;
+#endif
+
+namespace WebCore {
+
+ // These functions assume NSColors are in DeviceRGB colorspace
+ Color colorFromNSColor(NSColor *);
+ NSColor *nsColor(const Color&);
+
+ bool usesTestModeFocusRingColor();
+ void setUsesTestModeFocusRingColor(bool);
+
+ // Focus ring color used for testing purposes.
+ RGBA32 oldAquaFocusRingColor();
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/mac/ColorMac.mm b/Source/WebCore/platform/graphics/mac/ColorMac.mm
new file mode 100644
index 0000000..07d6353
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/ColorMac.mm
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#import "config.h"
+#import "ColorMac.h"
+
+#import <wtf/RetainPtr.h>
+#import <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+// NSColor calls don't throw, so no need to block Cocoa exceptions in this file
+
+static bool useOldAquaFocusRingColor;
+
+RGBA32 oldAquaFocusRingColor()
+{
+ return 0xFF7DADD9;
+}
+
+void setUsesTestModeFocusRingColor(bool newValue)
+{
+ useOldAquaFocusRingColor = newValue;
+}
+
+bool usesTestModeFocusRingColor()
+{
+ return useOldAquaFocusRingColor;
+}
+
+static RGBA32 makeRGBAFromNSColor(NSColor *c)
+{
+ CGFloat redComponent;
+ CGFloat greenComponent;
+ CGFloat blueComponent;
+ CGFloat alpha;
+ [c getRed:&redComponent green:&greenComponent blue:&blueComponent alpha:&alpha];
+
+ return makeRGBA(255 * redComponent, 255 * greenComponent, 255 * blueComponent, 255 * alpha);
+}
+
+Color colorFromNSColor(NSColor *c)
+{
+ return Color(makeRGBAFromNSColor(c));
+}
+
+NSColor *nsColor(const Color& color)
+{
+ RGBA32 c = color.rgb();
+ switch (c) {
+ case 0: {
+ // Need this to avoid returning nil because cachedRGBAValues will default to 0.
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:0]));
+ return clearColor.get();
+ }
+ case Color::black: {
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:1]));
+ return blackColor.get();
+ }
+ case Color::white: {
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1 green:1 blue:1 alpha:1]));
+ return whiteColor.get();
+ }
+ default: {
+ const int cacheSize = 32;
+ static unsigned cachedRGBAValues[cacheSize];
+ static RetainPtr<NSColor>* cachedColors = new RetainPtr<NSColor>[cacheSize];
+
+ for (int i = 0; i != cacheSize; ++i) {
+ if (cachedRGBAValues[i] == c)
+ return cachedColors[i].get();
+ }
+
+ NSColor *result = [NSColor colorWithDeviceRed:static_cast<CGFloat>(color.red()) / 255
+ green:static_cast<CGFloat>(color.green()) / 255
+ blue:static_cast<CGFloat>(color.blue()) / 255
+ alpha:static_cast<CGFloat>(color.alpha()) / 255];
+
+ static int cursor;
+ cachedRGBAValues[cursor] = c;
+ cachedColors[cursor] = result;
+ if (++cursor == cacheSize)
+ cursor = 0;
+ return result;
+ }
+ }
+}
+
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp
new file mode 100644
index 0000000..206fd5f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "ComplexTextController.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+#include "CharacterNames.h"
+#include "FloatSize.h"
+#include "Font.h"
+#include "TextBreakIterator.h"
+
+#include <wtf/StdLibExtras.h>
+
+#if defined(BUILDING_ON_LEOPARD)
+// Undefined when compiling agains the 10.5 SDK.
+#define kCTVersionNumber10_6 0x00030000
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+static inline CGFloat roundCGFloat(CGFloat f)
+{
+ if (sizeof(CGFloat) == sizeof(float))
+ return roundf(static_cast<float>(f));
+ return static_cast<CGFloat>(round(f));
+}
+
+static inline CGFloat ceilCGFloat(CGFloat f)
+{
+ if (sizeof(CGFloat) == sizeof(float))
+ return ceilf(static_cast<float>(f));
+ return static_cast<CGFloat>(ceil(f));
+}
+
+ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts, bool forTextEmphasis)
+ : m_font(*font)
+ , m_run(run)
+ , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
+ , m_forTextEmphasis(forTextEmphasis)
+ , m_currentCharacter(0)
+ , m_end(run.length())
+ , m_totalWidth(0)
+ , m_runWidthSoFar(0)
+ , m_numGlyphsSoFar(0)
+ , m_currentRun(0)
+ , m_glyphInCurrentRun(0)
+ , m_characterInCurrentGlyph(0)
+ , m_finalRoundingWidth(0)
+ , m_padding(run.padding())
+ , m_fallbackFonts(fallbackFonts)
+ , m_minGlyphBoundingBoxX(numeric_limits<float>::max())
+ , m_maxGlyphBoundingBoxX(numeric_limits<float>::min())
+ , m_minGlyphBoundingBoxY(numeric_limits<float>::max())
+ , m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
+ , m_lastRoundingGlyph(0)
+{
+ if (!m_padding)
+ m_padPerSpace = 0;
+ else {
+ int numSpaces = 0;
+ for (int s = 0; s < m_run.length(); s++) {
+ if (Font::treatAsSpace(m_run[s]))
+ numSpaces++;
+ }
+
+ if (!numSpaces)
+ m_padPerSpace = 0;
+ else
+ m_padPerSpace = m_padding / numSpaces;
+ }
+
+ collectComplexTextRuns();
+ adjustGlyphsAndAdvances();
+}
+
+int ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
+{
+ if (h >= m_totalWidth)
+ return m_run.ltr() ? m_end : 0;
+ if (h < 0)
+ return m_run.ltr() ? 0 : m_end;
+
+ CGFloat x = h;
+
+ size_t runCount = m_complexTextRuns.size();
+ size_t offsetIntoAdjustedGlyphs = 0;
+
+ for (size_t r = 0; r < runCount; ++r) {
+ const ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
+ for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) {
+ CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width;
+ if (x < adjustedAdvance) {
+ CFIndex hitGlyphStart = complexTextRun.indexAt(j);
+ CFIndex hitGlyphEnd;
+ if (m_run.ltr())
+ hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : static_cast<CFIndex>(complexTextRun.stringLength()));
+ else
+ hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : static_cast<CFIndex>(complexTextRun.stringLength()));
+
+ // FIXME: Instead of dividing the glyph's advance equally between the characters, this
+ // could use the glyph's "ligature carets". However, there is no Core Text API to get the
+ // ligature carets.
+ CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
+ int stringLength = complexTextRun.stringLength();
+ TextBreakIterator* cursorPositionIterator = cursorMovementIterator(complexTextRun.characters(), stringLength);
+ int clusterStart;
+ if (isTextBreak(cursorPositionIterator, hitIndex))
+ clusterStart = hitIndex;
+ else {
+ clusterStart = textBreakPreceding(cursorPositionIterator, hitIndex);
+ if (clusterStart == TextBreakDone)
+ clusterStart = 0;
+ }
+
+ if (!includePartialGlyphs)
+ return complexTextRun.stringLocation() + clusterStart;
+
+ int clusterEnd = textBreakFollowing(cursorPositionIterator, hitIndex);
+ if (clusterEnd == TextBreakDone)
+ clusterEnd = stringLength;
+
+ CGFloat clusterWidth;
+ // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns
+ // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
+ // reordering and on font fallback should occur within a CTLine.
+ if (clusterEnd - clusterStart > 1) {
+ clusterWidth = adjustedAdvance;
+ int firstGlyphBeforeCluster = j - 1;
+ while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
+ CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width;
+ clusterWidth += width;
+ x += width;
+ firstGlyphBeforeCluster--;
+ }
+ unsigned firstGlyphAfterCluster = j + 1;
+ while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
+ clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width;
+ firstGlyphAfterCluster++;
+ }
+ } else {
+ clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart);
+ x -= clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1);
+ }
+ if (x <= clusterWidth / 2)
+ return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
+ else
+ return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
+ }
+ x -= adjustedAdvance;
+ }
+ offsetIntoAdjustedGlyphs += complexTextRun.glyphCount();
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void ComplexTextController::collectComplexTextRuns()
+{
+ if (!m_end)
+ return;
+
+ // We break up glyph run generation for the string by FontData and (if needed) the use of small caps.
+ const UChar* cp = m_run.characters();
+
+ if (m_font.isSmallCaps())
+ m_smallCapsBuffer.resize(m_end);
+
+ unsigned indexOfFontTransition = m_run.rtl() ? m_end - 1 : 0;
+ const UChar* curr = m_run.rtl() ? cp + m_end - 1 : cp;
+ const UChar* end = m_run.rtl() ? cp - 1 : cp + m_end;
+
+ GlyphData glyphData;
+ GlyphData nextGlyphData;
+
+ bool isSurrogate = U16_IS_SURROGATE(*curr);
+ if (isSurrogate) {
+ if (m_run.ltr()) {
+ if (!U16_IS_SURROGATE_LEAD(curr[0]) || curr + 1 == end || !U16_IS_TRAIL(curr[1]))
+ return;
+ nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[0], curr[1]), false);
+ } else {
+ if (!U16_IS_TRAIL(curr[0]) || curr -1 == end || !U16_IS_SURROGATE_LEAD(curr[-1]))
+ return;
+ nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[-1], curr[0]), false);
+ }
+ } else
+ nextGlyphData = m_font.glyphDataForCharacter(*curr, false);
+
+ UChar newC = 0;
+
+ bool isSmallCaps;
+ bool nextIsSmallCaps = !isSurrogate && m_font.isSmallCaps() && !(U_GET_GC_MASK(*curr) & U_GC_M_MASK) && (newC = u_toupper(*curr)) != *curr;
+
+ if (nextIsSmallCaps)
+ m_smallCapsBuffer[curr - cp] = newC;
+
+ while (true) {
+ curr = m_run.rtl() ? curr - (isSurrogate ? 2 : 1) : curr + (isSurrogate ? 2 : 1);
+ if (curr == end)
+ break;
+
+ glyphData = nextGlyphData;
+ isSmallCaps = nextIsSmallCaps;
+ int index = curr - cp;
+ isSurrogate = U16_IS_SURROGATE(*curr);
+ UChar c = *curr;
+ bool forceSmallCaps = !isSurrogate && isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK);
+ if (isSurrogate) {
+ if (m_run.ltr()) {
+ if (!U16_IS_SURROGATE_LEAD(curr[0]) || curr + 1 == end || !U16_IS_TRAIL(curr[1]))
+ return;
+ nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[0], curr[1]), false);
+ } else {
+ if (!U16_IS_TRAIL(curr[0]) || curr -1 == end || !U16_IS_SURROGATE_LEAD(curr[-1]))
+ return;
+ nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[-1], curr[0]), false);
+ }
+ } else
+ nextGlyphData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps ? SmallCapsVariant : AutoVariant);
+
+ if (!isSurrogate && m_font.isSmallCaps()) {
+ nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c;
+ if (nextIsSmallCaps)
+ m_smallCapsBuffer[index] = forceSmallCaps ? c : newC;
+ }
+
+ if (nextGlyphData.fontData != glyphData.fontData || nextIsSmallCaps != isSmallCaps || !nextGlyphData.glyph != !glyphData.glyph) {
+ int itemStart = m_run.rtl() ? index + 1 : static_cast<int>(indexOfFontTransition);
+ int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition;
+ collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0);
+ indexOfFontTransition = index;
+ }
+ }
+
+ int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition;
+ if (itemLength) {
+ int itemStart = m_run.rtl() ? 0 : indexOfFontTransition;
+ collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0);
+ }
+}
+
+#if USE(CORE_TEXT) && USE(ATSUI)
+static inline bool shouldUseATSUIAPI()
+{
+ enum TypeRenderingAPIToUse { UnInitialized, UseATSUI, UseCoreText };
+ static TypeRenderingAPIToUse apiToUse = UnInitialized;
+
+ if (UNLIKELY(apiToUse == UnInitialized)) {
+ if (&CTGetCoreTextVersion != 0 && CTGetCoreTextVersion() >= kCTVersionNumber10_6)
+ apiToUse = UseCoreText;
+ else
+ apiToUse = UseATSUI;
+ }
+
+ return apiToUse == UseATSUI;
+}
+#endif
+
+CFIndex ComplexTextController::ComplexTextRun::indexAt(size_t i) const
+{
+#if USE(CORE_TEXT) && USE(ATSUI)
+ return shouldUseATSUIAPI() ? m_atsuiIndices[i] : m_coreTextIndices[i];
+#elif USE(ATSUI)
+ return m_atsuiIndices[i];
+#elif USE(CORE_TEXT)
+ return m_coreTextIndices[i];
+#endif
+}
+
+void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
+{
+#if USE(CORE_TEXT) && USE(ATSUI)
+ if (shouldUseATSUIAPI())
+ return collectComplexTextRunsForCharactersATSUI(cp, length, stringLocation, fontData);
+ return collectComplexTextRunsForCharactersCoreText(cp, length, stringLocation, fontData);
+#elif USE(ATSUI)
+ return collectComplexTextRunsForCharactersATSUI(cp, length, stringLocation, fontData);
+#elif USE(CORE_TEXT)
+ return collectComplexTextRunsForCharactersCoreText(cp, length, stringLocation, fontData);
+#endif
+}
+
+ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
+ : m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+ , m_isMonotonic(true)
+{
+#if USE(CORE_TEXT) && USE(ATSUI)
+ shouldUseATSUIAPI() ? createTextRunFromFontDataATSUI(ltr) : createTextRunFromFontDataCoreText(ltr);
+#elif USE(ATSUI)
+ createTextRunFromFontDataATSUI(ltr);
+#elif USE(CORE_TEXT)
+ createTextRunFromFontDataCoreText(ltr);
+#endif
+}
+
+void ComplexTextController::ComplexTextRun::setIsNonMonotonic()
+{
+ ASSERT(m_isMonotonic);
+ m_isMonotonic = false;
+
+ Vector<bool, 64> mappedIndices(m_stringLength);
+ for (size_t i = 0; i < m_glyphCount; ++i) {
+ ASSERT(indexAt(i) < static_cast<CFIndex>(m_stringLength));
+ mappedIndices[indexAt(i)] = true;
+ }
+
+ m_glyphEndOffsets.grow(m_glyphCount);
+ for (size_t i = 0; i < m_glyphCount; ++i) {
+ CFIndex nextMappedIndex = m_stringLength;
+ for (size_t j = indexAt(i) + 1; j < m_stringLength; ++j) {
+ if (mappedIndices[j]) {
+ nextMappedIndex = j;
+ break;
+ }
+ }
+ m_glyphEndOffsets[i] = nextMappedIndex;
+ }
+}
+
+void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
+{
+ if (static_cast<int>(offset) > m_end)
+ offset = m_end;
+
+ if (offset <= m_currentCharacter)
+ return;
+
+ m_currentCharacter = offset;
+
+ size_t runCount = m_complexTextRuns.size();
+
+ bool ltr = m_run.ltr();
+
+ unsigned k = ltr ? m_numGlyphsSoFar : m_adjustedGlyphs.size() - 1 - m_numGlyphsSoFar;
+ while (m_currentRun < runCount) {
+ const ComplexTextRun& complexTextRun = *m_complexTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun];
+ size_t glyphCount = complexTextRun.glyphCount();
+ unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
+ while (m_glyphInCurrentRun < glyphCount) {
+ unsigned glyphStartOffset = complexTextRun.indexAt(g);
+ unsigned glyphEndOffset;
+ if (complexTextRun.isMonotonic()) {
+ if (ltr)
+ glyphEndOffset = max<unsigned>(glyphStartOffset, g + 1 < glyphCount ? static_cast<unsigned>(complexTextRun.indexAt(g + 1)) : complexTextRun.stringLength());
+ else
+ glyphEndOffset = max<unsigned>(glyphStartOffset, g > 0 ? static_cast<unsigned>(complexTextRun.indexAt(g - 1)) : complexTextRun.stringLength());
+ } else
+ glyphEndOffset = complexTextRun.endOffsetAt(g);
+
+ CGSize adjustedAdvance = m_adjustedAdvances[k];
+
+ if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
+ return;
+
+ if (glyphBuffer && !m_characterInCurrentGlyph)
+ glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), adjustedAdvance);
+
+ unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
+ m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset;
+ // FIXME: Instead of dividing the glyph's advance equially between the characters, this
+ // could use the glyph's "ligature carets". However, there is no Core Text API to get the
+ // ligature carets.
+ if (glyphStartOffset == glyphEndOffset) {
+ // When there are multiple glyphs per character we need to advance by the full width of the glyph.
+ ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
+ m_runWidthSoFar += adjustedAdvance.width;
+ } else
+ m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
+
+ if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
+ return;
+
+ m_numGlyphsSoFar++;
+ m_glyphInCurrentRun++;
+ m_characterInCurrentGlyph = 0;
+ if (ltr) {
+ g++;
+ k++;
+ } else {
+ g--;
+ k--;
+ }
+ }
+ m_currentRun++;
+ m_glyphInCurrentRun = 0;
+ }
+ if (!ltr && m_numGlyphsSoFar == m_adjustedAdvances.size())
+ m_runWidthSoFar += m_finalRoundingWidth;
+}
+
+void ComplexTextController::adjustGlyphsAndAdvances()
+{
+ CGFloat widthSinceLastRounding = 0;
+ size_t runCount = m_complexTextRuns.size();
+ for (size_t r = 0; r < runCount; ++r) {
+ ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
+ unsigned glyphCount = complexTextRun.glyphCount();
+ const SimpleFontData* fontData = complexTextRun.fontData();
+
+ const CGGlyph* glyphs = complexTextRun.glyphs();
+ const CGSize* advances = complexTextRun.advances();
+
+ bool lastRun = r + 1 == runCount;
+ const UChar* cp = complexTextRun.characters();
+ CGFloat roundedSpaceWidth = roundCGFloat(fontData->spaceWidth());
+ bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances();
+ bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled();
+ CGPoint glyphOrigin = CGPointZero;
+ CFIndex lastCharacterIndex = m_run.ltr() ? numeric_limits<CFIndex>::min() : numeric_limits<CFIndex>::max();
+ bool isMonotonic = true;
+
+ for (unsigned i = 0; i < glyphCount; i++) {
+ CFIndex characterIndex = complexTextRun.indexAt(i);
+ if (m_run.ltr()) {
+ if (characterIndex < lastCharacterIndex)
+ isMonotonic = false;
+ } else {
+ if (characterIndex > lastCharacterIndex)
+ isMonotonic = false;
+ }
+ UChar ch = *(cp + characterIndex);
+ bool lastGlyph = lastRun && i + 1 == glyphCount;
+ UChar nextCh;
+ if (lastGlyph)
+ nextCh = ' ';
+ else if (i + 1 < glyphCount)
+ nextCh = *(cp + complexTextRun.indexAt(i + 1));
+ else
+ nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0));
+
+ bool treatAsSpace = Font::treatAsSpace(ch);
+ CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i];
+ CGSize advance = treatAsSpace ? CGSizeMake(fontData->spaceWidth(), advances[i].height) : advances[i];
+
+ if (ch == '\t' && m_run.allowTabs()) {
+ float tabWidth = m_font.tabWidth(*fontData);
+ advance.width = tabWidth - fmodf(m_run.xPos() + m_totalWidth + widthSinceLastRounding, tabWidth);
+ } else if (ch == zeroWidthSpace || (Font::treatAsZeroWidthSpace(ch) && !treatAsSpace)) {
+ advance.width = 0;
+ glyph = fontData->spaceGlyph();
+ }
+
+ float roundedAdvanceWidth = roundf(advance.width);
+ if (roundsAdvances)
+ advance.width = roundedAdvanceWidth;
+
+ advance.width += fontData->syntheticBoldOffset();
+
+ // We special case spaces in two ways when applying word rounding.
+ // First, we round spaces to an adjusted width in all fonts.
+ // Second, in fixed-pitch fonts we ensure that all glyphs that
+ // match the width of the space glyph have the same width as the space glyph.
+ if (roundedAdvanceWidth == roundedSpaceWidth && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) && m_run.applyWordRounding())
+ advance.width = fontData->adjustedSpaceWidth();
+
+ if (hasExtraSpacing) {
+ // If we're a glyph with an advance, go ahead and add in letter-spacing.
+ // That way we weed out zero width lurkers. This behavior matches the fast text code path.
+ if (advance.width && m_font.letterSpacing())
+ advance.width += m_font.letterSpacing();
+
+ // Handle justification and word-spacing.
+ if (treatAsSpace) {
+ // Account for padding. WebCore uses space padding to justify text.
+ // We distribute the specified padding over the available spaces in the run.
+ if (m_padding) {
+ // Use leftover padding if not evenly divisible by number of spaces.
+ if (m_padding < m_padPerSpace) {
+ advance.width += m_padding;
+ m_padding = 0;
+ } else {
+ float previousPadding = m_padding;
+ m_padding -= m_padPerSpace;
+ advance.width += roundf(previousPadding) - roundf(m_padding);
+ }
+ }
+
+ // Account for word-spacing.
+ if (characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing())
+ advance.width += m_font.wordSpacing();
+ }
+ }
+
+ // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters
+ // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
+ // We adjust the width of the last character of a "word" to ensure an integer width.
+ // Force characters that are used to determine word boundaries for the rounding hack
+ // to be integer width, so the following words will start on an integer boundary.
+ if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(ch))
+ advance.width = ceilCGFloat(advance.width);
+
+ // Check to see if the next character is a "rounding hack character", if so, adjust the
+ // width so that the total run width will be on an integer boundary.
+ if ((m_run.applyWordRounding() && !lastGlyph && Font::isRoundingHackCharacter(nextCh)) || (m_run.applyRunRounding() && lastGlyph)) {
+ CGFloat totalWidth = widthSinceLastRounding + advance.width;
+ widthSinceLastRounding = ceilCGFloat(totalWidth);
+ CGFloat extraWidth = widthSinceLastRounding - totalWidth;
+ if (m_run.ltr())
+ advance.width += extraWidth;
+ else {
+ if (m_lastRoundingGlyph)
+ m_adjustedAdvances[m_lastRoundingGlyph - 1].width += extraWidth;
+ else
+ m_finalRoundingWidth = extraWidth;
+ m_lastRoundingGlyph = m_adjustedAdvances.size() + 1;
+ }
+ m_totalWidth += widthSinceLastRounding;
+ widthSinceLastRounding = 0;
+ } else
+ widthSinceLastRounding += advance.width;
+
+ // FIXME: Combining marks should receive a text emphasis mark if they are combine with a space.
+ if (m_forTextEmphasis && (!Font::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK)))
+ glyph = 0;
+
+ advance.height *= -1;
+ m_adjustedAdvances.append(advance);
+ m_adjustedGlyphs.append(glyph);
+
+ FloatRect glyphBounds = fontData->boundsForGlyph(glyph);
+ glyphBounds.move(glyphOrigin.x, glyphOrigin.y);
+ m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphBounds.x());
+ m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.right());
+ m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphBounds.y());
+ m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.bottom());
+ glyphOrigin.x += advance.width;
+ glyphOrigin.y += advance.height;
+
+ lastCharacterIndex = characterIndex;
+ }
+ if (!isMonotonic)
+ complexTextRun.setIsNonMonotonic();
+ }
+ m_totalWidth += widthSinceLastRounding;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextController.h b/Source/WebCore/platform/graphics/mac/ComplexTextController.h
new file mode 100644
index 0000000..9cf80a6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/ComplexTextController.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 ComplexTextController_h
+#define ComplexTextController_h
+
+#include <ApplicationServices/ApplicationServices.h>
+#include "GlyphBuffer.h"
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+class Font;
+class SimpleFontData;
+class TextRun;
+
+// ComplexTextController is responsible for rendering and measuring glyphs for
+// complex scripts on OS X.
+// The underlying API can be selected at compile time based on USE(ATSUI) and
+// USE(CORE_TEXT). If both are defined then the Core Text APIs are used for
+// OS Versions >= 10.6, ATSUI is used otherwise.
+class ComplexTextController {
+public:
+ ComplexTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0, bool forTextEmphasis = false);
+
+ // Advance and emit glyphs up to the specified character.
+ void advance(unsigned to, GlyphBuffer* = 0);
+
+ // Compute the character offset for a given x coordinate.
+ int offsetForPosition(float x, bool includePartialGlyphs);
+
+ // Returns the width of everything we've consumed so far.
+ float runWidthSoFar() const { return m_runWidthSoFar; }
+
+ float totalWidth() const { return m_totalWidth; }
+
+ // Extra width to the left of the leftmost glyph.
+ float finalRoundingWidth() const { return m_finalRoundingWidth; }
+
+ float minGlyphBoundingBoxX() const { return m_minGlyphBoundingBoxX; }
+ float maxGlyphBoundingBoxX() const { return m_maxGlyphBoundingBoxX; }
+ float minGlyphBoundingBoxY() const { return m_minGlyphBoundingBoxY; }
+ float maxGlyphBoundingBoxY() const { return m_maxGlyphBoundingBoxY; }
+
+private:
+ class ComplexTextRun : public RefCounted<ComplexTextRun> {
+ public:
+#if USE(CORE_TEXT)
+ static PassRefPtr<ComplexTextRun> create(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength)
+ {
+ return adoptRef(new ComplexTextRun(ctRun, fontData, characters, stringLocation, stringLength));
+ }
+#endif
+#if USE(ATSUI)
+ static PassRefPtr<ComplexTextRun> create(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride)
+ {
+ return adoptRef(new ComplexTextRun(atsuTextLayout, fontData, characters, stringLocation, stringLength, ltr, directionalOverride));
+ }
+#endif
+ static PassRefPtr<ComplexTextRun> create(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
+ {
+ return adoptRef(new ComplexTextRun(fontData, characters, stringLocation, stringLength, ltr));
+ }
+
+ unsigned glyphCount() const { return m_glyphCount; }
+ const SimpleFontData* fontData() const { return m_fontData; }
+ const UChar* characters() const { return m_characters; }
+ unsigned stringLocation() const { return m_stringLocation; }
+ size_t stringLength() const { return m_stringLength; }
+ ALWAYS_INLINE CFIndex indexAt(size_t i) const;
+ CFIndex endOffsetAt(size_t i) const { ASSERT(!m_isMonotonic); return m_glyphEndOffsets[i]; }
+ const CGGlyph* glyphs() const { return m_glyphs; }
+ const CGSize* advances() const { return m_advances; }
+ bool isMonotonic() const { return m_isMonotonic; }
+ void setIsNonMonotonic();
+
+ private:
+#if USE(CORE_TEXT)
+ ComplexTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength);
+ void createTextRunFromFontDataCoreText(bool ltr);
+#endif
+#if USE(ATSUI)
+ ComplexTextRun(ATSUTextLayout, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride);
+ void createTextRunFromFontDataATSUI(bool ltr);
+#endif
+ ComplexTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr);
+
+#if USE(ATSUI)
+#ifdef BUILDING_ON_TIGER
+ typedef UInt32 URefCon;
+#endif
+ static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef, URefCon, void*, ATSULayoutOperationCallbackStatus*);
+#endif
+
+#if USE(CORE_TEXT)
+ RetainPtr<CTRunRef> m_coreTextRun;
+#endif
+ unsigned m_glyphCount;
+ const SimpleFontData* m_fontData;
+ const UChar* m_characters;
+ unsigned m_stringLocation;
+ size_t m_stringLength;
+#if USE(CORE_TEXT)
+ Vector<CFIndex, 64> m_coreTextIndicesVector;
+ const CFIndex* m_coreTextIndices;
+#endif
+#if USE(ATSUI)
+ Vector<CFIndex, 64> m_atsuiIndices;
+#endif
+ Vector<CFIndex, 64> m_glyphEndOffsets;
+ Vector<CGGlyph, 64> m_glyphsVector;
+ const CGGlyph* m_glyphs;
+ Vector<CGSize, 64> m_advancesVector;
+ const CGSize* m_advances;
+#if USE(ATSUI)
+ bool m_directionalOverride;
+#endif
+ bool m_isMonotonic;
+ };
+
+ void collectComplexTextRuns();
+
+ // collectComplexTextRunsForCharacters() is a stub function that calls through to the ATSUI or Core Text variants based
+ // on the API in use.
+ void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*);
+ void collectComplexTextRunsForCharactersATSUI(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*);
+ void collectComplexTextRunsForCharactersCoreText(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*);
+ void adjustGlyphsAndAdvances();
+
+ const Font& m_font;
+ const TextRun& m_run;
+ bool m_mayUseNaturalWritingDirection;
+ bool m_forTextEmphasis;
+
+ Vector<UChar, 256> m_smallCapsBuffer;
+
+ Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns;
+ Vector<CGSize, 256> m_adjustedAdvances;
+ Vector<CGGlyph, 256> m_adjustedGlyphs;
+
+ unsigned m_currentCharacter;
+ int m_end;
+
+ CGFloat m_totalWidth;
+
+ float m_runWidthSoFar;
+ unsigned m_numGlyphsSoFar;
+ size_t m_currentRun;
+ unsigned m_glyphInCurrentRun;
+ unsigned m_characterInCurrentGlyph;
+ float m_finalRoundingWidth;
+ float m_padding;
+ float m_padPerSpace;
+
+ HashSet<const SimpleFontData*>* m_fallbackFonts;
+
+ float m_minGlyphBoundingBoxX;
+ float m_maxGlyphBoundingBoxX;
+ float m_minGlyphBoundingBoxY;
+ float m_maxGlyphBoundingBoxY;
+
+ unsigned m_lastRoundingGlyph;
+};
+
+} // namespace WebCore
+
+#endif // ComplexTextController_h
diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp
new file mode 100644
index 0000000..c24a914
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ComplexTextController.h"
+
+#if USE(ATSUI)
+
+#include "CharacterNames.h"
+#include "Font.h"
+#include "ShapeArabic.h"
+
+#ifdef __LP64__
+// ATSUTextInserted() is SPI in 64-bit.
+extern "C" {
+OSStatus ATSUTextInserted(ATSUTextLayout iTextLayout, UniCharArrayOffset iInsertionLocation, UniCharCount iInsertionLength);
+}
+#endif
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef atsuLineRef, URefCon refCon, void*, ATSULayoutOperationCallbackStatus* callbackStatus)
+{
+ ComplexTextRun* complexTextRun = reinterpret_cast<ComplexTextRun*>(refCon);
+ OSStatus status;
+ ItemCount count;
+ ATSLayoutRecord* layoutRecords;
+
+ status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, reinterpret_cast<void**>(&layoutRecords), &count);
+ if (status != noErr) {
+ *callbackStatus = kATSULayoutOperationCallbackStatusContinue;
+ return status;
+ }
+
+ count--;
+ ItemCount j = 0;
+ CFIndex indexOffset = 0;
+
+ if (complexTextRun->m_directionalOverride) {
+ j++;
+ count -= 2;
+ indexOffset = -1;
+ }
+
+ complexTextRun->m_glyphCount = count;
+ complexTextRun->m_glyphsVector.reserveCapacity(count);
+ complexTextRun->m_advancesVector.reserveCapacity(count);
+ complexTextRun->m_atsuiIndices.reserveCapacity(count);
+
+ bool atBeginning = true;
+ CGFloat lastX = 0;
+
+ for (ItemCount i = 0; i < count; ++i, ++j) {
+ if (layoutRecords[j].glyphID == kATSDeletedGlyphcode) {
+ complexTextRun->m_glyphCount--;
+ continue;
+ }
+ complexTextRun->m_glyphsVector.uncheckedAppend(layoutRecords[j].glyphID);
+ complexTextRun->m_atsuiIndices.uncheckedAppend(layoutRecords[j].originalOffset / 2 + indexOffset);
+ CGFloat x = FixedToFloat(layoutRecords[j].realPos);
+ if (!atBeginning)
+ complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(x - lastX, 0));
+ lastX = x;
+ atBeginning = false;
+ }
+
+ complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(FixedToFloat(layoutRecords[j].realPos) - lastX, 0));
+
+ complexTextRun->m_glyphs = complexTextRun->m_glyphsVector.data();
+ complexTextRun->m_advances = complexTextRun->m_advancesVector.data();
+
+ status = ATSUDirectReleaseLayoutDataArrayPtr(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, reinterpret_cast<void**>(&layoutRecords));
+ *callbackStatus = kATSULayoutOperationCallbackStatusContinue;
+ return noErr;
+}
+
+static inline bool isArabicLamWithAlefLigature(UChar c)
+{
+ return c >= 0xfef5 && c <= 0xfefc;
+}
+
+static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength)
+{
+ unsigned shapingStart = 0;
+ while (shapingStart < totalLength) {
+ unsigned shapingEnd;
+ // We do not want to pass a Lam with Alef ligature followed by a space to the shaper,
+ // since we want to be able to identify this sequence as the result of shaping a Lam
+ // followed by an Alef and padding with a space.
+ bool foundLigatureSpace = false;
+ for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd)
+ foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' ';
+ shapingEnd++;
+
+ UErrorCode shapingError = U_ZERO_ERROR;
+ unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError);
+
+ if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) {
+ for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) {
+ if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ')
+ dest[++j] = zeroWidthSpace;
+ }
+ if (foundLigatureSpace) {
+ dest[shapingEnd] = ' ';
+ shapingEnd++;
+ } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) {
+ // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef,
+ // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR.
+ ASSERT(dest[shapingStart] == ' ');
+ dest[shapingStart] = zeroWidthSpace;
+ }
+ } else {
+ // Something went wrong. Abandon shaping and just copy the rest of the buffer.
+ LOG_ERROR("u_shapeArabic failed(%d)", shapingError);
+ shapingEnd = totalLength;
+ memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar));
+ }
+ shapingStart = shapingEnd;
+ }
+}
+
+ComplexTextController::ComplexTextRun::ComplexTextRun(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride)
+ : m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+ , m_directionalOverride(directionalOverride)
+ , m_isMonotonic(true)
+{
+ OSStatus status;
+
+ status = ATSUSetTextLayoutRefCon(atsuTextLayout, reinterpret_cast<URefCon>(this));
+
+ ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers;
+
+ Boolean rtl = !ltr;
+
+ Vector<UChar, 256> substituteCharacters;
+ bool shouldCheckForMirroring = !ltr && !fontData->m_ATSUMirrors;
+ bool shouldCheckForArabic = !fontData->shapesArabic();
+ bool shouldShapeArabic = false;
+
+ bool mirrored = false;
+ for (size_t i = 0; i < stringLength; ++i) {
+ if (shouldCheckForMirroring) {
+ UChar mirroredChar = u_charMirror(characters[i]);
+ if (mirroredChar != characters[i]) {
+ if (!mirrored) {
+ mirrored = true;
+ substituteCharacters.grow(stringLength);
+ memcpy(substituteCharacters.data(), characters, stringLength * sizeof(UChar));
+ ATSUTextMoved(atsuTextLayout, substituteCharacters.data());
+ }
+ substituteCharacters[i] = mirroredChar;
+ }
+ }
+ if (shouldCheckForArabic && isArabicChar(characters[i])) {
+ shouldCheckForArabic = false;
+ shouldShapeArabic = true;
+ }
+ }
+
+ if (shouldShapeArabic) {
+ Vector<UChar, 256> shapedArabic(stringLength);
+ shapeArabic(substituteCharacters.isEmpty() ? characters : substituteCharacters.data(), shapedArabic.data(), stringLength);
+ substituteCharacters.swap(shapedArabic);
+ ATSUTextMoved(atsuTextLayout, substituteCharacters.data());
+ }
+
+ if (directionalOverride) {
+ UChar override = ltr ? leftToRightOverride : rightToLeftOverride;
+ if (substituteCharacters.isEmpty()) {
+ substituteCharacters.grow(stringLength + 2);
+ substituteCharacters[0] = override;
+ memcpy(substituteCharacters.data() + 1, characters, stringLength * sizeof(UChar));
+ substituteCharacters[stringLength + 1] = popDirectionalFormatting;
+ ATSUTextMoved(atsuTextLayout, substituteCharacters.data());
+ } else {
+ substituteCharacters.prepend(override);
+ substituteCharacters.append(popDirectionalFormatting);
+ }
+ ATSUTextInserted(atsuTextLayout, 0, 2);
+ }
+
+ ATSULayoutOperationOverrideSpecifier overrideSpecifier;
+ overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment;
+ overrideSpecifier.overrideUPP = overrideLayoutOperation;
+
+ ATSUAttributeTag tags[] = { kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag };
+ ByteCount sizes[] = { sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) };
+ ATSUAttributeValuePtr values[] = { &lineLayoutOptions, &rtl, &overrideSpecifier };
+
+ status = ATSUSetLayoutControls(atsuTextLayout, 3, tags, sizes, values);
+
+ ItemCount boundsCount;
+ status = ATSUGetGlyphBounds(atsuTextLayout, 0, 0, 0, m_stringLength, kATSUseFractionalOrigins, 0, 0, &boundsCount);
+
+ status = ATSUDisposeTextLayout(atsuTextLayout);
+}
+
+void ComplexTextController::ComplexTextRun::createTextRunFromFontDataATSUI(bool ltr)
+{
+ m_atsuiIndices.reserveCapacity(m_stringLength);
+ unsigned r = 0;
+ while (r < m_stringLength) {
+ m_atsuiIndices.uncheckedAppend(r);
+ if (U_IS_SURROGATE(m_characters[r])) {
+ ASSERT(r + 1 < m_stringLength);
+ ASSERT(U_IS_SURROGATE_LEAD(m_characters[r]));
+ ASSERT(U_IS_TRAIL(m_characters[r + 1]));
+ r += 2;
+ } else
+ r++;
+ }
+ m_glyphCount = m_atsuiIndices.size();
+ if (!ltr) {
+ for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end)
+ std::swap(m_atsuiIndices[r], m_atsuiIndices[end]);
+ }
+
+ m_glyphsVector.fill(0, m_glyphCount);
+ m_glyphs = m_glyphsVector.data();
+ m_advancesVector.fill(CGSizeMake(m_fontData->widthForGlyph(0), 0), m_glyphCount);
+ m_advances = m_advancesVector.data();
+}
+
+static bool fontHasMirroringInfo(ATSUFontID fontID)
+{
+ ByteCount propTableSize;
+ OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize);
+ if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info
+ return true;
+ else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error
+ LOG_ERROR("ATSFontGetTable failed (%d)", static_cast<int>(status));
+
+ return false;
+}
+
+static void disableLigatures(const SimpleFontData* fontData, ATSUStyle atsuStyle, TypesettingFeatures typesettingFeatures)
+{
+ // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are
+ // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example.
+ // See bugzilla 5166.
+ if ((typesettingFeatures & Ligatures) || (fontData->orientation() == Horizontal && fontData->platformData().allowsLigatures()))
+ return;
+
+ ATSUFontFeatureType featureTypes[] = { kLigaturesType };
+ ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector };
+ OSStatus status = ATSUSetFontFeatures(atsuStyle, 1, featureTypes, featureSelectors);
+ if (status != noErr)
+ LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", static_cast<int>(status));
+}
+
+static ATSUStyle initializeATSUStyle(const SimpleFontData* fontData, TypesettingFeatures typesettingFeatures)
+{
+ unsigned key = typesettingFeatures + 1;
+ pair<HashMap<unsigned, ATSUStyle>::iterator, bool> addResult = fontData->m_ATSUStyleMap.add(key, 0);
+ ATSUStyle& atsuStyle = addResult.first->second;
+ if (!addResult.second)
+ return atsuStyle;
+
+ ATSUFontID fontID = fontData->platformData().ctFont() ? CTFontGetPlatformFont(fontData->platformData().ctFont(), 0) : 0;
+ if (!fontID) {
+ LOG_ERROR("unable to get ATSUFontID for %p", fontData->platformData().font());
+ fontData->m_ATSUStyleMap.remove(addResult.first);
+ return 0;
+ }
+
+ OSStatus status = ATSUCreateStyle(&atsuStyle);
+ if (status != noErr)
+ LOG_ERROR("ATSUCreateStyle failed (%d)", static_cast<int>(status));
+
+ Fixed fontSize = FloatToFixed(fontData->platformData().m_size);
+ Fract kerningInhibitFactor = FloatToFract(1);
+ static CGAffineTransform verticalFlip = CGAffineTransformMakeScale(1, -1);
+
+ ByteCount styleSizes[4] = { sizeof(fontSize), sizeof(fontID), sizeof(verticalFlip), sizeof(kerningInhibitFactor) };
+ ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag };
+ ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &verticalFlip, &kerningInhibitFactor };
+
+ bool allowKerning = typesettingFeatures & Kerning;
+ status = ATSUSetAttributes(atsuStyle, allowKerning ? 3 : 4, styleTags, styleSizes, styleValues);
+ if (status != noErr)
+ LOG_ERROR("ATSUSetAttributes failed (%d)", static_cast<int>(status));
+
+ fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID);
+
+ disableLigatures(fontData, atsuStyle, typesettingFeatures);
+ return atsuStyle;
+}
+
+void ComplexTextController::collectComplexTextRunsForCharactersATSUI(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
+{
+ if (!fontData) {
+ // Create a run of missing glyphs from the primary font.
+ m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
+ return;
+ }
+
+ if (m_fallbackFonts && fontData != m_font.primaryFont())
+ m_fallbackFonts->add(fontData);
+
+ ATSUStyle atsuStyle = initializeATSUStyle(fontData, m_font.typesettingFeatures());
+
+ OSStatus status;
+ ATSUTextLayout atsuTextLayout;
+ UniCharCount runLength = length;
+
+ status = ATSUCreateTextLayoutWithTextPtr(cp, 0, length, length, 1, &runLength, &atsuStyle, &atsuTextLayout);
+ if (status != noErr) {
+ LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed with error %d", static_cast<int>(status));
+ return;
+ }
+ m_complexTextRuns.append(ComplexTextRun::create(atsuTextLayout, fontData, cp, stringLocation, length, m_run.ltr(), m_run.directionalOverride()));
+}
+
+} // namespace WebCore
+
+#endif // USE(ATSUI)
diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp
new file mode 100644
index 0000000..42e7897
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "ComplexTextController.h"
+#include "WebCoreSystemInterface.h"
+
+#if USE(CORE_TEXT)
+
+#include "Font.h"
+
+#if defined(BUILDING_ON_LEOPARD)
+// The following symbols are SPI in 10.5.
+extern "C" {
+void CTRunGetAdvances(CTRunRef run, CFRange range, CGSize buffer[]);
+const CGSize* CTRunGetAdvancesPtr(CTRunRef run);
+extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
+}
+#endif
+
+namespace WebCore {
+
+ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength)
+ : m_coreTextRun(ctRun)
+ , m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+ , m_isMonotonic(true)
+{
+ m_glyphCount = CTRunGetGlyphCount(m_coreTextRun.get());
+ m_coreTextIndices = CTRunGetStringIndicesPtr(m_coreTextRun.get());
+ if (!m_coreTextIndices) {
+ m_coreTextIndicesVector.grow(m_glyphCount);
+ CTRunGetStringIndices(m_coreTextRun.get(), CFRangeMake(0, 0), m_coreTextIndicesVector.data());
+ m_coreTextIndices = m_coreTextIndicesVector.data();
+ }
+
+ m_glyphs = CTRunGetGlyphsPtr(m_coreTextRun.get());
+ if (!m_glyphs) {
+ m_glyphsVector.grow(m_glyphCount);
+ CTRunGetGlyphs(m_coreTextRun.get(), CFRangeMake(0, 0), m_glyphsVector.data());
+ m_glyphs = m_glyphsVector.data();
+ }
+
+ m_advances = CTRunGetAdvancesPtr(m_coreTextRun.get());
+ if (!m_advances) {
+ m_advancesVector.grow(m_glyphCount);
+ CTRunGetAdvances(m_coreTextRun.get(), CFRangeMake(0, 0), m_advancesVector.data());
+ m_advances = m_advancesVector.data();
+ }
+}
+
+// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on
+// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path.
+void ComplexTextController::ComplexTextRun::createTextRunFromFontDataCoreText(bool ltr)
+{
+ m_coreTextIndicesVector.reserveInitialCapacity(m_stringLength);
+ unsigned r = 0;
+ while (r < m_stringLength) {
+ m_coreTextIndicesVector.uncheckedAppend(r);
+ if (U_IS_SURROGATE(m_characters[r])) {
+ ASSERT(r + 1 < m_stringLength);
+ ASSERT(U_IS_SURROGATE_LEAD(m_characters[r]));
+ ASSERT(U_IS_TRAIL(m_characters[r + 1]));
+ r += 2;
+ } else
+ r++;
+ }
+ m_glyphCount = m_coreTextIndicesVector.size();
+ if (!ltr) {
+ for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end)
+ std::swap(m_coreTextIndicesVector[r], m_coreTextIndicesVector[end]);
+ }
+ m_coreTextIndices = m_coreTextIndicesVector.data();
+
+ // Synthesize a run of missing glyphs.
+ m_glyphsVector.fill(0, m_glyphCount);
+ m_glyphs = m_glyphsVector.data();
+ m_advancesVector.fill(CGSizeMake(m_fontData->widthForGlyph(0), 0), m_glyphCount);
+ m_advances = m_advancesVector.data();
+}
+
+struct ProviderInfo {
+ const UChar* cp;
+ unsigned length;
+ CFDictionaryRef attributes;
+};
+
+static const UniChar* provideStringAndAttributes(CFIndex stringIndex, CFIndex* charCount, CFDictionaryRef* attributes, void* refCon)
+{
+ ProviderInfo* info = static_cast<struct ProviderInfo*>(refCon);
+ if (stringIndex < 0 || static_cast<unsigned>(stringIndex) >= info->length)
+ return 0;
+
+ *charCount = info->length - stringIndex;
+ *attributes = info->attributes;
+ return info->cp + stringIndex;
+}
+
+void ComplexTextController::collectComplexTextRunsForCharactersCoreText(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
+{
+ if (!fontData) {
+ // Create a run of missing glyphs from the primary font.
+ m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
+ return;
+ }
+
+ if (m_fallbackFonts && fontData != m_font.primaryFont())
+ m_fallbackFonts->add(fontData);
+
+ RetainPtr<CTLineRef> line;
+
+ if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) {
+ static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel };
+ const short ltrForcedEmbeddingLevelValue = 0;
+ const short rtlForcedEmbeddingLevelValue = 1;
+ static const void* ltrOptionValues[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &ltrForcedEmbeddingLevelValue) };
+ static const void* rtlOptionValues[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &rtlForcedEmbeddingLevelValue) };
+ static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, WTF_ARRAY_LENGTH(optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, WTF_ARRAY_LENGTH(optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures()) };
+ RetainPtr<CTTypesetterRef> typesetter(AdoptCF, wkCreateCTTypesetterWithUniCharProviderAndOptions(&provideStringAndAttributes, 0, &info, m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
+#else
+ RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, cp, length, kCFAllocatorNull));
+ RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(m_font.typesettingFeatures())));
+ RetainPtr<CTTypesetterRef> typesetter(AdoptCF, CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
+#endif
+
+ line.adoptCF(CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0)));
+ } else {
+ ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures()) };
+
+ line.adoptCF(wkCreateCTLineWithUniCharProvider(&provideStringAndAttributes, 0, &info));
+ }
+
+ CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
+
+ CFIndex runCount = CFArrayGetCount(runArray);
+
+ for (CFIndex r = 0; r < runCount; r++) {
+ CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
+ ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
+ m_complexTextRuns.append(ComplexTextRun::create(ctRun, fontData, cp, stringLocation, length));
+ }
+}
+
+} // namespace WebCore
+
+#endif // USE(CORE_TEXT)
diff --git a/Source/WebCore/platform/graphics/mac/FloatPointMac.mm b/Source/WebCore/platform/graphics/mac/FloatPointMac.mm
new file mode 100644
index 0000000..2f73314
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/FloatPointMac.mm
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatPoint.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+FloatPoint::FloatPoint(const NSPoint& p) : m_x(p.x), m_y(p.y)
+{
+}
+
+FloatPoint::operator NSPoint() const
+{
+ return NSMakePoint(m_x, m_y);
+}
+
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/FloatRectMac.mm b/Source/WebCore/platform/graphics/mac/FloatRectMac.mm
new file mode 100644
index 0000000..1d6b045
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/FloatRectMac.mm
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+FloatRect::FloatRect(const NSRect& r) : m_location(r.origin), m_size(r.size)
+{
+}
+
+FloatRect::operator NSRect() const
+{
+ return NSMakeRect(x(), y(), width(), height());
+}
+
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/FloatSizeMac.mm b/Source/WebCore/platform/graphics/mac/FloatSizeMac.mm
new file mode 100644
index 0000000..01efbe9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/FloatSizeMac.mm
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatSize.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+FloatSize::FloatSize(const NSSize& s) : m_width(s.width), m_height(s.height)
+{
+}
+
+FloatSize::operator NSSize() const
+{
+ return NSMakeSize(m_width, m_height);
+}
+
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/FontCacheMac.mm b/Source/WebCore/platform/graphics/mac/FontCacheMac.mm
new file mode 100644
index 0000000..068bd8e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/FontCacheMac.mm
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "FontCache.h"
+
+#import "Font.h"
+#import "SimpleFontData.h"
+#import "FontPlatformData.h"
+#import "WebCoreSystemInterface.h"
+#import "WebFontCache.h"
+#import <AppKit/AppKit.h>
+#import <wtf/StdLibExtras.h>
+
+#ifdef BUILDING_ON_TIGER
+typedef int NSInteger;
+#endif
+
+namespace WebCore {
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef name, const void *, CFDictionaryRef)
+{
+ ASSERT_UNUSED(observer, observer == fontCache());
+ ASSERT_UNUSED(name, CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification));
+ fontCache()->invalidate();
+}
+#else
+static void fontCacheATSNotificationCallback(ATSFontNotificationInfoRef, void*)
+{
+ fontCache()->invalidate();
+}
+#endif
+
+void FontCache::platformInit()
+{
+ wkSetUpFontCache();
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately);
+#else
+ // kCTFontManagerRegisteredFontsChangedNotification does not exist on Leopard and earlier.
+ // FIXME: Passing kATSFontNotifyOptionReceiveWhileSuspended may be an overkill and does not seem to work anyway.
+ ATSFontNotificationSubscribe(fontCacheATSNotificationCallback, kATSFontNotifyOptionReceiveWhileSuspended, 0, 0);
+#endif
+}
+
+static int toAppKitFontWeight(FontWeight fontWeight)
+{
+ static int appKitFontWeights[] = {
+ 2, // FontWeight100
+ 3, // FontWeight200
+ 4, // FontWeight300
+ 5, // FontWeight400
+ 6, // FontWeight500
+ 8, // FontWeight600
+ 9, // FontWeight700
+ 10, // FontWeight800
+ 12, // FontWeight900
+ };
+ return appKitFontWeights[fontWeight];
+}
+
+static inline bool isAppKitFontWeightBold(NSInteger appKitFontWeight)
+{
+ return appKitFontWeight >= 7;
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ const FontPlatformData& platformData = font.fontDataAt(0)->fontDataForCharacter(characters[0])->platformData();
+ NSFont *nsFont = platformData.font();
+
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(characters) length:length freeWhenDone:NO];
+ NSFont *substituteFont = wkGetFontInLanguageForRange(nsFont, string, NSMakeRange(0, length));
+ [string release];
+
+ if (!substituteFont && length == 1)
+ substituteFont = wkGetFontInLanguageForCharacter(nsFont, characters[0]);
+ if (!substituteFont)
+ return 0;
+
+ // Use the family name from the AppKit-supplied substitute font, requesting the
+ // traits, weight, and size we want. One way this does better than the original
+ // AppKit request is that it takes synthetic bold and oblique into account.
+ // But it does create the possibility that we could end up with a font that
+ // doesn't actually cover the characters we need.
+
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+
+ NSFontTraitMask traits;
+ NSInteger weight;
+ CGFloat size;
+
+ if (nsFont) {
+ traits = [fontManager traitsOfFont:nsFont];
+ if (platformData.m_syntheticBold)
+ traits |= NSBoldFontMask;
+ if (platformData.m_syntheticOblique)
+ traits |= NSFontItalicTrait;
+ weight = [fontManager weightOfFont:nsFont];
+ size = [nsFont pointSize];
+ } else {
+ // For custom fonts nsFont is nil.
+ traits = font.italic() ? NSFontItalicTrait : 0;
+ weight = toAppKitFontWeight(font.weight());
+ size = font.pixelSize();
+ }
+
+ if (NSFont *bestVariation = [fontManager fontWithFamily:[substituteFont familyName] traits:traits weight:weight size:size])
+ substituteFont = bestVariation;
+
+ substituteFont = font.fontDescription().usePrinterFont() ? [substituteFont printerFont] : [substituteFont screenFont];
+
+ NSFontTraitMask substituteFontTraits = [fontManager traitsOfFont:substituteFont];
+ NSInteger substituteFontWeight = [fontManager weightOfFont:substituteFont];
+
+ FontPlatformData alternateFont(substituteFont, platformData.size(),
+ !font.isPlatformFont() && isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(substituteFontWeight),
+ !font.isPlatformFont() && (traits & NSFontItalicTrait) && !(substituteFontTraits & NSFontItalicTrait),
+ platformData.m_orientation);
+ return getCachedFontData(&alternateFont);
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ // Attempt to find an appropriate font using a match based on
+ // the presence of keywords in the the requested names. For example, we'll
+ // match any name that contains "Arabic" to Geeza Pro.
+ SimpleFontData* simpleFontData = 0;
+ const FontFamily* currFamily = &font.fontDescription().family();
+ while (currFamily && !simpleFontData) {
+ if (currFamily->family().length()) {
+ static String* matchWords[3] = { new String("Arabic"), new String("Pashto"), new String("Urdu") };
+ DEFINE_STATIC_LOCAL(AtomicString, geezaStr, ("Geeza Pro"));
+ for (int j = 0; j < 3 && !simpleFontData; ++j)
+ if (currFamily->family().contains(*matchWords[j], false))
+ simpleFontData = getCachedFontData(font.fontDescription(), geezaStr);
+ }
+ currFamily = currFamily->next();
+ }
+
+ return simpleFontData;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ DEFINE_STATIC_LOCAL(AtomicString, timesStr, ("Times"));
+
+ // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick
+ // the default that the user would get without changing any prefs.
+ SimpleFontData* simpleFontData = getCachedFontData(fontDescription, timesStr);
+ if (simpleFontData)
+ return simpleFontData;
+
+ // The Times fallback will almost always work, but in the highly unusual case where
+ // the user doesn't have it, we fall back on Lucida Grande because that's
+ // guaranteed to be there, according to Nathan Taylor. This is good enough
+ // to avoid a crash at least.
+ DEFINE_STATIC_LOCAL(AtomicString, lucidaGrandeStr, ("Lucida Grande"));
+ return getCachedFontData(fontDescription, lucidaGrandeStr);
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ [WebFontCache getTraits:traitsMasks inFamily:familyName];
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ NSFontTraitMask traits = fontDescription.italic() ? NSFontItalicTrait : 0;
+ NSInteger weight = toAppKitFontWeight(fontDescription.weight());
+ float size = fontDescription.computedPixelSize();
+
+ NSFont *nsFont = [WebFontCache fontWithFamily:family traits:traits weight:weight size:size];
+ if (!nsFont)
+ return 0;
+
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ NSFontTraitMask actualTraits = 0;
+ if (fontDescription.italic())
+ actualTraits = [fontManager traitsOfFont:nsFont];
+ NSInteger actualWeight = [fontManager weightOfFont:nsFont];
+
+ NSFont *platformFont = fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont];
+ bool syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight);
+ bool syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait);
+
+ return new FontPlatformData(platformFont, size, syntheticBold, syntheticOblique, fontDescription.orientation());
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp b/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp
new file mode 100644
index 0000000..ca006d9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "ComplexTextController.h"
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "SimpleFontData.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h,
+ int from, int to) const
+{
+ ComplexTextController controller(this, run);
+ controller.advance(from);
+ float beforeWidth = controller.runWidthSoFar();
+ controller.advance(to);
+ float afterWidth = controller.runWidthSoFar();
+
+ // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
+ if (run.rtl()) {
+ float totalWidth = controller.totalWidth();
+ return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
+ }
+
+ return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
+}
+
+float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
+{
+ float initialAdvance;
+
+ ComplexTextController controller(this, run, false, 0, forTextEmphasis);
+ controller.advance(from);
+ float beforeWidth = controller.runWidthSoFar();
+ controller.advance(to, &glyphBuffer);
+
+ if (glyphBuffer.isEmpty())
+ return 0;
+
+ float afterWidth = controller.runWidthSoFar();
+
+ if (run.rtl()) {
+ initialAdvance = controller.totalWidth() + controller.finalRoundingWidth() - afterWidth;
+ for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
+ glyphBuffer.swap(i, end);
+ } else
+ initialAdvance = beforeWidth;
+
+ return initialAdvance;
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+ // This glyph buffer holds our glyphs + advances + font data for each glyph.
+ GlyphBuffer glyphBuffer;
+
+ float startX = point.x() + getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer);
+
+ // We couldn't generate any glyphs for the run. Give up.
+ if (glyphBuffer.isEmpty())
+ return;
+
+ // Draw the glyph buffer now at the starting point returned in startX.
+ FloatPoint startPoint(startX, point.y());
+ drawGlyphBuffer(context, glyphBuffer, startPoint);
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
+{
+ GlyphBuffer glyphBuffer;
+ float initialAdvance = getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer, ForTextEmphasis);
+
+ if (glyphBuffer.isEmpty())
+ return;
+
+ drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+ ComplexTextController controller(this, run, true, fallbackFonts);
+ if (glyphOverflow) {
+ glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - ascent());
+ glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - descent());
+ glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX()));
+ glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth()));
+ }
+ return controller.totalWidth();
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float x, bool includePartialGlyphs) const
+{
+ ComplexTextController controller(this, run);
+ return controller.offsetForPosition(x, includePartialGlyphs);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..d04d0e4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "FontPlatformData.h"
+#include "OpenTypeSanitizer.h"
+#include "SharedBuffer.h"
+#include "WOFFFileFormat.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
+ if (m_atsContainer)
+ ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault);
+#endif
+ CGFontRelease(m_cgFont);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, FontRenderingMode)
+{
+ return FontPlatformData(m_cgFont, size, bold, italic, orientation);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+#if ENABLE(OPENTYPE_SANITIZER)
+ OpenTypeSanitizer sanitizer(buffer);
+ RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize();
+ if (!transcodeBuffer)
+ return 0; // validation failed.
+ buffer = transcodeBuffer.get();
+#else
+ RefPtr<SharedBuffer> sfntBuffer;
+ if (isWOFF(buffer)) {
+ Vector<char> sfnt;
+ if (!convertWOFFToSfnt(buffer, sfnt))
+ return 0;
+
+ sfntBuffer = SharedBuffer::adoptVector(sfnt);
+ buffer = sfntBuffer.get();
+ }
+#endif
+
+ ATSFontContainerRef containerRef = 0;
+
+ RetainPtr<CGFontRef> cgFontRef;
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ RetainPtr<CFDataRef> bufferData(AdoptCF, buffer->createCFData());
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(bufferData.get()));
+
+ cgFontRef.adoptCF(CGFontCreateWithDataProvider(dataProvider.get()));
+ if (!cgFontRef)
+ return 0;
+#else
+ // Use ATS to activate the font.
+
+ // The value "3" means that the font is private and can't be seen by anyone else.
+ ATSFontActivateFromMemory((void*)buffer->data(), buffer->size(), 3, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &containerRef);
+ if (!containerRef)
+ return 0;
+ ItemCount fontCount;
+ ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 0, NULL, &fontCount);
+
+ // We just support the first font in the list.
+ if (fontCount == 0) {
+ ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+ return 0;
+ }
+
+ ATSFontRef fontRef = 0;
+ ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1, &fontRef, NULL);
+ if (!fontRef) {
+ ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+ return 0;
+ }
+
+ cgFontRef.adoptCF(CGFontCreateWithPlatformFont(&fontRef));
+#ifndef BUILDING_ON_TIGER
+ // Workaround for <rdar://problem/5675504>.
+ if (cgFontRef && !CGFontGetNumberOfGlyphs(cgFontRef.get()))
+ cgFontRef = 0;
+#endif
+ if (!cgFontRef) {
+ ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+ return 0;
+ }
+#endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+
+ return new FontCustomPlatformData(containerRef, cgFontRef.releaseRef());
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype") || equalIgnoringCase(format, "woff");
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h
new file mode 100644
index 0000000..c11858c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include <CoreFoundation/CFBase.h>
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+typedef struct CGFont* CGFontRef;
+typedef UInt32 ATSFontContainerRef;
+typedef UInt32 ATSFontRef;
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(ATSFontContainerRef container, CGFontRef cgFont)
+ : m_atsContainer(container)
+ , m_cgFont(cgFont)
+ {
+ }
+
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+
+ static bool supportsFormat(const String&);
+
+ ATSFontContainerRef m_atsContainer;
+ CGFontRef m_cgFont;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/mac/FontMac.mm b/Source/WebCore/platform/graphics/mac/FontMac.mm
new file mode 100644
index 0000000..8519667
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/FontMac.mm
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#import "config.h"
+#import "Font.h"
+
+#import "GlyphBuffer.h"
+#import "GraphicsContext.h"
+#import "Logging.h"
+#import "SimpleFontData.h"
+#import "WebCoreSystemInterface.h"
+#import <AppKit/AppKit.h>
+
+#define SYNTHETIC_OBLIQUE_ANGLE 14
+
+#ifdef __LP64__
+#define URefCon void*
+#else
+#define URefCon UInt32
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return true;
+}
+
+static void showGlyphsWithAdvances(const SimpleFontData* font, CGContextRef context, const CGGlyph* glyphs, const CGSize* advances, size_t count)
+{
+ const FontPlatformData& platformData = font->platformData();
+ if (!platformData.isColorBitmapFont()) {
+ CGAffineTransform savedMatrix;
+ bool isVertical = font->orientation() == Vertical;
+
+ if (isVertical) {
+ CGAffineTransform rotateLeftTransform = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
+
+ savedMatrix = CGContextGetTextMatrix(context);
+ CGAffineTransform runMatrix = CGAffineTransformConcat(savedMatrix, rotateLeftTransform);
+ // Move start point to put glyphs into original region.
+ runMatrix.tx = savedMatrix.tx + font->ascent();
+ runMatrix.ty = savedMatrix.ty + font->descent();
+ CGContextSetTextMatrix(context, runMatrix);
+ }
+
+ CGContextShowGlyphsWithAdvances(context, glyphs, advances, count);
+
+ if (isVertical)
+ CGContextSetTextMatrix(context, savedMatrix);
+ }
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ else {
+ if (!count)
+ return;
+
+ Vector<CGPoint, 256> positions(count);
+ CGAffineTransform matrix = CGAffineTransformInvert(CGContextGetTextMatrix(context));
+ positions[0] = CGPointZero;
+ for (size_t i = 1; i < count; ++i) {
+ CGSize advance = CGSizeApplyAffineTransform(advances[i - 1], matrix);
+ positions[i].x = positions[i - 1].x + advance.width;
+ positions[i].y = positions[i - 1].y + advance.height;
+ }
+ CTFontDrawGlyphs(platformData.ctFont(), glyphs, positions.data(), count, context);
+ }
+#endif
+}
+
+void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
+{
+ CGContextRef cgContext = context->platformContext();
+
+ bool shouldSmoothFonts = true;
+ bool changeFontSmoothing = false;
+
+ switch(fontDescription().fontSmoothing()) {
+ case Antialiased: {
+ context->setShouldAntialias(true);
+ shouldSmoothFonts = false;
+ changeFontSmoothing = true;
+ break;
+ }
+ case SubpixelAntialiased: {
+ context->setShouldAntialias(true);
+ shouldSmoothFonts = true;
+ changeFontSmoothing = true;
+ break;
+ }
+ case NoSmoothing: {
+ context->setShouldAntialias(false);
+ shouldSmoothFonts = false;
+ changeFontSmoothing = true;
+ break;
+ }
+ case AutoSmoothing: {
+ // For the AutoSmooth case, don't do anything! Keep the default settings.
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ if (!shouldUseSmoothing()) {
+ shouldSmoothFonts = false;
+ changeFontSmoothing = true;
+ }
+
+ bool originalShouldUseFontSmoothing = false;
+ if (changeFontSmoothing) {
+ originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext);
+ CGContextSetShouldSmoothFonts(cgContext, shouldSmoothFonts);
+ }
+
+ const FontPlatformData& platformData = font->platformData();
+ NSFont* drawFont;
+ if (!isPrinterFont()) {
+ drawFont = [platformData.font() screenFont];
+ if (drawFont != platformData.font())
+ // We are getting this in too many places (3406411); use ERROR so it only prints on debug versions for now. (We should debug this also, eventually).
+ LOG_ERROR("Attempting to set non-screen font (%@) when drawing to screen. Using screen font anyway, may result in incorrect metrics.",
+ [[[platformData.font() fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
+ } else {
+ drawFont = [platformData.font() printerFont];
+ if (drawFont != platformData.font())
+ NSLog(@"Attempting to set non-printer font (%@) when printing. Using printer font anyway, may result in incorrect metrics.",
+ [[[platformData.font() fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
+ }
+
+ CGContextSetFont(cgContext, platformData.cgFont());
+
+ CGAffineTransform matrix = CGAffineTransformIdentity;
+ if (drawFont && !platformData.isColorBitmapFont())
+ memcpy(&matrix, [drawFont matrix], sizeof(matrix));
+ matrix.b = -matrix.b;
+ matrix.d = -matrix.d;
+ if (platformData.m_syntheticOblique)
+ matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0));
+ CGContextSetTextMatrix(cgContext, matrix);
+
+ if (drawFont) {
+ wkSetCGFontRenderingMode(cgContext, drawFont);
+ CGContextSetFontSize(cgContext, 1.0f);
+ } else
+ CGContextSetFontSize(cgContext, platformData.m_size);
+
+
+ FloatSize shadowOffset;
+ float shadowBlur;
+ Color shadowColor;
+ ColorSpace shadowColorSpace;
+ ColorSpace fillColorSpace = context->fillColorSpace();
+ context->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
+
+ bool hasSimpleShadow = context->textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && !platformData.isColorBitmapFont() && (!context->shadowsIgnoreTransforms() || context->getCTM().isIdentityOrTranslationOrFlipped());
+ if (hasSimpleShadow) {
+ // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
+ context->clearShadow();
+ Color fillColor = context->fillColor();
+ Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
+ context->setFillColor(shadowFillColor, shadowColorSpace);
+ float shadowTextX = point.x() + shadowOffset.width();
+ // If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative.
+ float shadowTextY = point.y() + shadowOffset.height() * (context->shadowsIgnoreTransforms() ? -1 : 1);
+ CGContextSetTextPosition(cgContext, shadowTextX, shadowTextY);
+ showGlyphsWithAdvances(font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->syntheticBoldOffset()) {
+ CGContextSetTextPosition(cgContext, shadowTextX + font->syntheticBoldOffset(), shadowTextY);
+ showGlyphsWithAdvances(font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+ context->setFillColor(fillColor, fillColorSpace);
+ }
+
+ CGContextSetTextPosition(cgContext, point.x(), point.y());
+ showGlyphsWithAdvances(font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->syntheticBoldOffset()) {
+ CGContextSetTextPosition(cgContext, point.x() + font->syntheticBoldOffset(), point.y());
+ showGlyphsWithAdvances(font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+
+ if (hasSimpleShadow)
+ context->setShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
+
+ if (changeFontSmoothing)
+ CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp b/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp
new file mode 100644
index 0000000..5388c24
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+#include "Font.h"
+
+#include "SimpleFontData.h"
+#include "WebCoreSystemInterface.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+#ifndef BUILDING_ON_TIGER
+static bool shouldUseCoreText(UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ if (fontData->orientation() == Vertical && !fontData->isBrokenIdeographFont()) {
+ // Ideographs don't have a vertical variant.
+ for (unsigned i = 0; i < bufferLength; ++i) {
+ if (!Font::isCJKIdeograph(buffer[i]))
+ return true;
+ }
+ }
+
+ return false;
+}
+#endif
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ bool haveGlyphs = false;
+
+#ifndef BUILDING_ON_TIGER
+ if (!shouldUseCoreText(buffer, bufferLength, fontData)) {
+ Vector<CGGlyph, 512> glyphs(bufferLength);
+ wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
+ for (unsigned i = 0; i < length; ++i) {
+ if (!glyphs[i])
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyphs[i], fontData);
+ haveGlyphs = true;
+ }
+ }
+ } else {
+ // We ask CoreText for possible vertical variant glyphs
+ RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
+ RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0)));
+ RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get()));
+
+ CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
+ CFIndex runCount = CFArrayGetCount(runArray);
+
+ // Initialize glyph entries
+ for (unsigned index = 0; index < length; ++index)
+ setGlyphDataForIndex(offset + index, 0, 0);
+
+ Vector<CGGlyph, 512> glyphVector;
+ Vector<CFIndex, 512> indexVector;
+ bool done = false;
+ for (CFIndex r = 0; r < runCount && !done ; ++r) {
+ // CTLine could map characters over multiple fonts using its own font fallback list.
+ // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont().
+ CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
+ ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
+
+ CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
+ CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
+ RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0));
+ // Use CGFont here as CFEqual for CTFont counts all attributes for font.
+ if (CFEqual(fontData->platformData().cgFont(), runCGFont.get())) {
+ // This run uses the font we want. Extract glyphs.
+ CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
+ const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
+ if (!glyphs) {
+ glyphVector.resize(glyphCount);
+ CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
+ glyphs = glyphVector.data();
+ }
+ const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
+ if (!stringIndices) {
+ indexVector.resize(glyphCount);
+ CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
+ stringIndices = indexVector.data();
+ }
+
+ for (CFIndex i = 0; i < glyphCount; ++i) {
+ if (stringIndices[i] >= static_cast<CFIndex>(length)) {
+ done = true;
+ break;
+ }
+ if (glyphs[i]) {
+ setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData);
+ haveGlyphs = true;
+ }
+ }
+ }
+ }
+ }
+#else
+ // Use an array of long so we get good enough alignment.
+ long glyphVector[(GLYPH_VECTOR_SIZE + sizeof(long) - 1) / sizeof(long)];
+
+ OSStatus status = wkInitializeGlyphVector(GlyphPage::size, &glyphVector);
+ if (status != noErr)
+ // This should never happen, perhaps indicates a bad font! If it does the
+ // font substitution code will find an alternate font.
+ return false;
+
+ wkConvertCharToGlyphs(fontData->m_styleGroup, buffer, bufferLength, &glyphVector);
+
+ unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector);
+ if (numGlyphs != length) {
+ // This should never happen, perhaps indicates a bad font?
+ // If it does happen, the font substitution code will find an alternate font.
+ wkClearGlyphVector(&glyphVector);
+ return false;
+ }
+
+ ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector);
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = glyphRecord->glyphID;
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
+ }
+ wkClearGlyphVector(&glyphVector);
+#endif
+
+ return haveGlyphs;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm
new file mode 100644
index 0000000..321d0ef
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#import "BlockExceptions.h"
+
+#include "ANGLE/ShaderLang.h"
+#include "ArrayBuffer.h"
+#include "ArrayBufferView.h"
+#include "CanvasRenderingContext.h"
+#include <CoreGraphics/CGBitmapContext.h>
+#include "Extensions3DOpenGL.h"
+#include "Float32Array.h"
+#include "GraphicsContext.h"
+#include "HTMLCanvasElement.h"
+#include "ImageBuffer.h"
+#include "Int32Array.h"
+#include "NotImplemented.h"
+#include <OpenGL/CGLRenderers.h>
+#include <OpenGL/gl.h>
+#include "Uint8Array.h"
+#include "WebGLLayer.h"
+#include "WebGLObject.h"
+#include <wtf/UnusedParam.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBits, int depthBits, bool accelerated, bool supersample, bool closest)
+{
+ attribs.clear();
+
+ attribs.append(kCGLPFAColorSize);
+ attribs.append(static_cast<CGLPixelFormatAttribute>(colorBits));
+ attribs.append(kCGLPFADepthSize);
+ attribs.append(static_cast<CGLPixelFormatAttribute>(depthBits));
+
+ if (accelerated)
+ attribs.append(kCGLPFAAccelerated);
+ else {
+ attribs.append(kCGLPFARendererID);
+ attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLRendererGenericFloatID));
+ }
+
+ if (supersample)
+ attribs.append(kCGLPFASupersample);
+
+ if (closest)
+ attribs.append(kCGLPFAClosestPolicy);
+
+ attribs.append(static_cast<CGLPixelFormatAttribute>(0));
+}
+
+PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
+{
+ // This implementation doesn't currently support rendering directly to the HostWindow.
+ if (renderStyle == RenderDirectlyToHostWindow)
+ return 0;
+ RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, false));
+ return context->m_contextObj ? context.release() : 0;
+}
+
+GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, bool)
+ : m_currentWidth(0)
+ , m_currentHeight(0)
+ , m_attrs(attrs)
+ , m_contextObj(0)
+ , m_texture(0)
+ , m_fbo(0)
+ , m_depthStencilBuffer(0)
+ , m_boundFBO(0)
+ , m_multisampleFBO(0)
+ , m_multisampleDepthStencilBuffer(0)
+ , m_multisampleColorBuffer(0)
+{
+ UNUSED_PARAM(hostWindow);
+
+ Vector<CGLPixelFormatAttribute> attribs;
+ CGLPixelFormatObj pixelFormatObj = 0;
+ GLint numPixelFormats = 0;
+
+ // We will try:
+ //
+ // 1) 32 bit RGBA/32 bit depth/accelerated/supersampled
+ // 2) 32 bit RGBA/32 bit depth/accelerated
+ // 3) 32 bit RGBA/16 bit depth/accelerated
+ // 4) closest to 32 bit RGBA/16 bit depth/software renderer
+ //
+ // If none of that works, we simply fail and set m_contextObj to 0.
+
+ setPixelFormat(attribs, 32, 32, true, true, false);
+ CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
+ if (numPixelFormats == 0) {
+ setPixelFormat(attribs, 32, 32, true, false, false);
+ CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
+
+ if (numPixelFormats == 0) {
+ setPixelFormat(attribs, 32, 16, true, false, false);
+ CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
+
+ if (numPixelFormats == 0) {
+ setPixelFormat(attribs, 32, 16, false, false, true);
+ CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
+
+ if (numPixelFormats == 0) {
+ // Could not find an acceptable renderer - fail
+ return;
+ }
+ }
+ }
+ }
+
+ CGLError err = CGLCreateContext(pixelFormatObj, 0, &m_contextObj);
+ CGLDestroyPixelFormat(pixelFormatObj);
+
+ if (err != kCGLNoError || !m_contextObj) {
+ // Could not create the context - fail
+ m_contextObj = 0;
+ return;
+ }
+
+ // Set the current context to the one given to us.
+ CGLSetCurrentContext(m_contextObj);
+
+ validateAttributes();
+
+ // Create the WebGLLayer
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ m_webGLLayer.adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:this]);
+#ifndef NDEBUG
+ [m_webGLLayer.get() setName:@"WebGL Layer"];
+#endif
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ // create a texture to render into
+ ::glGenTextures(1, &m_texture);
+ ::glBindTexture(GL_TEXTURE_2D, m_texture);
+ ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ ::glBindTexture(GL_TEXTURE_2D, 0);
+
+ // create an FBO
+ ::glGenFramebuffersEXT(1, &m_fbo);
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+
+ m_boundFBO = m_fbo;
+ if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth))
+ ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer);
+
+ // create an multisample FBO
+ if (m_attrs.antialias) {
+ ::glGenFramebuffersEXT(1, &m_multisampleFBO);
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
+ m_boundFBO = m_multisampleFBO;
+ ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer);
+ if (m_attrs.stencil || m_attrs.depth)
+ ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
+ }
+
+ // ANGLE initialization.
+
+ TBuiltInResource ANGLEResources;
+
+ ANGLEResources.MaxVertexAttribs = 0;
+ getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs);
+ ANGLEResources.MaxVertexUniformVectors = 0;
+ getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors);
+ ANGLEResources.MaxVaryingVectors = 0;
+ getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors);
+ ANGLEResources.MaxVertexTextureImageUnits = 0;
+ getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits);
+ ANGLEResources.MaxCombinedTextureImageUnits = 0;
+ getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits);
+ ANGLEResources.MaxTextureImageUnits = 0;
+ getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits);
+ ANGLEResources.MaxFragmentUniformVectors = 0;
+ getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors);
+
+ // Always set to 1 for OpenGL ES.
+ ANGLEResources.MaxDrawBuffers = 1;
+
+ m_compiler.setResources(ANGLEResources);
+
+ ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
+ ::glEnable(GL_POINT_SPRITE);
+
+ ::glClearColor(0, 0, 0, 0);
+}
+
+GraphicsContext3D::~GraphicsContext3D()
+{
+ if (m_contextObj) {
+ CGLSetCurrentContext(m_contextObj);
+ ::glDeleteTextures(1, &m_texture);
+ if (m_attrs.antialias) {
+ ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer);
+ if (m_attrs.stencil || m_attrs.depth)
+ ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
+ ::glDeleteFramebuffersEXT(1, &m_multisampleFBO);
+ } else {
+ if (m_attrs.stencil || m_attrs.depth)
+ ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer);
+ }
+ ::glDeleteFramebuffersEXT(1, &m_fbo);
+ CGLSetCurrentContext(0);
+ CGLDestroyContext(m_contextObj);
+ }
+}
+
+void GraphicsContext3D::makeContextCurrent()
+{
+ if (!m_contextObj)
+ return;
+
+ CGLContextObj currentContext = CGLGetCurrentContext();
+ if (currentContext != m_contextObj)
+ CGLSetCurrentContext(m_contextObj);
+}
+
+bool GraphicsContext3D::isGLES2Compliant() const
+{
+ return false;
+}
+
+}
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/Source/WebCore/platform/graphics/mac/GraphicsContextMac.mm
new file mode 100644
index 0000000..6a4fa03
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/GraphicsContextMac.mm
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#import "config.h"
+#import "GraphicsContext.h"
+
+#import "GraphicsContextPlatformPrivateCG.h"
+#import <AppKit/AppKit.h>
+#import <wtf/StdLibExtras.h>
+
+#import "LocalCurrentGraphicsContext.h"
+#import "WebCoreSystemInterface.h"
+
+@class NSColor;
+
+// FIXME: More of this should use CoreGraphics instead of AppKit.
+// FIXME: More of this should move into GraphicsContextCG.cpp.
+
+namespace WebCore {
+
+// NSColor, NSBezierPath, and NSGraphicsContext
+// calls in this file are all exception-safe, so we don't block
+// exceptions for those.
+
+static void drawFocusRingToContext(CGContextRef context, CGPathRef focusRingPath, CGColorRef color, int radius)
+{
+#ifdef BUILDING_ON_TIGER
+ CGContextBeginTransparencyLayer(context, 0);
+#endif
+ CGContextBeginPath(context);
+ CGContextAddPath(context, focusRingPath);
+ wkDrawFocusRing(context, color, radius);
+#ifdef BUILDING_ON_TIGER
+ CGContextEndTransparencyLayer(context);
+#endif
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int /*offset*/, const Color& color)
+{
+ // FIXME: Use 'offset' for something? http://webkit.org/b/49909
+
+ if (paintingDisabled())
+ return;
+
+ int radius = (width - 1) / 2;
+ CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0;
+
+ drawFocusRingToContext(platformContext(), path.platformPath(), colorRef, radius);
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ int radius = (width - 1) / 2;
+ offset += radius;
+ CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0;
+
+ RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable());
+ unsigned rectCount = rects.size();
+ for (unsigned i = 0; i < rectCount; i++)
+ CGPathAddRect(focusRingPath.get(), 0, CGRectInset(rects[i], -offset, -offset));
+
+ drawFocusRingToContext(platformContext(), focusRingPath.get(), colorRef, radius);
+}
+
+#ifdef BUILDING_ON_TIGER // Post-Tiger's setPlatformCompositeOperation() is defined in GraphicsContextCG.cpp.
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [[NSGraphicsContext graphicsContextWithGraphicsPort:platformContext() flipped:YES]
+ setCompositingOperation:(NSCompositingOperation)op];
+ [pool drain];
+}
+#endif
+
+static NSColor* createPatternColor(NSString* name, NSColor* defaultColor, bool& usingDot)
+{
+ NSImage *image = [NSImage imageNamed:name];
+ ASSERT(image); // if image is not available, we want to know
+ NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil);
+ if (color)
+ usingDot = true;
+ else
+ color = defaultColor;
+ return color;
+}
+
+// WebKit on Mac is a standard platform component, so it must use the standard platform artwork for underline.
+void GraphicsContext::drawLineForTextChecking(const IntPoint& point, int width, TextCheckingLineStyle style)
+{
+ if (paintingDisabled())
+ return;
+
+ // These are the same for misspelling or bad grammar.
+ int patternHeight = cMisspellingLineThickness;
+ int patternWidth = cMisspellingLinePatternWidth;
+
+ bool usingDot;
+ NSColor *patternColor;
+ switch (style) {
+ case TextCheckingSpellingLineStyle:
+ {
+ // Constants for spelling pattern color.
+ static bool usingDotForSpelling = false;
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"SpellingDot", [NSColor redColor], usingDotForSpelling)));
+ usingDot = usingDotForSpelling;
+ patternColor = spellingPatternColor.get();
+ break;
+ }
+ case TextCheckingGrammarLineStyle:
+ {
+ // Constants for grammar pattern color.
+ static bool usingDotForGrammar = false;
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, grammarPatternColor, (createPatternColor(@"GrammarDot", [NSColor greenColor], usingDotForGrammar)));
+ usingDot = usingDotForGrammar;
+ patternColor = grammarPatternColor.get();
+ break;
+ }
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ // To support correction panel.
+ case TextCheckingReplacementLineStyle:
+ {
+ // Constants for spelling pattern color.
+ static bool usingDotForSpelling = false;
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"CorrectionDot", [NSColor blueColor], usingDotForSpelling)));
+ usingDot = usingDotForSpelling;
+ patternColor = spellingPatternColor.get();
+ break;
+ }
+#endif
+ default:
+ return;
+ }
+
+ // Make sure to draw only complete dots.
+ // NOTE: Code here used to shift the underline to the left and increase the width
+ // to make sure everything gets underlined, but that results in drawing out of
+ // bounds (e.g. when at the edge of a view) and could make it appear that the
+ // space between adjacent misspelled words was underlined.
+ if (usingDot) {
+ // allow slightly more considering that the pattern ends with a transparent pixel
+ int widthMod = width % patternWidth;
+ if (patternWidth - widthMod > cMisspellingLinePatternGapWidth)
+ width -= widthMod;
+ }
+
+ // FIXME: This code should not use NSGraphicsContext currentContext
+ // In order to remove this requirement we will need to use CGPattern instead of NSColor
+ // FIXME: This code should not be using wkSetPatternPhaseInUserSpace, as this approach is wrong
+ // for transforms.
+
+ // Draw underline.
+ LocalCurrentGraphicsContext localContext(this);
+ NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
+ CGContextRef context = (CGContextRef)[currentContext graphicsPort];
+ CGContextSaveGState(context);
+
+ [patternColor set];
+
+ wkSetPatternPhaseInUserSpace(context, point);
+
+ NSRectFillUsingOperation(NSMakeRect(point.x(), point.y(), width, patternHeight), NSCompositeSourceOver);
+
+ CGContextRestoreGState(context);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/IconMac.mm b/Source/WebCore/platform/graphics/mac/IconMac.mm
new file mode 100644
index 0000000..bc8c312
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/IconMac.mm
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#import "config.h"
+#import "Icon.h"
+
+#import "GraphicsContext.h"
+#import "LocalCurrentGraphicsContext.h"
+#import "PlatformString.h"
+#import <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+Icon::Icon(NSImage *image)
+ : m_nsImage(image)
+{
+ // Need this because WebCore uses AppKit's flipped coordinate system exclusively.
+ [image setFlipped:YES];
+}
+
+Icon::~Icon()
+{
+}
+
+// FIXME: Move the code to ChromeClient::iconForFiles().
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ if (filenames.isEmpty())
+ return 0;
+
+ bool useIconFromFirstFile;
+#ifdef BUILDING_ON_TIGER
+ // FIXME: find a better image for multiple files to use on Tiger.
+ useIconFromFirstFile = true;
+#else
+ useIconFromFirstFile = filenames.size() == 1;
+#endif
+ if (useIconFromFirstFile) {
+ // Don't pass relative filenames -- we don't want a result that depends on the current directory.
+ // Need 0U here to disambiguate String::operator[] from operator(NSString*, int)[]
+ if (filenames[0].isEmpty() || filenames[0][0U] != '/')
+ return 0;
+
+ NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filenames[0]];
+ if (!image)
+ return 0;
+
+ return adoptRef(new Icon(image));
+ }
+#ifdef BUILDING_ON_TIGER
+ return 0;
+#else
+ NSImage* image = [NSImage imageNamed:NSImageNameMultipleDocuments];
+ if (!image)
+ return 0;
+
+ return adoptRef(new Icon(image));
+#endif
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (context->paintingDisabled())
+ return;
+
+ LocalCurrentGraphicsContext localCurrentGC(context);
+
+ [m_nsImage.get() drawInRect:rect
+ fromRect:NSMakeRect(0, 0, [m_nsImage.get() size].width, [m_nsImage.get() size].height)
+ operation:NSCompositeSourceOver fraction:1.0f];
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/ImageMac.mm b/Source/WebCore/platform/graphics/mac/ImageMac.mm
new file mode 100644
index 0000000..6ad3080
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/ImageMac.mm
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#import "config.h"
+#import "BitmapImage.h"
+
+#import "FloatRect.h"
+#import "GraphicsContext.h"
+#import "PlatformString.h"
+#import "SharedBuffer.h"
+
+@interface WebCoreBundleFinder : NSObject
+@end
+
+@implementation WebCoreBundleFinder
+@end
+
+namespace WebCore {
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+ if (m_frames.size() != 1)
+ return;
+
+ m_nsImage = 0;
+ m_tiffRep = 0;
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ NSBundle *bundle = [NSBundle bundleForClass:[WebCoreBundleFinder class]];
+ NSString *imagePath = [bundle pathForResource:[NSString stringWithUTF8String:name] ofType:@"tiff"];
+ NSData *namedImageData = [NSData dataWithContentsOfFile:imagePath];
+ if (namedImageData) {
+ RefPtr<Image> image = BitmapImage::create();
+ image->setData(SharedBuffer::wrapNSData(namedImageData), true);
+ return image.release();
+ }
+
+ // We have reports indicating resource loads are failing, but we don't yet know the root cause(s).
+ // Two theories are bad installs (image files are missing), and too-many-open-files.
+ // See rdar://5607381
+ ASSERT_NOT_REACHED();
+ return Image::nullImage();
+}
+
+CFDataRef BitmapImage::getTIFFRepresentation()
+{
+ if (m_tiffRep)
+ return m_tiffRep.get();
+
+ unsigned numFrames = frameCount();
+
+ // If numFrames is zero, we know for certain this image doesn't have valid data
+ // Even though the call to CGImageDestinationCreateWithData will fail and we'll handle it gracefully,
+ // in certain circumstances that call will spam the console with an error message
+ if (!numFrames)
+ return 0;
+
+ Vector<CGImageRef> images;
+ for (unsigned i = 0; i < numFrames; ++i ) {
+ CGImageRef cgImage = frameAtIndex(i);
+ if (cgImage)
+ images.append(cgImage);
+ }
+
+ unsigned numValidFrames = images.size();
+
+ RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, 0));
+ // FIXME: Use type kCGImageTypeIdentifierTIFF constant once is becomes available in the API
+ RetainPtr<CGImageDestinationRef> destination(AdoptCF, CGImageDestinationCreateWithData(data.get(), CFSTR("public.tiff"), numValidFrames, 0));
+
+ if (!destination)
+ return 0;
+
+ for (unsigned i = 0; i < numValidFrames; ++i)
+ CGImageDestinationAddImage(destination.get(), images[i], 0);
+
+ CGImageDestinationFinalize(destination.get());
+
+ m_tiffRep = data;
+ return m_tiffRep.get();
+}
+
+NSImage* BitmapImage::getNSImage()
+{
+ if (m_nsImage)
+ return m_nsImage.get();
+
+ CFDataRef data = getTIFFRepresentation();
+ if (!data)
+ return 0;
+
+ m_nsImage.adoptNS([[NSImage alloc] initWithData:(NSData*)data]);
+ return m_nsImage.get();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/IntPointMac.mm b/Source/WebCore/platform/graphics/mac/IntPointMac.mm
new file mode 100644
index 0000000..7a2e730
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/IntPointMac.mm
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+IntPoint::IntPoint(const NSPoint& p) : m_x(static_cast<int>(p.x)), m_y(static_cast<int>(p.y))
+{
+}
+
+IntPoint::operator NSPoint() const
+{
+ return NSMakePoint(m_x, m_y);
+}
+
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/IntRectMac.mm b/Source/WebCore/platform/graphics/mac/IntRectMac.mm
new file mode 100644
index 0000000..738618a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/IntRectMac.mm
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+IntRect::operator NSRect() const
+{
+ return NSMakeRect(x(), y(), width(), height());
+}
+
+IntRect enclosingIntRect(const NSRect& rect)
+{
+ int l = static_cast<int>(floorf(rect.origin.x));
+ int t = static_cast<int>(floorf(rect.origin.y));
+ int r = static_cast<int>(ceilf(NSMaxX(rect)));
+ int b = static_cast<int>(ceilf(NSMaxY(rect)));
+ return IntRect(l, t, r - l, b - t);
+}
+
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/IntSizeMac.mm b/Source/WebCore/platform/graphics/mac/IntSizeMac.mm
new file mode 100644
index 0000000..c7dcd88
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/IntSizeMac.mm
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntSize.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+IntSize::IntSize(const NSSize& s) : m_width(static_cast<int>(s.width)), m_height(static_cast<int>(s.height))
+{
+}
+
+IntSize::operator NSSize() const
+{
+ return NSMakeSize(m_width, m_height);
+}
+
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
new file mode 100644
index 0000000..95ab456
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 MediaPlayerPrivateQTKit_h
+#define MediaPlayerPrivateQTKit_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayerPrivate.h"
+#include "Timer.h"
+#include "FloatSize.h"
+#include <wtf/RetainPtr.h>
+
+#ifdef __OBJC__
+#import <QTKit/QTTime.h>
+@class QTMovie;
+@class QTMovieView;
+@class QTMovieLayer;
+@class QTVideoRendererWebKitOnly;
+@class WebCoreMovieObserver;
+#else
+class QTMovie;
+class QTMovieView;
+class QTTime;
+class QTMovieLayer;
+class QTVideoRendererWebKitOnly;
+class WebCoreMovieObserver;
+#endif
+
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
+namespace WebCore {
+
+class MediaPlayerPrivateQTKit : public MediaPlayerPrivateInterface {
+public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+
+ void repaint();
+ void loadStateChanged();
+ void rateChanged();
+ void sizeChanged();
+ void timeChanged();
+ void didEnd();
+
+private:
+ MediaPlayerPrivateQTKit(MediaPlayer*);
+ ~MediaPlayerPrivateQTKit();
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
+ PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+ bool hasAudio() const;
+ bool supportsFullscreen() const;
+
+ void load(const String& url);
+ void cancelLoad();
+ void loadInternal(const String& url);
+ void resumeLoad();
+
+ void play();
+ void pause();
+ void prepareToPlay();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float time);
+
+ void setRate(float);
+ void setVolume(float);
+ void setPreservesPitch(bool);
+
+ bool hasClosedCaptions() const;
+ void setClosedCaptionsVisible(bool);
+
+ void setPreload(MediaPlayer::Preload);
+
+ MediaPlayer::NetworkState networkState() const { return m_networkState; }
+ MediaPlayer::ReadyState readyState() const { return m_readyState; }
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setSize(const IntSize&);
+
+ virtual bool hasAvailableVideoFrame() const;
+
+ void paint(GraphicsContext*, const IntRect&);
+ void paintCurrentFrameInContext(GraphicsContext*, const IntRect&);
+ virtual void prepareForRendering();
+
+
+#if USE(ACCELERATED_COMPOSITING)
+ bool supportsAcceleratedRendering() const;
+ void acceleratedRenderingStateChanged();
+#endif
+
+ bool hasSingleSecurityOrigin() const;
+ MediaPlayer::MovieLoadType movieLoadType() const;
+
+ void createQTMovie(const String& url);
+ void createQTMovie(NSURL *, NSDictionary *movieAttributes);
+
+ enum MediaRenderingMode { MediaRenderingNone, MediaRenderingMovieView, MediaRenderingSoftwareRenderer, MediaRenderingMovieLayer };
+ MediaRenderingMode currentRenderingMode() const;
+ MediaRenderingMode preferredRenderingMode() const;
+
+ void setUpVideoRendering();
+ void tearDownVideoRendering();
+ bool hasSetUpVideoRendering() const;
+
+ void createQTMovieView();
+ void detachQTMovieView();
+
+ enum QTVideoRendererMode { QTVideoRendererModeDefault, QTVideoRendererModeListensForNewImages };
+ void createQTVideoRenderer(QTVideoRendererMode rendererMode);
+ void destroyQTVideoRenderer();
+
+ void createQTMovieLayer();
+ void destroyQTMovieLayer();
+
+ QTTime createQTTime(float time) const;
+
+ void updateStates();
+ void doSeek();
+ void cancelSeek();
+ void seekTimerFired(Timer<MediaPlayerPrivateQTKit>*);
+ float maxTimeLoaded() const;
+ void disableUnsupportedTracks();
+
+ void sawUnsupportedTracks();
+ void cacheMovieScale();
+ bool metaDataAvailable() const { return m_qtMovie && m_readyState >= MediaPlayer::HaveMetadata; }
+
+ bool isReadyForVideoSetup() const;
+
+ virtual float mediaTimeForTimeValue(float) const;
+
+ virtual double maximumDurationToCacheMediaTime() const { return 5; }
+
+ MediaPlayer* m_player;
+ RetainPtr<QTMovie> m_qtMovie;
+ RetainPtr<QTMovieView> m_qtMovieView;
+ RetainPtr<QTVideoRendererWebKitOnly> m_qtVideoRenderer;
+ RetainPtr<WebCoreMovieObserver> m_objcObserver;
+ String m_movieURL;
+ float m_seekTo;
+ Timer<MediaPlayerPrivateQTKit> m_seekTimer;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ IntRect m_rect;
+ FloatSize m_scaleFactor;
+ unsigned m_enabledTrackCount;
+ unsigned m_totalTrackCount;
+ float m_reportedDuration;
+ float m_cachedDuration;
+ float m_timeToRestore;
+ RetainPtr<QTMovieLayer> m_qtVideoLayer;
+ MediaPlayer::Preload m_preload;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+ bool m_visible;
+ bool m_hasUnsupportedTracks;
+ bool m_videoFrameHasDrawn;
+ bool m_delayingLoad;
+ bool m_isAllowedToRender;
+#if DRAW_FRAME_RATE
+ int m_frameCountWhilePlaying;
+ double m_timeStartedPlaying;
+ double m_timeStoppedPlaying;
+#endif
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
new file mode 100644
index 0000000..2361f6a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -0,0 +1,1673 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#import "config.h"
+
+#if ENABLE(VIDEO)
+
+#import "MediaPlayerPrivateQTKit.h"
+
+#ifdef BUILDING_ON_TIGER
+#import "AutodrainedPool.h"
+#endif
+
+#import "BlockExceptions.h"
+#import "FrameView.h"
+#import "GraphicsContext.h"
+#import "KURL.h"
+#import "MIMETypeRegistry.h"
+#import "SoftLinking.h"
+#import "TimeRanges.h"
+#import "WebCoreSystemInterface.h"
+#import <QTKit/QTKit.h>
+#import <objc/objc-runtime.h>
+#import <wtf/UnusedParam.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayer.h"
+#endif
+
+#if DRAW_FRAME_RATE
+#import "Font.h"
+#import "Frame.h"
+#import "Document.h"
+#import "RenderObject.h"
+#import "RenderStyle.h"
+#endif
+
+#ifdef BUILDING_ON_TIGER
+static IMP method_setImplementation(Method m, IMP imp)
+{
+ IMP result = m->method_imp;
+ m->method_imp = imp;
+ return result;
+}
+#endif
+
+SOFT_LINK_FRAMEWORK(QTKit)
+
+SOFT_LINK(QTKit, QTMakeTime, QTTime, (long long timeValue, long timeScale), (timeValue, timeScale))
+
+SOFT_LINK_CLASS(QTKit, QTMovie)
+SOFT_LINK_CLASS(QTKit, QTMovieView)
+SOFT_LINK_CLASS(QTKit, QTMovieLayer)
+
+SOFT_LINK_POINTER(QTKit, QTTrackMediaTypeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeBase, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeMPEG, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeSound, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeText, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeVideo, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieAskUnresolvedDataRefsAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieLoopsAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieDataSizeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieDidEndNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieHasVideoAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieHasAudioAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieIsActiveAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieLoadStateAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieLoadStateDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieNaturalSizeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieCurrentSizeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMoviePreventExternalURLLinksAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieRateChangesPreservePitchAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieRateDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieSizeDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieTimeDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieTimeScaleAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieURLAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieVolumeDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTSecurityPolicyNoCrossSiteAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification, NSString *)
+#ifndef BUILDING_ON_TIGER
+SOFT_LINK_POINTER(QTKit, QTMovieApertureModeClean, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieApertureModeAttribute, NSString *)
+#endif
+
+#define QTMovie getQTMovieClass()
+#define QTMovieView getQTMovieViewClass()
+#define QTMovieLayer getQTMovieLayerClass()
+
+#define QTTrackMediaTypeAttribute getQTTrackMediaTypeAttribute()
+#define QTMediaTypeAttribute getQTMediaTypeAttribute()
+#define QTMediaTypeBase getQTMediaTypeBase()
+#define QTMediaTypeMPEG getQTMediaTypeMPEG()
+#define QTMediaTypeSound getQTMediaTypeSound()
+#define QTMediaTypeText getQTMediaTypeText()
+#define QTMediaTypeVideo getQTMediaTypeVideo()
+#define QTMovieAskUnresolvedDataRefsAttribute getQTMovieAskUnresolvedDataRefsAttribute()
+#define QTMovieLoopsAttribute getQTMovieLoopsAttribute()
+#define QTMovieDataSizeAttribute getQTMovieDataSizeAttribute()
+#define QTMovieDidEndNotification getQTMovieDidEndNotification()
+#define QTMovieHasVideoAttribute getQTMovieHasVideoAttribute()
+#define QTMovieHasAudioAttribute getQTMovieHasAudioAttribute()
+#define QTMovieIsActiveAttribute getQTMovieIsActiveAttribute()
+#define QTMovieLoadStateAttribute getQTMovieLoadStateAttribute()
+#define QTMovieLoadStateDidChangeNotification getQTMovieLoadStateDidChangeNotification()
+#define QTMovieNaturalSizeAttribute getQTMovieNaturalSizeAttribute()
+#define QTMovieCurrentSizeAttribute getQTMovieCurrentSizeAttribute()
+#define QTMoviePreventExternalURLLinksAttribute getQTMoviePreventExternalURLLinksAttribute()
+#define QTMovieRateChangesPreservePitchAttribute getQTMovieRateChangesPreservePitchAttribute()
+#define QTMovieRateDidChangeNotification getQTMovieRateDidChangeNotification()
+#define QTMovieSizeDidChangeNotification getQTMovieSizeDidChangeNotification()
+#define QTMovieTimeDidChangeNotification getQTMovieTimeDidChangeNotification()
+#define QTMovieTimeScaleAttribute getQTMovieTimeScaleAttribute()
+#define QTMovieURLAttribute getQTMovieURLAttribute()
+#define QTMovieVolumeDidChangeNotification getQTMovieVolumeDidChangeNotification()
+#define QTSecurityPolicyNoCrossSiteAttribute getQTSecurityPolicyNoCrossSiteAttribute()
+#define QTVideoRendererWebKitOnlyNewImageAvailableNotification getQTVideoRendererWebKitOnlyNewImageAvailableNotification()
+#ifndef BUILDING_ON_TIGER
+#define QTMovieApertureModeClean getQTMovieApertureModeClean()
+#define QTMovieApertureModeAttribute getQTMovieApertureModeAttribute()
+#endif
+
+// Older versions of the QTKit header don't have these constants.
+#if !defined QTKIT_VERSION_MAX_ALLOWED || QTKIT_VERSION_MAX_ALLOWED <= QTKIT_VERSION_7_0
+enum {
+ QTMovieLoadStateError = -1L,
+ QTMovieLoadStateLoaded = 2000L,
+ QTMovieLoadStatePlayable = 10000L,
+ QTMovieLoadStatePlaythroughOK = 20000L,
+ QTMovieLoadStateComplete = 100000L
+};
+#endif
+
+@interface FakeQTMovieView : NSObject
+- (WebCoreMovieObserver *)delegate;
+@end
+
+using namespace WebCore;
+using namespace std;
+
+@interface WebCoreMovieObserver : NSObject
+{
+ MediaPlayerPrivateQTKit* m_callback;
+ NSView* m_view;
+ BOOL m_delayCallbacks;
+}
+-(id)initWithCallback:(MediaPlayerPrivateQTKit*)callback;
+-(void)disconnect;
+-(void)setView:(NSView*)view;
+-(void)repaint;
+-(void)setDelayCallbacks:(BOOL)shouldDelay;
+-(void)loadStateChanged:(NSNotification *)notification;
+-(void)rateChanged:(NSNotification *)notification;
+-(void)sizeChanged:(NSNotification *)notification;
+-(void)timeChanged:(NSNotification *)notification;
+-(void)didEnd:(NSNotification *)notification;
+@end
+
+@protocol WebKitVideoRenderingDetails
+-(void)setMovie:(id)movie;
+-(void)drawInRect:(NSRect)rect;
+@end
+
+namespace WebCore {
+
+#ifdef BUILDING_ON_TIGER
+static const long minimumQuickTimeVersion = 0x07300000; // 7.3
+#endif
+
+
+MediaPlayerPrivateInterface* MediaPlayerPrivateQTKit::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivateQTKit(player);
+}
+
+void MediaPlayerPrivateQTKit::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+MediaPlayerPrivateQTKit::MediaPlayerPrivateQTKit(MediaPlayer* player)
+ : m_player(player)
+ , m_objcObserver(AdoptNS, [[WebCoreMovieObserver alloc] initWithCallback:this])
+ , m_seekTo(-1)
+ , m_seekTimer(this, &MediaPlayerPrivateQTKit::seekTimerFired)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_rect()
+ , m_scaleFactor(1, 1)
+ , m_enabledTrackCount(0)
+ , m_totalTrackCount(0)
+ , m_reportedDuration(-1)
+ , m_cachedDuration(-1)
+ , m_timeToRestore(-1)
+ , m_preload(MediaPlayer::Auto)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+ , m_visible(false)
+ , m_hasUnsupportedTracks(false)
+ , m_videoFrameHasDrawn(false)
+ , m_isAllowedToRender(false)
+#if DRAW_FRAME_RATE
+ , m_frameCountWhilePlaying(0)
+ , m_timeStartedPlaying(0)
+ , m_timeStoppedPlaying(0)
+#endif
+{
+}
+
+MediaPlayerPrivateQTKit::~MediaPlayerPrivateQTKit()
+{
+ tearDownVideoRendering();
+
+ [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
+ [m_objcObserver.get() disconnect];
+}
+
+void MediaPlayerPrivateQTKit::createQTMovie(const String& url)
+{
+ NSURL *cocoaURL = KURL(ParsedURLString, url);
+ NSMutableDictionary *movieAttributes = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ cocoaURL, QTMovieURLAttribute,
+ [NSNumber numberWithBool:m_player->preservesPitch()], QTMovieRateChangesPreservePitchAttribute,
+ [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute,
+ [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute,
+ [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute,
+ [NSNumber numberWithBool:NO], QTMovieLoopsAttribute,
+#ifndef BUILDING_ON_TIGER
+ QTMovieApertureModeClean, QTMovieApertureModeAttribute,
+#endif
+ nil];
+
+#if !defined(BUILDING_ON_LEOPARD)
+ CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
+ CFArrayRef proxiesForURL = CFNetworkCopyProxiesForURL((CFURLRef)cocoaURL, proxySettings);
+ BOOL willUseProxy = YES;
+
+ if (!proxiesForURL || !CFArrayGetCount(proxiesForURL))
+ willUseProxy = NO;
+
+ if (CFArrayGetCount(proxiesForURL) == 1) {
+ CFDictionaryRef proxy = (CFDictionaryRef)CFArrayGetValueAtIndex(proxiesForURL, 0);
+ ASSERT(CFGetTypeID(proxy) == CFDictionaryGetTypeID());
+
+ CFStringRef proxyType = (CFStringRef)CFDictionaryGetValue(proxy, kCFProxyTypeKey);
+ ASSERT(CFGetTypeID(proxyType) == CFStringGetTypeID());
+
+ if (CFStringCompare(proxyType, kCFProxyTypeNone, 0) == kCFCompareEqualTo)
+ willUseProxy = NO;
+ }
+
+ if (!willUseProxy) {
+ // Only pass the QTMovieOpenForPlaybackAttribute flag if there are no proxy servers, due
+ // to rdar://problem/7531776.
+ [movieAttributes setObject:[NSNumber numberWithBool:YES] forKey:@"QTMovieOpenForPlaybackAttribute"];
+ }
+
+ if (proxiesForURL)
+ CFRelease(proxiesForURL);
+ if (proxySettings)
+ CFRelease(proxySettings);
+#endif
+
+ createQTMovie(cocoaURL, movieAttributes);
+}
+
+static void disableComponentsOnce()
+{
+ static bool sComponentsDisabled = false;
+ if (sComponentsDisabled)
+ return;
+ sComponentsDisabled = true;
+
+ // eat/PDF and grip/PDF components must be disabled twice since they are registered twice
+ // with different flags. However, there is currently a bug in 64-bit QTKit (<rdar://problem/8378237>)
+ // which causes subsequent disable component requests of exactly the same type to be ignored if
+ // QTKitServer has not yet started. As a result, we must pass in exactly the flags we want to
+ // disable per component. As a failsafe, if in the future these flags change, we will disable the
+ // PDF components for a third time with a wildcard flags field:
+ uint32_t componentsToDisable[11][5] = {
+ {'eat ', 'TEXT', 'text', 0, 0},
+ {'eat ', 'TXT ', 'text', 0, 0},
+ {'eat ', 'utxt', 'text', 0, 0},
+ {'eat ', 'TEXT', 'tx3g', 0, 0},
+ {'eat ', 'PDF ', 'vide', 0x44802, 0},
+ {'eat ', 'PDF ', 'vide', 0x45802, 0},
+ {'eat ', 'PDF ', 'vide', 0, 0},
+ {'grip', 'PDF ', 'appl', 0x844a00, 0},
+ {'grip', 'PDF ', 'appl', 0x845a00, 0},
+ {'grip', 'PDF ', 'appl', 0, 0},
+ {'imdc', 'pdf ', 'appl', 0, 0},
+ };
+
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(componentsToDisable); ++i)
+ wkQTMovieDisableComponent(componentsToDisable[i]);
+}
+
+void MediaPlayerPrivateQTKit::createQTMovie(NSURL *url, NSDictionary *movieAttributes)
+{
+ disableComponentsOnce();
+
+ [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
+
+ bool recreating = false;
+ if (m_qtMovie) {
+ recreating = true;
+ destroyQTVideoRenderer();
+ m_qtMovie = 0;
+ }
+
+ // Disable rtsp streams for now, <rdar://problem/5693967>
+ if (protocolIs([url scheme], "rtsp"))
+ return;
+
+ NSError *error = nil;
+ m_qtMovie.adoptNS([[QTMovie alloc] initWithAttributes:movieAttributes error:&error]);
+
+ if (!m_qtMovie)
+ return;
+
+ [m_qtMovie.get() setVolume:m_player->volume()];
+
+ if (recreating && hasVideo())
+ createQTVideoRenderer(QTVideoRendererModeListensForNewImages);
+
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(loadStateChanged:)
+ name:QTMovieLoadStateDidChangeNotification
+ object:m_qtMovie.get()];
+
+ // In updateState(), we track when maxTimeLoaded() == duration().
+ // In newer version of QuickTime, a notification is emitted when maxTimeLoaded changes.
+ // In older version of QuickTime, QTMovieLoadStateDidChangeNotification be fired.
+ if (NSString *maxTimeLoadedChangeNotification = wkQTMovieMaxTimeLoadedChangeNotification()) {
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(loadStateChanged:)
+ name:maxTimeLoadedChangeNotification
+ object:m_qtMovie.get()];
+ }
+
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(rateChanged:)
+ name:QTMovieRateDidChangeNotification
+ object:m_qtMovie.get()];
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(sizeChanged:)
+ name:QTMovieSizeDidChangeNotification
+ object:m_qtMovie.get()];
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(timeChanged:)
+ name:QTMovieTimeDidChangeNotification
+ object:m_qtMovie.get()];
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(didEnd:)
+ name:QTMovieDidEndNotification
+ object:m_qtMovie.get()];
+}
+
+static void mainThreadSetNeedsDisplay(id self, SEL)
+{
+ id view = [self superview];
+ ASSERT(!view || [view isKindOfClass:[QTMovieView class]]);
+ if (!view || ![view isKindOfClass:[QTMovieView class]])
+ return;
+
+ FakeQTMovieView *movieView = static_cast<FakeQTMovieView *>(view);
+ WebCoreMovieObserver* delegate = [movieView delegate];
+ ASSERT(!delegate || [delegate isKindOfClass:[WebCoreMovieObserver class]]);
+ if (!delegate || ![delegate isKindOfClass:[WebCoreMovieObserver class]])
+ return;
+
+ [delegate repaint];
+}
+
+static Class QTVideoRendererClass()
+{
+ static Class QTVideoRendererWebKitOnlyClass = NSClassFromString(@"QTVideoRendererWebKitOnly");
+ return QTVideoRendererWebKitOnlyClass;
+}
+
+void MediaPlayerPrivateQTKit::createQTMovieView()
+{
+ detachQTMovieView();
+
+ static bool addedCustomMethods = false;
+ if (!m_player->inMediaDocument() && !addedCustomMethods) {
+ Class QTMovieContentViewClass = NSClassFromString(@"QTMovieContentView");
+ ASSERT(QTMovieContentViewClass);
+
+ Method mainThreadSetNeedsDisplayMethod = class_getInstanceMethod(QTMovieContentViewClass, @selector(_mainThreadSetNeedsDisplay));
+ ASSERT(mainThreadSetNeedsDisplayMethod);
+
+ method_setImplementation(mainThreadSetNeedsDisplayMethod, reinterpret_cast<IMP>(mainThreadSetNeedsDisplay));
+ addedCustomMethods = true;
+ }
+
+ // delay callbacks as we *will* get notifications during setup
+ [m_objcObserver.get() setDelayCallbacks:YES];
+
+ m_qtMovieView.adoptNS([[QTMovieView alloc] init]);
+ setSize(m_player->size());
+ NSView* parentView = m_player->frameView()->documentView();
+ [parentView addSubview:m_qtMovieView.get()];
+#ifdef BUILDING_ON_TIGER
+ // setDelegate: isn't a public call in Tiger, so use performSelector to keep the compiler happy
+ [m_qtMovieView.get() performSelector:@selector(setDelegate:) withObject:m_objcObserver.get()];
+#else
+ [m_qtMovieView.get() setDelegate:m_objcObserver.get()];
+#endif
+ [m_objcObserver.get() setView:m_qtMovieView.get()];
+ [m_qtMovieView.get() setMovie:m_qtMovie.get()];
+ [m_qtMovieView.get() setControllerVisible:NO];
+ [m_qtMovieView.get() setPreservesAspectRatio:NO];
+ // the area not covered by video should be transparent
+ [m_qtMovieView.get() setFillColor:[NSColor clearColor]];
+
+ // If we're in a media document, allow QTMovieView to render in its default mode;
+ // otherwise tell it to draw synchronously.
+ // Note that we expect mainThreadSetNeedsDisplay to be invoked only when synchronous drawing is requested.
+ if (!m_player->inMediaDocument())
+ wkQTMovieViewSetDrawSynchronously(m_qtMovieView.get(), YES);
+
+ [m_objcObserver.get() setDelayCallbacks:NO];
+}
+
+void MediaPlayerPrivateQTKit::detachQTMovieView()
+{
+ if (m_qtMovieView) {
+ [m_objcObserver.get() setView:nil];
+#ifdef BUILDING_ON_TIGER
+ // setDelegate: isn't a public call in Tiger, so use performSelector to keep the compiler happy
+ [m_qtMovieView.get() performSelector:@selector(setDelegate:) withObject:nil];
+#else
+ [m_qtMovieView.get() setDelegate:nil];
+#endif
+ [m_qtMovieView.get() removeFromSuperview];
+ m_qtMovieView = nil;
+ }
+}
+
+void MediaPlayerPrivateQTKit::createQTVideoRenderer(QTVideoRendererMode rendererMode)
+{
+ destroyQTVideoRenderer();
+
+ m_qtVideoRenderer.adoptNS([[QTVideoRendererClass() alloc] init]);
+ if (!m_qtVideoRenderer)
+ return;
+
+ // associate our movie with our instance of QTVideoRendererWebKitOnly
+ [(id<WebKitVideoRenderingDetails>)m_qtVideoRenderer.get() setMovie:m_qtMovie.get()];
+
+ if (rendererMode == QTVideoRendererModeListensForNewImages) {
+ // listen to QTVideoRendererWebKitOnly's QTVideoRendererWebKitOnlyNewImageDidBecomeAvailableNotification
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(newImageAvailable:)
+ name:QTVideoRendererWebKitOnlyNewImageAvailableNotification
+ object:m_qtVideoRenderer.get()];
+ }
+}
+
+void MediaPlayerPrivateQTKit::destroyQTVideoRenderer()
+{
+ if (!m_qtVideoRenderer)
+ return;
+
+ // stop observing the renderer's notifications before we toss it
+ [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()
+ name:QTVideoRendererWebKitOnlyNewImageAvailableNotification
+ object:m_qtVideoRenderer.get()];
+
+ // disassociate our movie from our instance of QTVideoRendererWebKitOnly
+ [(id<WebKitVideoRenderingDetails>)m_qtVideoRenderer.get() setMovie:nil];
+
+ m_qtVideoRenderer = nil;
+}
+
+void MediaPlayerPrivateQTKit::createQTMovieLayer()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!m_qtMovie)
+ return;
+
+ ASSERT(supportsAcceleratedRendering());
+
+ if (!m_qtVideoLayer) {
+ m_qtVideoLayer.adoptNS([[QTMovieLayer alloc] init]);
+ if (!m_qtVideoLayer)
+ return;
+
+ [m_qtVideoLayer.get() setMovie:m_qtMovie.get()];
+#ifndef NDEBUG
+ [(CALayer *)m_qtVideoLayer.get() setName:@"Video layer"];
+#endif
+ // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
+ }
+#endif
+}
+
+void MediaPlayerPrivateQTKit::destroyQTMovieLayer()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!m_qtVideoLayer)
+ return;
+
+ // disassociate our movie from our instance of QTMovieLayer
+ [m_qtVideoLayer.get() setMovie:nil];
+ m_qtVideoLayer = nil;
+#endif
+}
+
+MediaPlayerPrivateQTKit::MediaRenderingMode MediaPlayerPrivateQTKit::currentRenderingMode() const
+{
+ if (m_qtMovieView)
+ return MediaRenderingMovieView;
+
+ if (m_qtVideoLayer)
+ return MediaRenderingMovieLayer;
+
+ if (m_qtVideoRenderer)
+ return MediaRenderingSoftwareRenderer;
+
+ return MediaRenderingNone;
+}
+
+MediaPlayerPrivateQTKit::MediaRenderingMode MediaPlayerPrivateQTKit::preferredRenderingMode() const
+{
+ if (!m_player->frameView() || !m_qtMovie)
+ return MediaRenderingNone;
+
+ if (m_player->inMediaDocument() || !QTVideoRendererClass())
+ return MediaRenderingMovieView;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+void MediaPlayerPrivateQTKit::setUpVideoRendering()
+{
+ if (!isReadyForVideoSetup())
+ return;
+
+ MediaRenderingMode currentMode = currentRenderingMode();
+ MediaRenderingMode preferredMode = preferredRenderingMode();
+ if (currentMode == preferredMode && currentMode != MediaRenderingNone)
+ return;
+
+ if (currentMode != MediaRenderingNone)
+ tearDownVideoRendering();
+
+ switch (preferredMode) {
+ case MediaRenderingMovieView:
+ createQTMovieView();
+ break;
+ case MediaRenderingNone:
+ case MediaRenderingSoftwareRenderer:
+ createQTVideoRenderer(QTVideoRendererModeListensForNewImages);
+ break;
+ case MediaRenderingMovieLayer:
+ createQTMovieLayer();
+ break;
+ }
+
+ // If using a movie layer, inform the client so the compositing tree is updated.
+ if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+}
+
+void MediaPlayerPrivateQTKit::tearDownVideoRendering()
+{
+ if (m_qtMovieView)
+ detachQTMovieView();
+ if (m_qtVideoRenderer)
+ destroyQTVideoRenderer();
+ if (m_qtVideoLayer)
+ destroyQTMovieLayer();
+}
+
+bool MediaPlayerPrivateQTKit::hasSetUpVideoRendering() const
+{
+ return m_qtMovieView
+ || m_qtVideoLayer
+ || m_qtVideoRenderer;
+}
+
+QTTime MediaPlayerPrivateQTKit::createQTTime(float time) const
+{
+ if (!metaDataAvailable())
+ return QTMakeTime(0, 600);
+ long timeScale = [[m_qtMovie.get() attributeForKey:QTMovieTimeScaleAttribute] longValue];
+ return QTMakeTime(time * timeScale, timeScale);
+}
+
+void MediaPlayerPrivateQTKit::resumeLoad()
+{
+ m_delayingLoad = false;
+
+ if (!m_movieURL.isNull())
+ loadInternal(m_movieURL);
+}
+
+void MediaPlayerPrivateQTKit::load(const String& url)
+{
+ m_movieURL = url;
+
+ // If the element is not supposed to load any data return immediately because QTKit
+ // doesn't have API to throttle loading.
+ if (m_preload == MediaPlayer::None) {
+ m_delayingLoad = true;
+ return;
+ }
+
+ loadInternal(url);
+}
+
+void MediaPlayerPrivateQTKit::loadInternal(const String& url)
+{
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+ }
+ cancelSeek();
+ m_videoFrameHasDrawn = false;
+
+ [m_objcObserver.get() setDelayCallbacks:YES];
+
+ createQTMovie(url);
+
+ [m_objcObserver.get() loadStateChanged:nil];
+ [m_objcObserver.get() setDelayCallbacks:NO];
+}
+
+void MediaPlayerPrivateQTKit::prepareToPlay()
+{
+ if (!m_qtMovie || m_delayingLoad)
+ resumeLoad();
+}
+
+PlatformMedia MediaPlayerPrivateQTKit::platformMedia() const
+{
+ PlatformMedia pm;
+ pm.type = PlatformMedia::QTMovieType;
+ pm.media.qtMovie = m_qtMovie.get();
+ return pm;
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayerPrivateQTKit::platformLayer() const
+{
+ return m_qtVideoLayer.get();
+}
+#endif
+
+void MediaPlayerPrivateQTKit::play()
+{
+ if (!metaDataAvailable())
+ return;
+ m_startedPlaying = true;
+#if DRAW_FRAME_RATE
+ m_frameCountWhilePlaying = 0;
+#endif
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ [m_qtMovie.get() setRate:m_player->rate()];
+ [m_objcObserver.get() setDelayCallbacks:NO];
+}
+
+void MediaPlayerPrivateQTKit::pause()
+{
+ if (!metaDataAvailable())
+ return;
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate];
+#endif
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ [m_qtMovie.get() stop];
+ [m_objcObserver.get() setDelayCallbacks:NO];
+}
+
+float MediaPlayerPrivateQTKit::duration() const
+{
+ if (!metaDataAvailable())
+ return 0;
+
+ if (m_cachedDuration != -1.0f)
+ return m_cachedDuration;
+
+ QTTime time = [m_qtMovie.get() duration];
+ if (time.flags == kQTTimeIsIndefinite)
+ return numeric_limits<float>::infinity();
+ return static_cast<float>(time.timeValue) / time.timeScale;
+}
+
+float MediaPlayerPrivateQTKit::currentTime() const
+{
+ if (!metaDataAvailable())
+ return 0;
+ QTTime time = [m_qtMovie.get() currentTime];
+ return static_cast<float>(time.timeValue) / time.timeScale;
+}
+
+void MediaPlayerPrivateQTKit::seek(float time)
+{
+ // Nothing to do if we are already in the middle of a seek to the same time.
+ if (time == m_seekTo)
+ return;
+
+ cancelSeek();
+
+ if (!metaDataAvailable())
+ return;
+
+ if (time > duration())
+ time = duration();
+
+ m_seekTo = time;
+ if (maxTimeSeekable() >= m_seekTo)
+ doSeek();
+ else
+ m_seekTimer.start(0, 0.5f);
+}
+
+void MediaPlayerPrivateQTKit::doSeek()
+{
+ QTTime qttime = createQTTime(m_seekTo);
+ // setCurrentTime generates several event callbacks, update afterwards
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ float oldRate = [m_qtMovie.get() rate];
+
+ if (oldRate)
+ [m_qtMovie.get() setRate:0];
+ [m_qtMovie.get() setCurrentTime:qttime];
+
+ // restore playback only if not at end, otherwise QTMovie will loop
+ float timeAfterSeek = currentTime();
+ if (oldRate && timeAfterSeek < duration())
+ [m_qtMovie.get() setRate:oldRate];
+
+ cancelSeek();
+ [m_objcObserver.get() setDelayCallbacks:NO];
+}
+
+void MediaPlayerPrivateQTKit::cancelSeek()
+{
+ m_seekTo = -1;
+ m_seekTimer.stop();
+}
+
+void MediaPlayerPrivateQTKit::seekTimerFired(Timer<MediaPlayerPrivateQTKit>*)
+{
+ if (!metaDataAvailable()|| !seeking() || currentTime() == m_seekTo) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ return;
+ }
+
+ if (maxTimeSeekable() >= m_seekTo)
+ doSeek();
+ else {
+ MediaPlayer::NetworkState state = networkState();
+ if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ }
+ }
+}
+
+bool MediaPlayerPrivateQTKit::paused() const
+{
+ if (!metaDataAvailable())
+ return true;
+ return [m_qtMovie.get() rate] == 0;
+}
+
+bool MediaPlayerPrivateQTKit::seeking() const
+{
+ if (!metaDataAvailable())
+ return false;
+ return m_seekTo >= 0;
+}
+
+IntSize MediaPlayerPrivateQTKit::naturalSize() const
+{
+ if (!metaDataAvailable())
+ return IntSize();
+
+ // In spite of the name of this method, return QTMovieNaturalSizeAttribute transformed by the
+ // initial movie scale because the spec says intrinsic size is:
+ //
+ // ... the dimensions of the resource in CSS pixels after taking into account the resource's
+ // dimensions, aspect ratio, clean aperture, resolution, and so forth, as defined for the
+ // format used by the resource
+
+ NSSize naturalSize = [[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
+ return IntSize(naturalSize.width * m_scaleFactor.width(), naturalSize.height * m_scaleFactor.height());
+}
+
+bool MediaPlayerPrivateQTKit::hasVideo() const
+{
+ if (!metaDataAvailable())
+ return false;
+ return [[m_qtMovie.get() attributeForKey:QTMovieHasVideoAttribute] boolValue];
+}
+
+bool MediaPlayerPrivateQTKit::hasAudio() const
+{
+ if (!m_qtMovie)
+ return false;
+ return [[m_qtMovie.get() attributeForKey:QTMovieHasAudioAttribute] boolValue];
+}
+
+bool MediaPlayerPrivateQTKit::supportsFullscreen() const
+{
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ return true;
+#else
+ // See <rdar://problem/7389945>
+ return false;
+#endif
+}
+
+void MediaPlayerPrivateQTKit::setVolume(float volume)
+{
+ if (m_qtMovie)
+ [m_qtMovie.get() setVolume:volume];
+}
+
+bool MediaPlayerPrivateQTKit::hasClosedCaptions() const
+{
+ if (!metaDataAvailable())
+ return false;
+ return wkQTMovieHasClosedCaptions(m_qtMovie.get());
+}
+
+void MediaPlayerPrivateQTKit::setClosedCaptionsVisible(bool closedCaptionsVisible)
+{
+ if (metaDataAvailable()) {
+ wkQTMovieSetShowClosedCaptions(m_qtMovie.get(), closedCaptionsVisible);
+
+#if USE(ACCELERATED_COMPOSITING) && (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
+ if (closedCaptionsVisible && m_qtVideoLayer) {
+ // Captions will be rendered upside down unless we flag the movie as flipped (again). See <rdar://7408440>.
+ [m_qtVideoLayer.get() setGeometryFlipped:YES];
+ }
+#endif
+ }
+}
+
+void MediaPlayerPrivateQTKit::setRate(float rate)
+{
+ if (m_qtMovie)
+ [m_qtMovie.get() setRate:rate];
+}
+
+void MediaPlayerPrivateQTKit::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_qtMovie)
+ return;
+
+ // QTMovieRateChangesPreservePitchAttribute cannot be changed dynamically after QTMovie creation.
+ // If the passed in value is different than what already exists, we need to recreate the QTMovie for it to take effect.
+ if ([[m_qtMovie.get() attributeForKey:QTMovieRateChangesPreservePitchAttribute] boolValue] == preservesPitch)
+ return;
+
+ RetainPtr<NSDictionary> movieAttributes(AdoptNS, [[m_qtMovie.get() movieAttributes] mutableCopy]);
+ ASSERT(movieAttributes);
+ [movieAttributes.get() setValue:[NSNumber numberWithBool:preservesPitch] forKey:QTMovieRateChangesPreservePitchAttribute];
+ m_timeToRestore = currentTime();
+
+ createQTMovie([movieAttributes.get() valueForKey:QTMovieURLAttribute], movieAttributes.get());
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivateQTKit::buffered() const
+{
+ RefPtr<TimeRanges> timeRanges = TimeRanges::create();
+ float loaded = maxTimeLoaded();
+ if (loaded > 0)
+ timeRanges->add(0, loaded);
+ return timeRanges.release();
+}
+
+float MediaPlayerPrivateQTKit::maxTimeSeekable() const
+{
+ if (!metaDataAvailable())
+ return 0;
+
+ // infinite duration means live stream
+ if (isinf(duration()))
+ return 0;
+
+ return wkQTMovieMaxTimeSeekable(m_qtMovie.get());
+}
+
+float MediaPlayerPrivateQTKit::maxTimeLoaded() const
+{
+ if (!metaDataAvailable())
+ return 0;
+ return wkQTMovieMaxTimeLoaded(m_qtMovie.get());
+}
+
+unsigned MediaPlayerPrivateQTKit::bytesLoaded() const
+{
+ float dur = duration();
+ if (!dur)
+ return 0;
+ return totalBytes() * maxTimeLoaded() / dur;
+}
+
+unsigned MediaPlayerPrivateQTKit::totalBytes() const
+{
+ if (!metaDataAvailable())
+ return 0;
+ return [[m_qtMovie.get() attributeForKey:QTMovieDataSizeAttribute] intValue];
+}
+
+void MediaPlayerPrivateQTKit::cancelLoad()
+{
+ // FIXME: Is there a better way to check for this?
+ if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
+ return;
+
+ tearDownVideoRendering();
+ m_qtMovie = nil;
+
+ updateStates();
+}
+
+void MediaPlayerPrivateQTKit::cacheMovieScale()
+{
+ NSSize initialSize = NSZeroSize;
+ NSSize naturalSize = [[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ // QTMovieCurrentSizeAttribute is not allowed with instances of QTMovie that have been
+ // opened with QTMovieOpenForPlaybackAttribute, so ask for the display transform attribute instead.
+ NSAffineTransform *displayTransform = [m_qtMovie.get() attributeForKey:@"QTMoviePreferredTransformAttribute"];
+ if (displayTransform)
+ initialSize = [displayTransform transformSize:naturalSize];
+ else {
+ initialSize.width = naturalSize.width;
+ initialSize.height = naturalSize.height;
+ }
+#else
+ initialSize = [[m_qtMovie.get() attributeForKey:QTMovieCurrentSizeAttribute] sizeValue];
+#endif
+
+ if (naturalSize.width)
+ m_scaleFactor.setWidth(initialSize.width / naturalSize.width);
+ if (naturalSize.height)
+ m_scaleFactor.setHeight(initialSize.height / naturalSize.height);
+}
+
+bool MediaPlayerPrivateQTKit::isReadyForVideoSetup() const
+{
+ return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
+}
+
+void MediaPlayerPrivateQTKit::prepareForRendering()
+{
+ if (m_isAllowedToRender)
+ return;
+ m_isAllowedToRender = true;
+
+ if (!hasSetUpVideoRendering())
+ setUpVideoRendering();
+
+ // If using a movie layer, inform the client so the compositing tree is updated. This is crucial if the movie
+ // has a poster, as it will most likely not have a layer and we will now be rendering frames to the movie layer.
+ if (currentRenderingMode() == MediaRenderingMovieLayer || preferredRenderingMode() == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+}
+
+void MediaPlayerPrivateQTKit::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError);
+
+ if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) {
+ disableUnsupportedTracks();
+ if (m_player->inMediaDocument()) {
+ if (!m_enabledTrackCount || m_hasUnsupportedTracks) {
+ // This has a type of media that we do not handle directly with a <video>
+ // element, eg. a rtsp track or QuickTime VR. Tell the MediaPlayerClient
+ // that we noticed.
+ sawUnsupportedTracks();
+ return;
+ }
+ } else if (!m_enabledTrackCount)
+ loadState = QTMovieLoadStateError;
+
+ if (loadState != QTMovieLoadStateError) {
+ wkQTMovieSelectPreferredAlternates(m_qtMovie.get());
+ cacheMovieScale();
+ MediaPlayer::MovieLoadType movieType = movieLoadType();
+ m_isStreaming = movieType == MediaPlayer::StoredStream || movieType == MediaPlayer::LiveStream;
+ }
+ }
+
+ // If this movie is reloading and we mean to restore the current time/rate, this might be the right time to do it.
+ if (loadState >= QTMovieLoadStateLoaded && oldNetworkState < MediaPlayer::Loaded && m_timeToRestore != -1.0f) {
+ QTTime qttime = createQTTime(m_timeToRestore);
+ m_timeToRestore = -1.0f;
+
+ // Disable event callbacks from setCurrentTime for restoring time in a recreated video
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ [m_qtMovie.get() setCurrentTime:qttime];
+ [m_qtMovie.get() setRate:m_player->rate()];
+ [m_objcObserver.get() setDelayCallbacks:NO];
+ }
+
+ BOOL completelyLoaded = !m_isStreaming && (loadState >= QTMovieLoadStateComplete);
+
+ // Note: QT indicates that we are fully loaded with QTMovieLoadStateComplete.
+ // However newer versions of QT do not, so we check maxTimeLoaded against duration.
+ if (!completelyLoaded && !m_isStreaming && metaDataAvailable())
+ completelyLoaded = maxTimeLoaded() == duration();
+
+ if (completelyLoaded) {
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ m_networkState = MediaPlayer::Loading;
+ } else if (loadState >= QTMovieLoadStatePlayable) {
+ // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+ m_networkState = MediaPlayer::Loading;
+ } else if (loadState >= QTMovieLoadStateLoaded) {
+ m_readyState = MediaPlayer::HaveMetadata;
+ m_networkState = MediaPlayer::Loading;
+ } else if (loadState > QTMovieLoadStateError) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_networkState = MediaPlayer::Loading;
+ } else {
+ // Loading or decoding failed.
+
+ if (m_player->inMediaDocument()) {
+ // Something went wrong in the loading of media within a standalone file.
+ // This can occur with chained refmovies pointing to streamed media.
+ sawUnsupportedTracks();
+ return;
+ }
+
+ float loaded = maxTimeLoaded();
+ if (!loaded)
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (!m_enabledTrackCount)
+ m_networkState = MediaPlayer::FormatError;
+ else {
+ // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
+ if (loaded > 0)
+ m_networkState = MediaPlayer::DecodeError;
+ else
+ m_readyState = MediaPlayer::HaveNothing;
+ }
+ }
+
+ if (isReadyForVideoSetup() && !hasSetUpVideoRendering())
+ setUpVideoRendering();
+
+ if (seeking())
+ m_readyState = m_readyState >= MediaPlayer::HaveMetadata ? MediaPlayer::HaveMetadata : MediaPlayer::HaveNothing;
+
+ // Streaming movies don't use the network when paused.
+ if (m_isStreaming && m_readyState >= MediaPlayer::HaveMetadata && m_networkState >= MediaPlayer::Loading && [m_qtMovie.get() rate] == 0)
+ m_networkState = MediaPlayer::Idle;
+
+ if (m_networkState != oldNetworkState)
+ m_player->networkStateChanged();
+
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+
+ if (loadState >= QTMovieLoadStateLoaded) {
+ float dur = duration();
+ if (dur != m_reportedDuration) {
+ if (m_reportedDuration != -1.0f)
+ m_player->durationChanged();
+ m_reportedDuration = dur;
+ }
+ }
+}
+
+void MediaPlayerPrivateQTKit::loadStateChanged()
+{
+ if (!m_hasUnsupportedTracks)
+ updateStates();
+}
+
+void MediaPlayerPrivateQTKit::rateChanged()
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ updateStates();
+ m_player->rateChanged();
+}
+
+void MediaPlayerPrivateQTKit::sizeChanged()
+{
+ if (!m_hasUnsupportedTracks)
+ m_player->sizeChanged();
+}
+
+void MediaPlayerPrivateQTKit::timeChanged()
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ // It may not be possible to seek to a specific time in a streamed movie. When seeking in a
+ // stream QuickTime sets the movie time to closest time possible and posts a timechanged
+ // notification. Update m_seekTo so we can detect when the seek completes.
+ if (m_seekTo != -1)
+ m_seekTo = currentTime();
+
+ m_timeToRestore = -1.0f;
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivateQTKit::didEnd()
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate];
+#endif
+
+ // Hang onto the current time and use it as duration from now on since QuickTime is telling us we
+ // are at the end. Do this because QuickTime sometimes reports one time for duration and stops
+ // playback at another time, which causes problems in HTMLMediaElement. QTKit's 'ended' event
+ // fires when playing in reverse so don't update duration when at time zero!
+ float now = currentTime();
+ if (now > 0)
+ m_cachedDuration = now;
+
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivateQTKit::setSize(const IntSize&)
+{
+ // Don't resize the view now because [view setFrame] also resizes the movie itself, and because
+ // the renderer calls this function immediately when we report a size change (QTMovieSizeDidChangeNotification)
+ // we can get into a feedback loop observing the size change and resetting the size, and this can cause
+ // QuickTime to miss resetting a movie's size when the media size changes (as happens with an rtsp movie
+ // once the rtsp server sends the track sizes). Instead we remember the size passed to paint() and resize
+ // the view when it changes.
+ // <rdar://problem/6336092> REGRESSION: rtsp movie does not resize correctly
+}
+
+void MediaPlayerPrivateQTKit::setVisible(bool b)
+{
+ if (m_visible != b) {
+ m_visible = b;
+ if (b)
+ setUpVideoRendering();
+ else
+ tearDownVideoRendering();
+ }
+}
+
+bool MediaPlayerPrivateQTKit::hasAvailableVideoFrame() const
+{
+ // When using a QTMovieLayer return true as soon as the movie reaches QTMovieLoadStatePlayable
+ // because although we don't *know* when the first frame has decoded, by the time we get and
+ // process the notification a frame should have propagated the VisualContext and been set on
+ // the layer.
+ if (currentRenderingMode() == MediaRenderingMovieLayer)
+ return m_readyState >= MediaPlayer::HaveCurrentData;
+
+ // When using the software renderer QuickTime signals that a frame is available so we might as well
+ // wait until we know that a frame has been drawn.
+ return m_videoFrameHasDrawn;
+}
+
+void MediaPlayerPrivateQTKit::repaint()
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+#if DRAW_FRAME_RATE
+ if (m_startedPlaying) {
+ m_frameCountWhilePlaying++;
+ // to eliminate preroll costs from our calculation,
+ // our frame rate calculation excludes the first frame drawn after playback starts
+ if (1==m_frameCountWhilePlaying)
+ m_timeStartedPlaying = [NSDate timeIntervalSinceReferenceDate];
+ }
+#endif
+ m_videoFrameHasDrawn = true;
+ m_player->repaint();
+}
+
+void MediaPlayerPrivateQTKit::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& r)
+{
+ id qtVideoRenderer = m_qtVideoRenderer.get();
+ if (!qtVideoRenderer && currentRenderingMode() == MediaRenderingMovieLayer) {
+ // We're being told to render into a context, but we already have the
+ // MovieLayer going. This probably means we've been called from <canvas>.
+ // Set up a QTVideoRenderer to use, but one that doesn't register for
+ // update callbacks. That way, it won't bother us asking to repaint.
+ createQTVideoRenderer(QTVideoRendererModeDefault);
+ qtVideoRenderer = m_qtVideoRenderer.get();
+ }
+ paint(context, r);
+}
+
+void MediaPlayerPrivateQTKit::paint(GraphicsContext* context, const IntRect& r)
+{
+ if (context->paintingDisabled() || m_hasUnsupportedTracks)
+ return;
+ NSView *view = m_qtMovieView.get();
+ id qtVideoRenderer = m_qtVideoRenderer.get();
+ if (!view && !qtVideoRenderer)
+ return;
+
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ context->save();
+ context->translate(r.x(), r.y() + r.height());
+ context->scale(FloatSize(1.0f, -1.0f));
+ context->setImageInterpolationQuality(InterpolationLow);
+ IntRect paintRect(IntPoint(0, 0), IntSize(r.width(), r.height()));
+
+#ifdef BUILDING_ON_TIGER
+ AutodrainedPool pool;
+#endif
+ NSGraphicsContext* newContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context->platformContext() flipped:NO];
+
+ // draw the current video frame
+ if (qtVideoRenderer) {
+ [NSGraphicsContext saveGraphicsState];
+ [NSGraphicsContext setCurrentContext:newContext];
+ [(id<WebKitVideoRenderingDetails>)qtVideoRenderer drawInRect:paintRect];
+ [NSGraphicsContext restoreGraphicsState];
+ } else {
+ if (m_rect != r) {
+ m_rect = r;
+ if (m_player->inMediaDocument()) {
+ // the QTMovieView needs to be placed in the proper location for document mode
+ [view setFrame:m_rect];
+ }
+ else {
+ // We don't really need the QTMovieView in any specific location so let's just get it out of the way
+ // where it won't intercept events or try to bring up the context menu.
+ IntRect farAwayButCorrectSize(m_rect);
+ farAwayButCorrectSize.move(-1000000, -1000000);
+ [view setFrame:farAwayButCorrectSize];
+ }
+ }
+
+ if (m_player->inMediaDocument()) {
+ // If we're using a QTMovieView in a media document, the view may get layer-backed. AppKit won't update
+ // the layer hosting correctly if we call displayRectIgnoringOpacity:inContext:, so use displayRectIgnoringOpacity:
+ // in this case. See <rdar://problem/6702882>.
+ [view displayRectIgnoringOpacity:paintRect];
+ } else
+ [view displayRectIgnoringOpacity:paintRect inContext:newContext];
+ }
+
+#if DRAW_FRAME_RATE
+ // Draw the frame rate only after having played more than 10 frames.
+ if (m_frameCountWhilePlaying > 10) {
+ Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : NULL;
+ Document* document = frame ? frame->document() : NULL;
+ RenderObject* renderer = document ? document->renderer() : NULL;
+ RenderStyle* styleToUse = renderer ? renderer->style() : NULL;
+ if (styleToUse) {
+ double frameRate = (m_frameCountWhilePlaying - 1) / ( m_startedPlaying ? ([NSDate timeIntervalSinceReferenceDate] - m_timeStartedPlaying) :
+ (m_timeStoppedPlaying - m_timeStartedPlaying) );
+ String text = String::format("%1.2f", frameRate);
+ TextRun textRun(text.characters(), text.length());
+ const Color color(255, 0, 0);
+ context->scale(FloatSize(1.0f, -1.0f));
+ context->setStrokeColor(color, styleToUse->colorSpace());
+ context->setStrokeStyle(SolidStroke);
+ context->setStrokeThickness(1.0f);
+ context->setFillColor(color, styleToUse->colorSpace());
+ context->drawText(styleToUse->font(), textRun, IntPoint(2, -3));
+ }
+ }
+#endif
+
+ context->restore();
+ END_BLOCK_OBJC_EXCEPTIONS;
+ [m_objcObserver.get() setDelayCallbacks:NO];
+}
+
+static void addFileTypesToCache(NSArray * fileTypes, HashSet<String> &cache)
+{
+ int count = [fileTypes count];
+ for (int n = 0; n < count; n++) {
+ CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]);
+ RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL));
+ if (!uti)
+ continue;
+ RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType));
+ if (mime)
+ cache.add(mime.get());
+
+ // -movieFileTypes: returns both file extensions and OSTypes. The later are surrounded by single
+ // quotes, eg. 'MooV', so don't bother looking at those.
+ if (CFStringGetCharacterAtIndex(ext, 0) != '\'') {
+ // UTI is missing many media related MIME types supported by QTKit (see rdar://6434168), and not all
+ // web servers use the MIME type UTI returns for an extension (see rdar://7875393), so even if UTI
+ // has a type for this extension add any types in hard coded table in the MIME type regsitry.
+ Vector<String> typesForExtension = MIMETypeRegistry::getMediaMIMETypesForExtension(ext);
+ unsigned count = typesForExtension.size();
+ for (unsigned ndx = 0; ndx < count; ++ndx) {
+ if (!cache.contains(typesForExtension[ndx]))
+ cache.add(typesForExtension[ndx]);
+ }
+ }
+ }
+}
+
+static HashSet<String> mimeCommonTypesCache()
+{
+ DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ typeListInitialized = true;
+ NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes];
+ addFileTypesToCache(fileTypes, cache);
+ }
+
+ return cache;
+}
+
+static HashSet<String> mimeModernTypesCache()
+{
+ DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ typeListInitialized = true;
+ NSArray* fileTypes = [QTMovie movieFileTypes:(QTMovieFileTypeOptions)wkQTIncludeOnlyModernMediaFileTypes()];
+ addFileTypesToCache(fileTypes, cache);
+ }
+
+ return cache;
+}
+
+void MediaPlayerPrivateQTKit::getSupportedTypes(HashSet<String>& supportedTypes)
+{
+ supportedTypes = mimeModernTypesCache();
+
+ // Note: this method starts QTKitServer if it isn't already running when in 64-bit because it has to return the list
+ // of every MIME type supported by QTKit.
+ HashSet<String> commonTypes = mimeCommonTypesCache();
+ HashSet<String>::const_iterator it = commonTypes.begin();
+ HashSet<String>::const_iterator end = commonTypes.end();
+ for (; it != end; ++it)
+ supportedTypes.add(*it);
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivateQTKit::supportsType(const String& type, const String& codecs)
+{
+ // Only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
+ // extended MIME type yet.
+
+ // We check the "modern" type cache first, as it doesn't require QTKitServer to start.
+ if (mimeModernTypesCache().contains(type) || mimeCommonTypesCache().contains(type))
+ return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
+
+ return MediaPlayer::IsNotSupported;
+}
+
+bool MediaPlayerPrivateQTKit::isAvailable()
+{
+#ifdef BUILDING_ON_TIGER
+ SInt32 version;
+ OSErr result;
+ result = Gestalt(gestaltQuickTime, &version);
+ if (result != noErr) {
+ LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support.");
+ return false;
+ }
+ if (version < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", version, minimumQuickTimeVersion);
+ return false;
+ }
+ return true;
+#else
+ // On 10.5 and higher, QuickTime will always be new enough for <video> and <audio> support, so we just check that the framework can be loaded.
+ return QTKitLibrary();
+#endif
+}
+
+void MediaPlayerPrivateQTKit::disableUnsupportedTracks()
+{
+ if (!m_qtMovie) {
+ m_enabledTrackCount = 0;
+ m_totalTrackCount = 0;
+ return;
+ }
+
+ static HashSet<String>* allowedTrackTypes = 0;
+ if (!allowedTrackTypes) {
+ allowedTrackTypes = new HashSet<String>;
+ allowedTrackTypes->add(QTMediaTypeVideo);
+ allowedTrackTypes->add(QTMediaTypeSound);
+ allowedTrackTypes->add(QTMediaTypeText);
+ allowedTrackTypes->add(QTMediaTypeBase);
+ allowedTrackTypes->add(QTMediaTypeMPEG);
+ allowedTrackTypes->add("clcp"); // Closed caption
+ allowedTrackTypes->add("sbtl"); // Subtitle
+ allowedTrackTypes->add("odsm"); // MPEG-4 object descriptor stream
+ allowedTrackTypes->add("sdsm"); // MPEG-4 scene description stream
+ allowedTrackTypes->add("tmcd"); // timecode
+ allowedTrackTypes->add("tc64"); // timcode-64
+ allowedTrackTypes->add("tmet"); // timed metadata
+ }
+
+ NSArray *tracks = [m_qtMovie.get() tracks];
+
+ m_totalTrackCount = [tracks count];
+ m_enabledTrackCount = m_totalTrackCount;
+ for (unsigned trackIndex = 0; trackIndex < m_totalTrackCount; trackIndex++) {
+ // Grab the track at the current index. If there isn't one there, then
+ // we can move onto the next one.
+ QTTrack *track = [tracks objectAtIndex:trackIndex];
+ if (!track)
+ continue;
+
+ // Check to see if the track is disabled already, we should move along.
+ // We don't need to re-disable it.
+ if (![track isEnabled]) {
+ --m_enabledTrackCount;
+ continue;
+ }
+
+ // Get the track's media type.
+ NSString *mediaType = [track attributeForKey:QTTrackMediaTypeAttribute];
+ if (!mediaType)
+ continue;
+
+ // Test whether the media type is in our white list.
+ if (!allowedTrackTypes->contains(mediaType)) {
+ // If this track type is not allowed, then we need to disable it.
+ [track setEnabled:NO];
+ --m_enabledTrackCount;
+ m_hasUnsupportedTracks = true;
+ }
+
+ // Disable chapter tracks. These are most likely to lead to trouble, as
+ // they will be composited under the video tracks, forcing QT to do extra
+ // work.
+ QTTrack *chapterTrack = [track performSelector:@selector(chapterlist)];
+ if (!chapterTrack)
+ continue;
+
+ // Try to grab the media for the track.
+ QTMedia *chapterMedia = [chapterTrack media];
+ if (!chapterMedia)
+ continue;
+
+ // Grab the media type for this track.
+ id chapterMediaType = [chapterMedia attributeForKey:QTMediaTypeAttribute];
+ if (!chapterMediaType)
+ continue;
+
+ // Check to see if the track is a video track. We don't care about
+ // other non-video tracks.
+ if (![chapterMediaType isEqual:QTMediaTypeVideo])
+ continue;
+
+ // Check to see if the track is already disabled. If it is, we
+ // should move along.
+ if (![chapterTrack isEnabled])
+ continue;
+
+ // Disable the evil, evil track.
+ [chapterTrack setEnabled:NO];
+ --m_enabledTrackCount;
+ m_hasUnsupportedTracks = true;
+ }
+}
+
+void MediaPlayerPrivateQTKit::sawUnsupportedTracks()
+{
+ m_hasUnsupportedTracks = true;
+ m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player);
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool MediaPlayerPrivateQTKit::supportsAcceleratedRendering() const
+{
+ // Also don't claim to support accelerated rendering when in the media document, as we will then render
+ // via QTMovieView which is already accelerated.
+ return isReadyForVideoSetup() && getQTMovieLayerClass() != Nil && !m_player->inMediaDocument();
+}
+
+void MediaPlayerPrivateQTKit::acceleratedRenderingStateChanged()
+{
+ // Set up or change the rendering path if necessary.
+ setUpVideoRendering();
+}
+#endif
+
+bool MediaPlayerPrivateQTKit::hasSingleSecurityOrigin() const
+{
+ // We tell quicktime to disallow resources that come from different origins
+ // so we know all media is single origin.
+ return true;
+}
+
+MediaPlayer::MovieLoadType MediaPlayerPrivateQTKit::movieLoadType() const
+{
+ if (!m_qtMovie)
+ return MediaPlayer::Unknown;
+
+ MediaPlayer::MovieLoadType movieType = (MediaPlayer::MovieLoadType)wkQTMovieGetType(m_qtMovie.get());
+
+ // Can't include WebKitSystemInterface from WebCore so we can't get the enum returned
+ // by wkQTMovieGetType, but at least verify that the value is in the valid range.
+ ASSERT(movieType >= MediaPlayer::Unknown && movieType <= MediaPlayer::LiveStream);
+
+ return movieType;
+}
+
+void MediaPlayerPrivateQTKit::setPreload(MediaPlayer::Preload preload)
+{
+ m_preload = preload;
+ if (m_delayingLoad && m_preload != MediaPlayer::None)
+ resumeLoad();
+}
+
+float MediaPlayerPrivateQTKit::mediaTimeForTimeValue(float timeValue) const
+{
+ if (!metaDataAvailable())
+ return timeValue;
+
+ QTTime qttime = createQTTime(timeValue);
+ return static_cast<float>(qttime.timeValue) / qttime.timeScale;
+}
+
+} // namespace WebCore
+
+@implementation WebCoreMovieObserver
+
+- (id)initWithCallback:(MediaPlayerPrivateQTKit*)callback
+{
+ m_callback = callback;
+ return [super init];
+}
+
+- (void)disconnect
+{
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ m_callback = 0;
+}
+
+-(NSMenu*)menuForEventDelegate:(NSEvent*)theEvent
+{
+ // Get the contextual menu from the QTMovieView's superview, the frame view
+ return [[m_view superview] menuForEvent:theEvent];
+}
+
+-(void)setView:(NSView*)view
+{
+ m_view = view;
+}
+
+-(void)repaint
+{
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0.];
+ else if (m_callback)
+ m_callback->repaint();
+}
+
+- (void)loadStateChanged:(NSNotification *)unusedNotification
+{
+ UNUSED_PARAM(unusedNotification);
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->loadStateChanged();
+}
+
+- (void)rateChanged:(NSNotification *)unusedNotification
+{
+ UNUSED_PARAM(unusedNotification);
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->rateChanged();
+}
+
+- (void)sizeChanged:(NSNotification *)unusedNotification
+{
+ UNUSED_PARAM(unusedNotification);
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->sizeChanged();
+}
+
+- (void)timeChanged:(NSNotification *)unusedNotification
+{
+ UNUSED_PARAM(unusedNotification);
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->timeChanged();
+}
+
+- (void)didEnd:(NSNotification *)unusedNotification
+{
+ UNUSED_PARAM(unusedNotification);
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->didEnd();
+}
+
+- (void)newImageAvailable:(NSNotification *)unusedNotification
+{
+ UNUSED_PARAM(unusedNotification);
+ [self repaint];
+}
+
+- (void)setDelayCallbacks:(BOOL)shouldDelay
+{
+ m_delayCallbacks = shouldDelay;
+}
+
+@end
+
+#endif
diff --git a/Source/WebCore/platform/graphics/mac/MediaPlayerProxy.h b/Source/WebCore/platform/graphics/mac/MediaPlayerProxy.h
new file mode 100644
index 0000000..cc7ec95
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/MediaPlayerProxy.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 MediaPlayerProxy_h
+#define MediaPlayerProxy_h
+
+#ifdef __OBJC__
+@class WebMediaPlayerProxy;
+#else
+class WebMediaPlayerProxy;
+#endif
+
+enum MediaPlayerProxyNotificationType {
+
+ MediaPlayerNotificationMediaValidated = 1,
+ MediaPlayerNotificationMediaFailedToValidate,
+
+ MediaPlayerNotificationStartUsingNetwork,
+ MediaPlayerNotificationStopUsingNetwork,
+
+ MediaPlayerNotificationEnteredFullscreen,
+ MediaPlayerNotificationExitedFullscreen,
+
+ MediaPlayerNotificationReadyForInspection,
+ MediaPlayerNotificationReadyForPlayback,
+ MediaPlayerNotificationDidPlayToTheEnd,
+
+ MediaPlayerNotificationPlaybackFailed,
+
+ MediaPlayerNotificationStreamLikelyToKeepUp,
+ MediaPlayerNotificationStreamUnlikelyToKeepUp,
+ MediaPlayerNotificationStreamBufferFull,
+ MediaPlayerNotificationStreamRanDry,
+ MediaPlayerNotificationFileLoaded,
+
+ MediaPlayerNotificationSizeDidChange,
+ MediaPlayerNotificationVolumeDidChange,
+ MediaPlayerNotificationMutedDidChange,
+ MediaPlayerNotificationTimeJumped,
+
+ MediaPlayerNotificationPlayPauseButtonPressed,
+};
+
+#ifdef __OBJC__
+@interface NSObject (WebMediaPlayerProxy)
+
+- (int)_interfaceVersion;
+
+- (void)_disconnect;
+
+- (void)_load:(NSURL *)url;
+- (void)_cancelLoad;
+
+- (void)_setPoster:(NSURL *)url;
+
+- (void)_play;
+- (void)_pause;
+
+- (NSSize)_naturalSize;
+
+- (BOOL)_hasVideo;
+- (BOOL)_hasAudio;
+
+- (NSTimeInterval)_duration;
+
+- (double)_currentTime;
+- (void)_setCurrentTime:(double)time;
+- (BOOL)_seeking;
+
+- (void)_setEndTime:(double)time;
+
+- (float)_rate;
+- (void)_setRate:(float)rate;
+
+- (float)_volume;
+- (void)_setVolume:(float)newVolume;
+
+- (BOOL)_muted;
+- (void)_setMuted:(BOOL)muted;
+
+- (float)_maxTimeBuffered;
+- (float)_maxTimeSeekable;
+- (NSArray *)_bufferedTimeRanges;
+
+- (int)_dataRate;
+
+- (BOOL)_totalBytesKnown;
+- (unsigned)_totalBytes;
+- (unsigned)_bytesLoaded;
+
+- (NSArray *)_mimeTypes;
+
+@end
+#endif
+
+#endif
diff --git a/Source/WebCore/platform/graphics/mac/SimpleFontDataATSUI.mm b/Source/WebCore/platform/graphics/mac/SimpleFontDataATSUI.mm
new file mode 100644
index 0000000..4b2e7b2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/SimpleFontDataATSUI.mm
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "SimpleFontData.h"
+
+#if USE(ATSUI)
+
+#import "Font.h"
+#import "FontCache.h"
+#import "FontDescription.h"
+#import <ApplicationServices/ApplicationServices.h>
+#import <AppKit/AppKit.h>
+#import <wtf/Assertions.h>
+
+using namespace std;
+
+namespace WebCore {
+
+void SimpleFontData::checkShapesArabic() const
+{
+ ASSERT(!m_checkedShapesArabic);
+
+ m_checkedShapesArabic = true;
+
+ ATSUFontID fontID = m_platformData.ctFont() ? CTFontGetPlatformFont(m_platformData.ctFont(), 0) : 0;
+ if (!fontID) {
+ LOG_ERROR("unable to get ATSUFontID for %@", m_platformData.font());
+ return;
+ }
+
+ // This function is called only on fonts that contain Arabic glyphs. Our
+ // heuristic is that if such a font has a glyph metamorphosis table, then
+ // it includes shaping information for Arabic.
+ FourCharCode tables[] = { 'morx', 'mort' };
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(tables); ++i) {
+ ByteCount tableSize;
+ OSStatus status = ATSFontGetTable(fontID, tables[i], 0, 0, 0, &tableSize);
+ if (status == noErr) {
+ m_shapesArabic = true;
+ return;
+ }
+
+ if (status != kATSInvalidFontTableAccess)
+ LOG_ERROR("ATSFontGetTable failed (%d)", status);
+ }
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/graphics/mac/SimpleFontDataCoreText.cpp b/Source/WebCore/platform/graphics/mac/SimpleFontDataCoreText.cpp
new file mode 100644
index 0000000..452bd54
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/SimpleFontDataCoreText.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "SimpleFontData.h"
+
+#import "Font.h"
+#import "FontCache.h"
+#import "FontDescription.h"
+#import <ApplicationServices/ApplicationServices.h>
+
+using namespace std;
+
+namespace WebCore {
+
+CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typesettingFeatures) const
+{
+ unsigned key = typesettingFeatures + 1;
+ pair<HashMap<unsigned, RetainPtr<CFDictionaryRef> >::iterator, bool> addResult = m_CFStringAttributes.add(key, RetainPtr<CFDictionaryRef>());
+ RetainPtr<CFDictionaryRef>& attributesDictionary = addResult.first->second;
+ if (!addResult.second)
+ return attributesDictionary.get();
+
+ bool allowLigatures = (orientation() == Horizontal && platformData().allowsLigatures()) || (typesettingFeatures & Ligatures);
+
+ static const int ligaturesNotAllowedValue = 0;
+ static CFNumberRef ligaturesNotAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesNotAllowedValue);
+
+ static const int ligaturesAllowedValue = 1;
+ static CFNumberRef ligaturesAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesAllowedValue);
+
+ if (!(typesettingFeatures & Kerning)) {
+ static const float kerningAdjustmentValue = 0;
+ static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue);
+ static const void* keysWithKerningDisabled[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName, kCTVerticalFormsAttributeName };
+ const void* valuesWithKerningDisabled[] = { platformData().ctFont(), kerningAdjustment, allowLigatures
+ ? ligaturesAllowed : ligaturesNotAllowed, orientation() == Vertical ? kCFBooleanTrue : kCFBooleanFalse };
+ attributesDictionary.adoptCF(CFDictionaryCreate(0, keysWithKerningDisabled, valuesWithKerningDisabled,
+ WTF_ARRAY_LENGTH(keysWithKerningDisabled), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ } else {
+ // By omitting the kCTKernAttributeName attribute, we get Core Text's standard kerning.
+ static const void* keysWithKerningEnabled[] = { kCTFontAttributeName, kCTLigatureAttributeName, kCTVerticalFormsAttributeName };
+ const void* valuesWithKerningEnabled[] = { platformData().ctFont(), allowLigatures ? ligaturesAllowed : ligaturesNotAllowed, orientation() == Vertical ? kCFBooleanTrue : kCFBooleanFalse };
+ attributesDictionary.adoptCF(CFDictionaryCreate(0, keysWithKerningEnabled, valuesWithKerningEnabled,
+ WTF_ARRAY_LENGTH(keysWithKerningEnabled), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ }
+
+ return attributesDictionary.get();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
new file mode 100644
index 0000000..92585c6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "SimpleFontData.h"
+
+#import "BlockExceptions.h"
+#import "Color.h"
+#import "FloatRect.h"
+#import "Font.h"
+#import "FontCache.h"
+#import "FontDescription.h"
+#import "SharedBuffer.h"
+#import "WebCoreSystemInterface.h"
+#import <AppKit/AppKit.h>
+#import <ApplicationServices/ApplicationServices.h>
+#import <float.h>
+#import <unicode/uchar.h>
+#import <wtf/Assertions.h>
+#import <wtf/StdLibExtras.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/UnusedParam.h>
+
+@interface NSFont (WebAppKitSecretAPI)
+- (BOOL)_isFakeFixedPitch;
+@end
+
+using namespace std;
+
+namespace WebCore {
+
+const float smallCapsFontSizeMultiplier = 0.7f;
+static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x / unitsPerEm; }
+
+static bool initFontData(SimpleFontData* fontData)
+{
+ if (!fontData->platformData().cgFont())
+ return false;
+
+#ifdef BUILDING_ON_TIGER
+ ATSUStyle fontStyle;
+ if (ATSUCreateStyle(&fontStyle) != noErr)
+ return false;
+
+ ATSUFontID fontId = fontData->platformData().m_atsuFontID;
+ if (!fontId) {
+ ATSUDisposeStyle(fontStyle);
+ return false;
+ }
+
+ ATSUAttributeTag tag = kATSUFontTag;
+ ByteCount size = sizeof(ATSUFontID);
+ ATSUFontID *valueArray[1] = {&fontId};
+ OSStatus status = ATSUSetAttributes(fontStyle, 1, &tag, &size, (void* const*)valueArray);
+ if (status != noErr) {
+ ATSUDisposeStyle(fontStyle);
+ return false;
+ }
+
+ if (wkGetATSStyleGroup(fontStyle, &fontData->m_styleGroup) != noErr) {
+ ATSUDisposeStyle(fontStyle);
+ return false;
+ }
+
+ ATSUDisposeStyle(fontStyle);
+#endif
+
+ return true;
+}
+
+static NSString *webFallbackFontFamily(void)
+{
+ DEFINE_STATIC_LOCAL(RetainPtr<NSString>, webFallbackFontFamily, ([[NSFont systemFontOfSize:16.0f] familyName]));
+ return webFallbackFontFamily.get();
+}
+
+#if !ERROR_DISABLED
+#if defined(__LP64__) || (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD))
+static NSString* pathFromFont(NSFont*)
+{
+ // FMGetATSFontRefFromFont is not available. As pathFromFont is only used for debugging purposes,
+ // returning nil is acceptable.
+ return nil;
+}
+#else
+static NSString* pathFromFont(NSFont *font)
+{
+#ifndef BUILDING_ON_TIGER
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(CTFontGetPlatformFont(toCTFontRef(font), 0));
+#else
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(wkGetNSFontATSUFontId(font));
+#endif
+ FSRef fileRef;
+
+#ifndef BUILDING_ON_TIGER
+ OSStatus status = ATSFontGetFileReference(atsFont, &fileRef);
+ if (status != noErr)
+ return nil;
+#else
+ FSSpec oFile;
+ OSStatus status = ATSFontGetFileSpecification(atsFont, &oFile);
+ if (status != noErr)
+ return nil;
+
+ status = FSpMakeFSRef(&oFile, &fileRef);
+ if (status != noErr)
+ return nil;
+#endif
+
+ UInt8 filePathBuffer[PATH_MAX];
+ status = FSRefMakePath(&fileRef, filePathBuffer, PATH_MAX);
+ if (status == noErr)
+ return [NSString stringWithUTF8String:(const char*)filePathBuffer];
+
+ return nil;
+}
+#endif // __LP64__
+#endif // !ERROR_DISABLED
+
+void SimpleFontData::platformInit()
+{
+#ifdef BUILDING_ON_TIGER
+ m_styleGroup = 0;
+#endif
+#if USE(ATSUI)
+ m_ATSUMirrors = false;
+ m_checkedShapesArabic = false;
+ m_shapesArabic = false;
+#endif
+
+ m_syntheticBoldOffset = m_platformData.m_syntheticBold ? 1.0f : 0.f;
+
+ bool failedSetup = false;
+ if (!initFontData(this)) {
+ // Ack! Something very bad happened, like a corrupt font.
+ // Try looking for an alternate 'base' font for this renderer.
+
+ // Special case hack to use "Times New Roman" in place of "Times".
+ // "Times RO" is a common font whose family name is "Times".
+ // It overrides the normal "Times" family font.
+ // It also appears to have a corrupt regular variant.
+ NSString *fallbackFontFamily;
+ if ([[m_platformData.font() familyName] isEqual:@"Times"])
+ fallbackFontFamily = @"Times New Roman";
+ else
+ fallbackFontFamily = webFallbackFontFamily();
+
+ // Try setting up the alternate font.
+ // This is a last ditch effort to use a substitute font when something has gone wrong.
+#if !ERROR_DISABLED
+ RetainPtr<NSFont> initialFont = m_platformData.font();
+#endif
+ if (m_platformData.font())
+ m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:fallbackFontFamily]);
+ else
+ m_platformData.setFont([NSFont fontWithName:fallbackFontFamily size:m_platformData.size()]);
+#if !ERROR_DISABLED
+ NSString *filePath = pathFromFont(initialFont.get());
+ if (!filePath)
+ filePath = @"not known";
+#endif
+ if (!initFontData(this)) {
+ if ([fallbackFontFamily isEqual:@"Times New Roman"]) {
+ // OK, couldn't setup Times New Roman as an alternate to Times, fallback
+ // on the system font. If this fails we have no alternative left.
+ m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:webFallbackFontFamily()]);
+ if (!initFontData(this)) {
+ // We tried, Times, Times New Roman, and the system font. No joy. We have to give up.
+ LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath);
+ failedSetup = true;
+ }
+ } else {
+ // We tried the requested font and the system font. No joy. We have to give up.
+ LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath);
+ failedSetup = true;
+ }
+ }
+
+ // Report the problem.
+ LOG_ERROR("Corrupt font detected, using %@ in place of %@ located at \"%@\".",
+ [m_platformData.font() familyName], [initialFont.get() familyName], filePath);
+ }
+
+ // If all else fails, try to set up using the system font.
+ // This is probably because Times and Times New Roman are both unavailable.
+ if (failedSetup) {
+ m_platformData.setFont([NSFont systemFontOfSize:[m_platformData.font() pointSize]]);
+ LOG_ERROR("failed to set up font, using system font %s", m_platformData.font());
+ initFontData(this);
+ }
+
+ int iAscent;
+ int iDescent;
+ int iLineGap;
+#ifdef BUILDING_ON_TIGER
+ wkGetFontMetrics(m_platformData.cgFont(), &iAscent, &iDescent, &iLineGap, &m_unitsPerEm);
+#else
+ iAscent = CGFontGetAscent(m_platformData.cgFont());
+ iDescent = CGFontGetDescent(m_platformData.cgFont());
+ iLineGap = CGFontGetLeading(m_platformData.cgFont());
+ m_unitsPerEm = CGFontGetUnitsPerEm(m_platformData.cgFont());
+#endif
+
+ float pointSize = m_platformData.m_size;
+ float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize;
+ float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize;
+ float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize;
+
+ // We need to adjust Times, Helvetica, and Courier to closely match the
+ // vertical metrics of their Microsoft counterparts that are the de facto
+ // web standard. The AppKit adjustment of 20% is too big and is
+ // incorrectly added to line spacing, so we use a 15% adjustment instead
+ // and add it to the ascent.
+ NSString *familyName = [m_platformData.font() familyName];
+ if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"])
+ fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f);
+ else if ([familyName isEqualToString:@"Geeza Pro"]) {
+ // Geeza Pro has glyphs that draw slightly above the ascent or far below the descent. Adjust
+ // those vertical metrics to better match reality, so that diacritics at the bottom of one line
+ // do not overlap diacritics at the top of the next line.
+ fAscent *= 1.08f;
+ fDescent *= 2.f;
+ }
+
+ m_ascent = lroundf(fAscent);
+ m_descent = lroundf(fDescent);
+ m_lineGap = lroundf(fLineGap);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ // Hack Hiragino line metrics to allow room for marked text underlines.
+ // <rdar://problem/5386183>
+ if (m_descent < 3 && m_lineGap >= 3 && [familyName hasPrefix:@"Hiragino"]) {
+ m_lineGap -= 3 - m_descent;
+ m_descent = 3;
+ }
+
+ if (m_orientation == Vertical) {
+ // Ignore vertical orientation when the font doesn't support vertical metrics.
+ // The check doesn't look neat but this is what AppKit does for vertical writing...
+ RetainPtr<CFArrayRef> tableTags(AdoptCF, CTFontCopyAvailableTables(m_platformData.ctFont(), kCTFontTableOptionExcludeSynthetic));
+ CFIndex numTables = CFArrayGetCount(tableTags.get());
+ bool found = false;
+ for (CFIndex index = 0; index < numTables; ++index) {
+ CTFontTableTag tag = (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tableTags.get(), index);
+ if (tag == kCTFontTableVhea || tag == kCTFontTableVORG) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false)
+ m_orientation = Horizontal;
+ }
+
+ // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font.
+ // Unfortunately, NSFont will round this for us so we don't quite get the right value.
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+ NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0;
+ if (xGlyph) {
+ CGRect xBox = platformBoundsForGlyph(xGlyph);
+ // Use the maximum of either width or height because "x" is nearly square
+ // and web pages that foolishly use this metric for width will be laid out
+ // poorly if we return an accurate height. Classic case is Times 13 point,
+ // which has an "x" that is 7x6 pixels.
+ m_xHeight = static_cast<float>(max(CGRectGetMaxX(xBox), -CGRectGetMinY(xBox)));
+ } else {
+#ifndef BUILDING_ON_TIGER
+ m_xHeight = static_cast<float>(CGFontGetXHeight(m_platformData.cgFont())) / m_unitsPerEm;
+#else
+ m_xHeight = m_platformData.font() ? [m_platformData.font() xHeight] : 0;
+#endif
+ // CGFontGetXHeight() returns a wrong value for "Apple Symbols" font (a float close to 0, but not strictly 0).
+ // The following code makes a guess for m_xHeight in that case.
+ // The int cast is a workaround for the "almost" zero value returned by CGFontGetXHeight().
+ if (!static_cast<int>(m_xHeight) && fAscent)
+ m_xHeight = 2 * fAscent / 3;
+ }
+}
+
+static CFDataRef copyFontTableForTag(FontPlatformData& platformData, FourCharCode tableName)
+{
+#ifdef BUILDING_ON_TIGER
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(platformData.m_atsuFontID);
+
+ ByteCount tableSize;
+ if (ATSFontGetTable(atsFont, tableName, 0, 0, NULL, &tableSize) != noErr)
+ return 0;
+
+ CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, tableSize);
+ if (!data)
+ return 0;
+
+ CFDataIncreaseLength(data, tableSize);
+ if (ATSFontGetTable(atsFont, tableName, 0, tableSize, CFDataGetMutableBytePtr(data), &tableSize) != noErr) {
+ CFRelease(data);
+ return 0;
+ }
+
+ return data;
+#else
+ return CGFontCopyTableForTag(platformData.cgFont(), tableName);
+#endif
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ m_avgCharWidth = 0;
+ m_maxCharWidth = 0;
+
+ RetainPtr<CFDataRef> os2Table(AdoptCF, copyFontTableForTag(m_platformData, 'OS/2'));
+ if (os2Table && CFDataGetLength(os2Table.get()) >= 4) {
+ const UInt8* os2 = CFDataGetBytePtr(os2Table.get());
+ SInt16 os2AvgCharWidth = os2[2] * 256 + os2[3];
+ m_avgCharWidth = scaleEmToUnits(os2AvgCharWidth, m_unitsPerEm) * m_platformData.m_size;
+ }
+
+ RetainPtr<CFDataRef> headTable(AdoptCF, copyFontTableForTag(m_platformData, 'head'));
+ if (headTable && CFDataGetLength(headTable.get()) >= 42) {
+ const UInt8* head = CFDataGetBytePtr(headTable.get());
+ ushort uxMin = head[36] * 256 + head[37];
+ ushort uxMax = head[40] * 256 + head[41];
+ SInt16 xMin = static_cast<SInt16>(uxMin);
+ SInt16 xMax = static_cast<SInt16>(uxMax);
+ float diff = static_cast<float>(xMax - xMin);
+ m_maxCharWidth = scaleEmToUnits(diff, m_unitsPerEm) * m_platformData.m_size;
+ }
+
+ // Fallback to a cross-platform estimate, which will populate these values if they are non-positive.
+ initCharWidths();
+}
+
+void SimpleFontData::platformDestroy()
+{
+ if (!isCustomFont() && m_derivedFontData) {
+ // These come from the cache.
+ if (m_derivedFontData->smallCaps)
+ fontCache()->releaseFontData(m_derivedFontData->smallCaps.leakPtr());
+
+ if (m_derivedFontData->emphasisMark)
+ fontCache()->releaseFontData(m_derivedFontData->emphasisMark.leakPtr());
+ }
+
+#ifdef BUILDING_ON_TIGER
+ if (m_styleGroup)
+ wkReleaseStyleGroup(m_styleGroup);
+#endif
+#if USE(ATSUI)
+ HashMap<unsigned, ATSUStyle>::iterator end = m_ATSUStyleMap.end();
+ for (HashMap<unsigned, ATSUStyle>::iterator it = m_ATSUStyleMap.begin(); it != end; ++it)
+ ATSUDisposeStyle(it->second);
+#endif
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ if (isCustomFont()) {
+ FontPlatformData scaledFontData(m_platformData);
+ scaledFontData.m_size = scaledFontData.m_size * scaleFactor;
+ return new SimpleFontData(scaledFontData, true, false);
+ }
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ float size = m_platformData.size() * scaleFactor;
+ FontPlatformData scaledFontData([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size], size);
+
+ // AppKit resets the type information (screen/printer) when you convert a font to a different size.
+ // We have to fix up the font that we're handed back.
+ scaledFontData.setFont(fontDescription.usePrinterFont() ? [scaledFontData.font() printerFont] : [scaledFontData.font() screenFont]);
+
+ if (scaledFontData.font()) {
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_platformData.font()];
+
+ if (m_platformData.m_syntheticBold)
+ fontTraits |= NSBoldFontMask;
+ if (m_platformData.m_syntheticOblique)
+ fontTraits |= NSItalicFontMask;
+
+ NSFontTraitMask scaledFontTraits = [fontManager traitsOfFont:scaledFontData.font()];
+ scaledFontData.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(scaledFontTraits & NSBoldFontMask);
+ scaledFontData.m_syntheticOblique = (fontTraits & NSItalicFontMask) && !(scaledFontTraits & NSItalicFontMask);
+
+ return fontCache()->getCachedFontData(&scaledFontData);
+ }
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return 0;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, smallCapsFontSizeMultiplier);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5f);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(characters) length:length freeWhenDone:NO];
+ NSCharacterSet *set = [[m_platformData.font() coveredCharacterSet] invertedSet];
+ bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound;
+ [string release];
+ return result;
+}
+
+void SimpleFontData::determinePitch()
+{
+ NSFont* f = m_platformData.font();
+ // Special case Osaka-Mono.
+ // According to <rdar://problem/3999467>, we should treat Osaka-Mono as fixed pitch.
+ // Note that the AppKit does not report Osaka-Mono as fixed pitch.
+
+ // Special case MS-PGothic.
+ // According to <rdar://problem/4032938>, we should not treat MS-PGothic as fixed pitch.
+ // Note that AppKit does report MS-PGothic as fixed pitch.
+
+ // Special case MonotypeCorsiva
+ // According to <rdar://problem/5454704>, we should not treat MonotypeCorsiva as fixed pitch.
+ // Note that AppKit does report MonotypeCorsiva as fixed pitch.
+
+ NSString *name = [f fontName];
+ m_treatAsFixedPitch = ([f isFixedPitch] || [f _isFakeFixedPitch] ||
+ [name caseInsensitiveCompare:@"Osaka-Mono"] == NSOrderedSame) &&
+ [name caseInsensitiveCompare:@"MS-PGothic"] != NSOrderedSame &&
+ [name caseInsensitiveCompare:@"MonotypeCorsiva"] != NSOrderedSame;
+}
+
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const
+{
+ FloatRect boundingBox;
+#ifndef BUILDING_ON_TIGER
+ boundingBox = CTFontGetBoundingRectsForGlyphs(m_platformData.ctFont(),
+ orientation() == Vertical ? kCTFontVerticalOrientation : kCTFontHorizontalOrientation, &glyph, 0, 1);
+ boundingBox.setY(-boundingBox.bottom());
+#else
+ // FIXME: Custom fonts don't have NSFonts, so this function doesn't compute correct bounds for these on Tiger.
+ if (!m_platformData.font())
+ return boundingBox;
+ boundingBox = [m_platformData.font() boundingRectForGlyph:glyph];
+ boundingBox.setY(-boundingBox.bottom());
+#endif
+ if (m_syntheticBoldOffset)
+ boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset);
+
+ return boundingBox;
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ CGSize advance;
+ if (orientation() == Horizontal || m_isBrokenIdeographFont) {
+ NSFont* font = platformData().font();
+ float pointSize = platformData().m_size;
+ CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
+ if (!wkGetGlyphTransformedAdvances(platformData().cgFont(), font, &m, &glyph, &advance)) {
+ LOG_ERROR("Unable to cache glyph widths for %@ %f", [font displayName], pointSize);
+ advance.width = 0;
+ }
+ } else
+ CTFontGetAdvancesForGlyphs(m_platformData.ctFont(), kCTFontVerticalOrientation, &glyph, &advance, 1);
+
+ return advance.width + m_syntheticBoldOffset;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/mac/WebGLLayer.h b/Source/WebCore/platform/graphics/mac/WebGLLayer.h
new file mode 100644
index 0000000..6440b71
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/WebGLLayer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 WebGLLayer_h
+#define WebGLLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import <QuartzCore/QuartzCore.h>
+
+namespace WebCore {
+ class GraphicsLayer;
+ class GraphicsContext3D;
+}
+
+@interface WebGLLayer : CAOpenGLLayer
+{
+ WebCore::GraphicsLayer* m_layerOwner;
+ WebCore::GraphicsContext3D* m_context;
+}
+
+- (id)initWithGraphicsContext3D:(WebCore::GraphicsContext3D*)context;
+
+- (CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace;
+
+@end
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebGLLayer_h
diff --git a/Source/WebCore/platform/graphics/mac/WebGLLayer.mm b/Source/WebCore/platform/graphics/mac/WebGLLayer.mm
new file mode 100644
index 0000000..c24181b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/WebGLLayer.mm
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+#if ENABLE(3D_CANVAS)
+
+#import "WebGLLayer.h"
+
+#import "GraphicsContext3D.h"
+#import "GraphicsLayer.h"
+#import <OpenGL/OpenGL.h>
+#import <wtf/FastMalloc.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/UnusedParam.h>
+
+using namespace WebCore;
+
+@implementation WebGLLayer
+
+-(id)initWithGraphicsContext3D:(GraphicsContext3D*)context
+{
+ m_context = context;
+ self = [super init];
+ return self;
+}
+
+-(CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
+{
+ // FIXME: The mask param tells you which display (on a multi-display system)
+ // is to be used. But since we are now getting the pixel format from the
+ // Canvas CGL context, we don't use it. This seems to do the right thing on
+ // one multi-display system. But there may be cases where this is not the case.
+ // If needed we will have to set the display mask in the Canvas CGLContext and
+ // make sure it matches.
+ UNUSED_PARAM(mask);
+ return CGLRetainPixelFormat(CGLGetPixelFormat(m_context->platformGraphicsContext3D()));
+}
+
+-(CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
+{
+ CGLContextObj contextObj;
+ CGLCreateContext(pixelFormat, m_context->platformGraphicsContext3D(), &contextObj);
+ return contextObj;
+}
+
+-(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
+{
+ m_context->prepareTexture();
+
+ CGLSetCurrentContext(glContext);
+
+ CGRect frame = [self frame];
+
+ // draw the FBO into the layer
+ glViewport(0, 0, frame.size.width, frame.size.height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1, 1, -1, 1, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, m_context->platformTexture());
+
+ glBegin(GL_TRIANGLE_FAN);
+ glTexCoord2f(0, 0);
+ glVertex2f(-1, -1);
+ glTexCoord2f(1, 0);
+ glVertex2f(1, -1);
+ glTexCoord2f(1, 1);
+ glVertex2f(1, 1);
+ glTexCoord2f(0, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+
+ // Call super to finalize the drawing. By default all it does is call glFlush().
+ [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp];
+}
+
+static void freeData(void *, const void *data, size_t /* size */)
+{
+ fastFree(const_cast<void *>(data));
+}
+
+-(CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace
+{
+ CGLSetCurrentContext(m_context->platformGraphicsContext3D());
+
+ RetainPtr<CGColorSpaceRef> imageColorSpace = colorSpace;
+ if (!imageColorSpace)
+ imageColorSpace.adoptCF(CGColorSpaceCreateDeviceRGB());
+
+ CGRect layerBounds = CGRectIntegral([self bounds]);
+
+ size_t width = layerBounds.size.width;
+ size_t height = layerBounds.size.height;
+
+ size_t rowBytes = (width * 4 + 15) & ~15;
+ size_t dataSize = rowBytes * height;
+ void* data = fastMalloc(dataSize);
+ if (!data)
+ return 0;
+
+ glPixelStorei(GL_PACK_ROW_LENGTH, rowBytes / 4);
+ glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
+
+ CGDataProviderRef provider = CGDataProviderCreateWithData(0, data, dataSize, freeData);
+ CGImageRef image = CGImageCreate(width, height, 8, 32, rowBytes, imageColorSpace.get(),
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
+ provider, 0, true,
+ kCGRenderingIntentDefault);
+ CGDataProviderRelease(provider);
+ return image;
+}
+
+- (void)display
+{
+ [super display];
+ if (m_layerOwner)
+ m_layerOwner->layerDidDisplay(self);
+}
+
+@end
+
+@implementation WebGLLayer(WebGLLayerAdditions)
+
+-(void)setLayerOwner:(GraphicsLayer*)aLayer
+{
+ m_layerOwner = aLayer;
+}
+
+-(GraphicsLayer*)layerOwner
+{
+ return m_layerOwner;
+}
+
+@end
+
+#endif // ENABLE(3D_CANVAS)
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/mac/WebLayer.h b/Source/WebCore/platform/graphics/mac/WebLayer.h
new file mode 100644
index 0000000..30bf55b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/WebLayer.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 WebLayer_h
+#define WebLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import <QuartzCore/QuartzCore.h>
+
+namespace WebCore {
+ class GraphicsLayer;
+ class PlatformCALayerClient;
+}
+
+#if defined(BUILDING_ON_LEOPARD)
+@interface CALayer(WebLayerInternal)
+- (CGAffineTransform)contentsTransform;
+- (void)setContentsTransform:(CGAffineTransform)t;
+@end
+#endif
+
+@interface WebLayer : CALayer
+{
+}
+@end
+
+// Functions allows us to share implementation across WebTiledLayer and WebLayer
+void drawLayerContents(CGContextRef, CALayer *, WebCore::PlatformCALayerClient*);
+void setLayerNeedsDisplayInRect(CALayer *, WebCore::PlatformCALayerClient*, CGRect);
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebLayer_h
diff --git a/Source/WebCore/platform/graphics/mac/WebLayer.mm b/Source/WebCore/platform/graphics/mac/WebLayer.mm
new file mode 100644
index 0000000..06ea9be
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/WebLayer.mm
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "WebLayer.h"
+
+#import "GraphicsContext.h"
+#import "GraphicsLayerCA.h"
+#import "PlatformCALayer.h"
+#import <objc/objc-runtime.h>
+#import <QuartzCore/QuartzCore.h>
+#import <wtf/UnusedParam.h>
+
+using namespace WebCore;
+
+@implementation WebLayer
+
+void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCALayerClient* layerContents)
+{
+ if (!layerContents)
+ return;
+
+ CGContextSaveGState(context);
+
+ CGRect layerBounds = [layer bounds];
+ if (layerContents->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesBottomUp) {
+ CGContextScaleCTM(context, 1, -1);
+ CGContextTranslateCTM(context, 0, -layerBounds.size.height);
+ }
+
+ [NSGraphicsContext saveGraphicsState];
+
+ // Set up an NSGraphicsContext for the context, so that parts of AppKit that rely on
+ // the current NSGraphicsContext (e.g. NSCell drawing) get the right one.
+ NSGraphicsContext* layerContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:YES];
+ [NSGraphicsContext setCurrentContext:layerContext];
+
+ GraphicsContext graphicsContext(context);
+
+ if (!layerContents->platformCALayerContentsOpaque()) {
+ // Turn off font smoothing to improve the appearance of text rendered onto a transparent background.
+ graphicsContext.setShouldSmoothFonts(false);
+ }
+
+ // It's important to get the clip from the context, because it may be significantly
+ // smaller than the layer bounds (e.g. tiled layers)
+ CGRect clipBounds = CGContextGetClipBoundingBox(context);
+ IntRect clip(enclosingIntRect(clipBounds));
+ layerContents->platformCALayerPaintContents(graphicsContext, clip);
+
+ [NSGraphicsContext restoreGraphicsState];
+
+ if (layerContents->platformCALayerShowRepaintCounter()) {
+ bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]];
+
+ char text[16]; // that's a lot of repaints
+ snprintf(text, sizeof(text), "%d", layerContents->platformCALayerIncrementRepaintCount());
+
+ CGContextSaveGState(context);
+ if (isTiledLayer)
+ CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 0.8f);
+ else
+ CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
+
+ CGRect aBounds = layerBounds;
+
+ aBounds.size.width = 10 + 12 * strlen(text);
+ aBounds.size.height = 25;
+ CGContextFillRect(context, aBounds);
+
+ CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f);
+
+ CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));
+ CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman);
+ CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text));
+
+ CGContextRestoreGState(context);
+ }
+
+ CGContextRestoreGState(context);
+}
+
+void setLayerNeedsDisplayInRect(CALayer *layer, WebCore::PlatformCALayerClient* layerContents, CGRect rect)
+{
+ if (layerContents && layerContents->platformCALayerDrawsContent()) {
+ struct objc_super layerSuper = { layer, class_getSuperclass(object_getClass(layer)) };
+#if defined(BUILDING_ON_LEOPARD)
+ rect = CGRectApplyAffineTransform(rect, [layer contentsTransform]);
+#else
+ if (layerContents->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesBottomUp)
+ rect.origin.y = [layer bounds].size.height - rect.origin.y - rect.size.height;
+#endif
+ objc_msgSendSuper(&layerSuper, @selector(setNeedsDisplayInRect:), rect);
+
+#ifndef NDEBUG
+ if (layerContents->platformCALayerShowRepaintCounter()) {
+ CGRect bounds = [layer bounds];
+ CGRect indicatorRect = CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25);
+#if defined(BUILDING_ON_LEOPARD)
+ indicatorRect = CGRectApplyAffineTransform(indicatorRect, [layer contentsTransform]);
+#else
+ if (layerContents->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesBottomUp)
+ indicatorRect.origin.y = [layer bounds].size.height - indicatorRect.origin.y - indicatorRect.size.height;
+#endif
+ objc_msgSendSuper(&layerSuper, @selector(setNeedsDisplayInRect:), indicatorRect);
+ }
+#endif
+ }
+}
+
+// Disable default animations
+- (id<CAAction>)actionForKey:(NSString *)key
+{
+ UNUSED_PARAM(key);
+ return nil;
+}
+
+- (void)setNeedsDisplay
+{
+ PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
+ if (layer && layer->owner() && layer->owner()->platformCALayerDrawsContent())
+ [super setNeedsDisplay];
+}
+
+- (void)setNeedsDisplayInRect:(CGRect)dirtyRect
+{
+ PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
+ if (layer)
+ setLayerNeedsDisplayInRect(self, layer->owner(), dirtyRect);
+}
+
+- (void)display
+{
+ [super display];
+ PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
+ if (layer && layer->owner())
+ layer->owner()->platformCALayerLayerDidDisplay(self);
+}
+
+- (void)drawInContext:(CGContextRef)context
+{
+ PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
+ if (layer)
+ drawLayerContents(context, self, layer->owner());
+}
+
+@end // implementation WebLayer
+
+// MARK: -
+
+#ifndef NDEBUG
+
+@implementation CALayer(ExtendedDescription)
+
+- (NSString*)_descriptionWithPrefix:(NSString*)inPrefix
+{
+ CGRect aBounds = [self bounds];
+ CGPoint aPos = [self position];
+
+ NSString* selfString = [NSString stringWithFormat:@"%@<%@ 0x%08x> \"%@\" bounds(%.1f, %.1f, %.1f, %.1f) pos(%.1f, %.1f), sublayers=%d masking=%d",
+ inPrefix,
+ [self class],
+ self,
+ [self name],
+ aBounds.origin.x, aBounds.origin.y, aBounds.size.width, aBounds.size.height,
+ aPos.x, aPos.y,
+ [[self sublayers] count],
+ [self masksToBounds]];
+
+ NSMutableString* curDesc = [NSMutableString stringWithString:selfString];
+
+ if ([[self sublayers] count] > 0)
+ [curDesc appendString:@"\n"];
+
+ NSString* sublayerPrefix = [inPrefix stringByAppendingString:@"\t"];
+
+ NSEnumerator* sublayersEnum = [[self sublayers] objectEnumerator];
+ CALayer* curLayer;
+ while ((curLayer = [sublayersEnum nextObject]))
+ [curDesc appendString:[curLayer _descriptionWithPrefix:sublayerPrefix]];
+
+ if ([[self sublayers] count] == 0)
+ [curDesc appendString:@"\n"];
+
+ return curDesc;
+}
+
+- (NSString*)extendedDescription
+{
+ return [self _descriptionWithPrefix:@""];
+}
+
+@end // implementation WebLayer(ExtendedDescription)
+
+#endif // NDEBUG
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/mac/WebTiledLayer.h b/Source/WebCore/platform/graphics/mac/WebTiledLayer.h
new file mode 100644
index 0000000..6f559e3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/WebTiledLayer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 WebTiledLayer_h
+#define WebTiledLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "WebLayer.h"
+
+@interface WebTiledLayer : CATiledLayer
+{
+}
+
+// implements WebLayerAdditions
+
+@end
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebTiledLayer_h
+
diff --git a/Source/WebCore/platform/graphics/mac/WebTiledLayer.mm b/Source/WebCore/platform/graphics/mac/WebTiledLayer.mm
new file mode 100644
index 0000000..e9fa5b7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/mac/WebTiledLayer.mm
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "WebTiledLayer.h"
+
+#import "GraphicsContext.h"
+#import "GraphicsLayerCA.h"
+#import "PlatformCALayer.h"
+#import <wtf/UnusedParam.h>
+
+using namespace WebCore;
+
+@implementation WebTiledLayer
+
+// Set a zero duration for the fade in of tiles
++ (CFTimeInterval)fadeDuration
+{
+ return 0;
+}
+
+// Make sure that tiles are drawn on the main thread
++ (BOOL)shouldDrawOnMainThread
+{
+ return YES;
+}
+
+// Disable default animations
+- (id<CAAction>)actionForKey:(NSString *)key
+{
+ UNUSED_PARAM(key);
+ return nil;
+}
+
+- (void)setNeedsDisplay
+{
+ PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
+ if (layer && layer->owner() && layer->owner()->platformCALayerDrawsContent())
+ [super setNeedsDisplay];
+}
+
+- (void)setNeedsDisplayInRect:(CGRect)dirtyRect
+{
+ PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
+ if (layer)
+ setLayerNeedsDisplayInRect(self, layer->owner(), dirtyRect);
+}
+
+- (void)display
+{
+ [super display];
+ PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
+ if (layer && layer->owner())
+ layer->owner()->platformCALayerLayerDidDisplay(self);
+}
+
+- (void)drawInContext:(CGContextRef)context
+{
+ PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
+ if (layer)
+ drawLayerContents(context, self, layer->owner());
+}
+
+@end // implementation WebTiledLayer
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp
new file mode 100644
index 0000000..4215d12
--- /dev/null
+++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "Extensions3DOpenGL.h"
+
+#include "GraphicsContext3D.h"
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+#include <OpenGL/gl.h>
+#endif
+
+namespace WebCore {
+
+Extensions3DOpenGL::Extensions3DOpenGL()
+ : m_initializedAvailableExtensions(false)
+{
+}
+
+Extensions3DOpenGL::~Extensions3DOpenGL()
+{
+}
+
+bool Extensions3DOpenGL::supports(const String& name)
+{
+ // Note on support for BGRA:
+ //
+ // For OpenGL ES2.0, requires checking for
+ // GL_EXT_texture_format_BGRA8888 and GL_EXT_read_format_bgra.
+ // For desktop GL, BGRA has been supported since OpenGL 1.2.
+ //
+ // However, note that the GL ES2 extension requires the
+ // internalFormat to glTexImage2D() be GL_BGRA, while desktop GL
+ // will not accept GL_BGRA (must be GL_RGBA), so this must be
+ // checked on each platform. Desktop GL offers neither
+ // GL_EXT_texture_format_BGRA8888 or GL_EXT_read_format_bgra, so
+ // treat them as unsupported here.
+ if (!m_initializedAvailableExtensions) {
+ String extensionsString(reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS)));
+ Vector<String> availableExtensions;
+ extensionsString.split(" ", availableExtensions);
+ for (size_t i = 0; i < availableExtensions.size(); ++i)
+ m_availableExtensions.add(availableExtensions[i]);
+ m_initializedAvailableExtensions = true;
+ }
+
+ // GL_ANGLE_framebuffer_blit and GL_ANGLE_framebuffer_multisample are "fake". They are implemented using other
+ // extensions. In particular GL_EXT_framebuffer_blit and GL_EXT_framebuffer_multisample
+ if (name == "GL_ANGLE_framebuffer_blit")
+ return m_availableExtensions.contains("GL_EXT_framebuffer_blit");
+ if (name == "GL_ANGLE_framebuffer_multisample")
+ return m_availableExtensions.contains("GL_EXT_framebuffer_multisample");
+
+ // If GL_ARB_texture_float is available then we report GL_OES_texture_float and
+ // GL_OES_texture_half_float as available.
+ if (name == "GL_OES_texture_float" || name == "GL_OES_texture_half_float")
+ return m_availableExtensions.contains("GL_ARB_texture_float");
+
+ return m_availableExtensions.contains(name);
+}
+
+void Extensions3DOpenGL::ensureEnabled(const String& name)
+{
+ ASSERT_UNUSED(name, supports(name));
+}
+
+int Extensions3DOpenGL::getGraphicsResetStatusARB()
+{
+ return GraphicsContext3D::NO_ERROR;
+}
+
+void Extensions3DOpenGL::blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter)
+{
+ ::glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
+void Extensions3DOpenGL::renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height)
+{
+ ::glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h
new file mode 100644
index 0000000..59f8180
--- /dev/null
+++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 Extensions3DOpenGL_h
+#define Extensions3DOpenGL_h
+
+#include "Extensions3D.h"
+
+#include "GraphicsContext3D.h"
+#include <wtf/HashSet.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class Extensions3DOpenGL : public Extensions3D {
+public:
+ virtual ~Extensions3DOpenGL();
+
+ // Extensions3D methods.
+ virtual bool supports(const String&);
+ virtual void ensureEnabled(const String&);
+ virtual int getGraphicsResetStatusARB();
+ virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter);
+ virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height);
+
+private:
+ // This class only needs to be instantiated by GraphicsContext3D implementations.
+ friend class GraphicsContext3D;
+ Extensions3DOpenGL();
+
+ bool m_initializedAvailableExtensions;
+ HashSet<String> m_availableExtensions;
+};
+
+} // namespace WebCore
+
+#endif // Extensions3DOpenGL_h
diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp
new file mode 100644
index 0000000..221ee11
--- /dev/null
+++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp
@@ -0,0 +1,1476 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#include "ArrayBuffer.h"
+#include "ArrayBufferView.h"
+#include "WebGLObject.h"
+#include "CanvasRenderingContext.h"
+#include "Extensions3DOpenGL.h"
+#include "Float32Array.h"
+#include "GraphicsContext.h"
+#include "HTMLCanvasElement.h"
+#include "ImageBuffer.h"
+#include "Int32Array.h"
+#include "NotImplemented.h"
+#include "Uint8Array.h"
+
+#if PLATFORM(MAC)
+#include <OpenGL/gl.h>
+#endif
+
+#include <wtf/UnusedParam.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+void GraphicsContext3D::validateAttributes()
+{
+ const char* extensions = reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS));
+ if (m_attrs.stencil) {
+ if (std::strstr(extensions, "GL_EXT_packed_depth_stencil")) {
+ if (!m_attrs.depth)
+ m_attrs.depth = true;
+ } else
+ m_attrs.stencil = false;
+ }
+ if (m_attrs.antialias) {
+ bool isValidVendor = true;
+ // Currently in Mac we only turn on antialias if vendor is NVIDIA.
+ const char* vendor = reinterpret_cast<const char*>(::glGetString(GL_VENDOR));
+ if (!std::strstr(vendor, "NVIDIA"))
+ isValidVendor = false;
+ if (!isValidVendor || !std::strstr(extensions, "GL_EXT_framebuffer_multisample"))
+ m_attrs.antialias = false;
+ }
+ // FIXME: instead of enforcing premultipliedAlpha = true, implement the
+ // correct behavior when premultipliedAlpha = false is requested.
+ m_attrs.premultipliedAlpha = true;
+}
+
+void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* context)
+{
+ HTMLCanvasElement* canvas = context->canvas();
+ ImageBuffer* imageBuffer = canvas->buffer();
+
+ int rowBytes = m_currentWidth * 4;
+ int totalBytes = rowBytes * m_currentHeight;
+
+ OwnArrayPtr<unsigned char> pixels(new unsigned char[totalBytes]);
+ if (!pixels)
+ return;
+
+ makeContextCurrent();
+
+ bool mustRestoreFBO = false;
+ if (m_attrs.antialias) {
+ ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO);
+ ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo);
+ ::glBlitFramebufferEXT(0, 0, m_currentWidth, m_currentHeight, 0, 0, m_currentWidth, m_currentHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ mustRestoreFBO = true;
+ } else {
+ if (m_boundFBO != m_fbo) {
+ mustRestoreFBO = true;
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ }
+ }
+
+ GLint packAlignment = 4;
+ bool mustRestorePackAlignment = false;
+ ::glGetIntegerv(GL_PACK_ALIGNMENT, &packAlignment);
+ if (packAlignment > 4) {
+ ::glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ mustRestorePackAlignment = true;
+ }
+
+ ::glReadPixels(0, 0, m_currentWidth, m_currentHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels.get());
+
+ if (mustRestorePackAlignment)
+ ::glPixelStorei(GL_PACK_ALIGNMENT, packAlignment);
+
+ if (mustRestoreFBO)
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);
+
+ paintToCanvas(pixels.get(), m_currentWidth, m_currentHeight,
+ canvas->width(), canvas->height(), imageBuffer->context()->platformContext());
+}
+
+void GraphicsContext3D::reshape(int width, int height)
+{
+ if (!m_contextObj)
+ return;
+
+ if (width == m_currentWidth && height == m_currentHeight)
+ return;
+
+ m_currentWidth = width;
+ m_currentHeight = height;
+
+ makeContextCurrent();
+
+ GLuint internalColorFormat, colorFormat, internalDepthStencilFormat = 0;
+ if (m_attrs.alpha) {
+ internalColorFormat = GL_RGBA8;
+ colorFormat = GL_RGBA;
+ } else {
+ internalColorFormat = GL_RGB8;
+ colorFormat = GL_RGB;
+ }
+ if (m_attrs.stencil || m_attrs.depth) {
+ // We don't allow the logic where stencil is required and depth is not.
+ // See GraphicsContext3D constructor.
+ if (m_attrs.stencil && m_attrs.depth)
+ internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT;
+ else
+ internalDepthStencilFormat = GL_DEPTH_COMPONENT;
+ }
+
+ bool mustRestoreFBO = false;
+
+ // resize multisample FBO
+ if (m_attrs.antialias) {
+ GLint maxSampleCount;
+ ::glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount);
+ GLint sampleCount = std::min(8, maxSampleCount);
+ if (sampleCount > maxSampleCount)
+ sampleCount = maxSampleCount;
+ if (m_boundFBO != m_multisampleFBO) {
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
+ mustRestoreFBO = true;
+ }
+ ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer);
+ ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalColorFormat, width, height);
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer);
+ if (m_attrs.stencil || m_attrs.depth) {
+ ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer);
+ ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalDepthStencilFormat, width, height);
+ if (m_attrs.stencil)
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer);
+ if (m_attrs.depth)
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer);
+ }
+ ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+ if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ // FIXME: cleanup.
+ notImplemented();
+ }
+ }
+
+ // resize regular FBO
+ if (m_boundFBO != m_fbo) {
+ mustRestoreFBO = true;
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ }
+ ::glBindTexture(GL_TEXTURE_2D, m_texture);
+ ::glTexImage2D(GL_TEXTURE_2D, 0, internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0);
+ ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0);
+ ::glBindTexture(GL_TEXTURE_2D, 0);
+ if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) {
+ ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer);
+ ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height);
+ if (m_attrs.stencil)
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer);
+ if (m_attrs.depth)
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer);
+ ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+ }
+ if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ // FIXME: cleanup
+ notImplemented();
+ }
+
+ if (m_attrs.antialias) {
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
+ if (m_boundFBO == m_multisampleFBO)
+ mustRestoreFBO = false;
+ }
+
+ // Initialize renderbuffers to 0.
+ GLfloat clearColor[] = {0, 0, 0, 0}, clearDepth = 0;
+ GLint clearStencil = 0;
+ GLboolean colorMask[] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, depthMask = GL_TRUE;
+ GLuint stencilMask = 0xffffffff;
+ GLboolean isScissorEnabled = GL_FALSE;
+ GLboolean isDitherEnabled = GL_FALSE;
+ GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
+ ::glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
+ ::glClearColor(0, 0, 0, 0);
+ ::glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
+ ::glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ if (m_attrs.depth) {
+ ::glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearDepth);
+ ::glClearDepth(1);
+ ::glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);
+ ::glDepthMask(GL_TRUE);
+ clearMask |= GL_DEPTH_BUFFER_BIT;
+ }
+ if (m_attrs.stencil) {
+ ::glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &clearStencil);
+ ::glClearStencil(0);
+ ::glGetIntegerv(GL_STENCIL_WRITEMASK, reinterpret_cast<GLint*>(&stencilMask));
+ ::glStencilMaskSeparate(GL_FRONT, 0xffffffff);
+ clearMask |= GL_STENCIL_BUFFER_BIT;
+ }
+ isScissorEnabled = ::glIsEnabled(GL_SCISSOR_TEST);
+ ::glDisable(GL_SCISSOR_TEST);
+ isDitherEnabled = ::glIsEnabled(GL_DITHER);
+ ::glDisable(GL_DITHER);
+
+ ::glClear(clearMask);
+
+ ::glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
+ ::glColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
+ if (m_attrs.depth) {
+ ::glClearDepth(clearDepth);
+ ::glDepthMask(depthMask);
+ }
+ if (m_attrs.stencil) {
+ ::glClearStencil(clearStencil);
+ ::glStencilMaskSeparate(GL_FRONT, stencilMask);
+ }
+ if (isScissorEnabled)
+ ::glEnable(GL_SCISSOR_TEST);
+ else
+ ::glDisable(GL_SCISSOR_TEST);
+ if (isDitherEnabled)
+ ::glEnable(GL_DITHER);
+ else
+ ::glDisable(GL_DITHER);
+
+ if (mustRestoreFBO)
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);
+
+ ::glFlush();
+}
+
+IntSize GraphicsContext3D::getInternalFramebufferSize()
+{
+ return IntSize(m_currentWidth, m_currentHeight);
+}
+
+void GraphicsContext3D::prepareTexture()
+{
+ makeContextCurrent();
+ if (m_attrs.antialias) {
+ ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO);
+ ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo);
+ ::glBlitFramebufferEXT(0, 0, m_currentWidth, m_currentHeight, 0, 0, m_currentWidth, m_currentHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);
+ }
+ ::glFinish();
+}
+
+void GraphicsContext3D::activeTexture(GC3Denum texture)
+{
+ makeContextCurrent();
+ ::glActiveTexture(texture);
+}
+
+void GraphicsContext3D::attachShader(Platform3DObject program, Platform3DObject shader)
+{
+ ASSERT(program);
+ ASSERT(shader);
+ makeContextCurrent();
+ ::glAttachShader(program, shader);
+}
+
+void GraphicsContext3D::bindAttribLocation(Platform3DObject program, GC3Duint index, const String& name)
+{
+ ASSERT(program);
+ makeContextCurrent();
+ ::glBindAttribLocation(program, index, name.utf8().data());
+}
+
+void GraphicsContext3D::bindBuffer(GC3Denum target, Platform3DObject buffer)
+{
+ makeContextCurrent();
+ ::glBindBuffer(target, buffer);
+}
+
+
+void GraphicsContext3D::bindFramebuffer(GC3Denum target, Platform3DObject buffer)
+{
+ makeContextCurrent();
+ GLuint fbo;
+ if (buffer)
+ fbo = buffer;
+ else
+ fbo = (m_attrs.antialias ? m_multisampleFBO : m_fbo);
+ if (fbo != m_boundFBO) {
+ ::glBindFramebufferEXT(target, fbo);
+ m_boundFBO = fbo;
+ }
+}
+
+void GraphicsContext3D::bindRenderbuffer(GC3Denum target, Platform3DObject renderbuffer)
+{
+ makeContextCurrent();
+ ::glBindRenderbufferEXT(target, renderbuffer);
+}
+
+
+void GraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture)
+{
+ makeContextCurrent();
+ ::glBindTexture(target, texture);
+}
+
+void GraphicsContext3D::blendColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha)
+{
+ makeContextCurrent();
+ ::glBlendColor(red, green, blue, alpha);
+}
+
+void GraphicsContext3D::blendEquation(GC3Denum mode)
+{
+ makeContextCurrent();
+ ::glBlendEquation(mode);
+}
+
+void GraphicsContext3D::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
+{
+ makeContextCurrent();
+ ::glBlendEquationSeparate(modeRGB, modeAlpha);
+}
+
+
+void GraphicsContext3D::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
+{
+ makeContextCurrent();
+ ::glBlendFunc(sfactor, dfactor);
+}
+
+void GraphicsContext3D::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
+{
+ makeContextCurrent();
+ ::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage)
+{
+ makeContextCurrent();
+ ::glBufferData(target, size, 0, usage);
+}
+
+void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage)
+{
+ makeContextCurrent();
+ ::glBufferData(target, size, data, usage);
+}
+
+void GraphicsContext3D::bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data)
+{
+ makeContextCurrent();
+ ::glBufferSubData(target, offset, size, data);
+}
+
+GC3Denum GraphicsContext3D::checkFramebufferStatus(GC3Denum target)
+{
+ makeContextCurrent();
+ return ::glCheckFramebufferStatusEXT(target);
+}
+
+void GraphicsContext3D::clearColor(GC3Dclampf r, GC3Dclampf g, GC3Dclampf b, GC3Dclampf a)
+{
+ makeContextCurrent();
+ ::glClearColor(r, g, b, a);
+}
+
+void GraphicsContext3D::clear(GC3Dbitfield mask)
+{
+ makeContextCurrent();
+ ::glClear(mask);
+}
+
+void GraphicsContext3D::clearDepth(GC3Dclampf depth)
+{
+ makeContextCurrent();
+ ::glClearDepth(depth);
+}
+
+void GraphicsContext3D::clearStencil(GC3Dint s)
+{
+ makeContextCurrent();
+ ::glClearStencil(s);
+}
+
+void GraphicsContext3D::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
+{
+ makeContextCurrent();
+ ::glColorMask(red, green, blue, alpha);
+}
+
+void GraphicsContext3D::compileShader(Platform3DObject shader)
+{
+ ASSERT(shader);
+ makeContextCurrent();
+
+ int GLshaderType;
+ ANGLEShaderType shaderType;
+
+ glGetShaderiv(shader, SHADER_TYPE, &GLshaderType);
+
+ if (GLshaderType == VERTEX_SHADER)
+ shaderType = SHADER_TYPE_VERTEX;
+ else if (GLshaderType == FRAGMENT_SHADER)
+ shaderType = SHADER_TYPE_FRAGMENT;
+ else
+ return; // Invalid shader type.
+
+ HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader);
+
+ if (result == m_shaderSourceMap.end())
+ return;
+
+ ShaderSourceEntry& entry = result->second;
+
+ String translatedShaderSource;
+ String shaderInfoLog;
+
+ bool isValid = m_compiler.validateShaderSource(entry.source.utf8().data(), shaderType, translatedShaderSource, shaderInfoLog);
+
+ entry.log = shaderInfoLog;
+ entry.isValid = isValid;
+
+ if (!isValid)
+ return; // Shader didn't validate, don't move forward with compiling translated source
+
+ int translatedShaderLength = translatedShaderSource.length();
+
+ const CString& translatedShaderCString = translatedShaderSource.utf8();
+ const char* translatedShaderPtr = translatedShaderCString.data();
+
+ ::glShaderSource(shader, 1, &translatedShaderPtr, &translatedShaderLength);
+
+ ::glCompileShader(shader);
+
+ int GLCompileSuccess;
+
+ ::glGetShaderiv(shader, COMPILE_STATUS, &GLCompileSuccess);
+
+ // ASSERT that ANGLE generated GLSL will be accepted by OpenGL
+ ASSERT(GLCompileSuccess == GL_TRUE);
+}
+
+void GraphicsContext3D::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
+{
+ makeContextCurrent();
+ if (m_attrs.antialias && m_boundFBO == m_multisampleFBO) {
+ ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO);
+ ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo);
+ ::glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ }
+ ::glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+ if (m_attrs.antialias && m_boundFBO == m_multisampleFBO)
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
+}
+
+void GraphicsContext3D::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+ makeContextCurrent();
+ if (m_attrs.antialias && m_boundFBO == m_multisampleFBO) {
+ ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO);
+ ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo);
+ ::glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ }
+ ::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+ if (m_attrs.antialias && m_boundFBO == m_multisampleFBO)
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
+}
+
+void GraphicsContext3D::cullFace(GC3Denum mode)
+{
+ makeContextCurrent();
+ ::glCullFace(mode);
+}
+
+void GraphicsContext3D::depthFunc(GC3Denum func)
+{
+ makeContextCurrent();
+ ::glDepthFunc(func);
+}
+
+void GraphicsContext3D::depthMask(GC3Dboolean flag)
+{
+ makeContextCurrent();
+ ::glDepthMask(flag);
+}
+
+void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar)
+{
+ makeContextCurrent();
+ ::glDepthRange(zNear, zFar);
+}
+
+void GraphicsContext3D::detachShader(Platform3DObject program, Platform3DObject shader)
+{
+ ASSERT(program);
+ ASSERT(shader);
+ makeContextCurrent();
+ ::glDetachShader(program, shader);
+}
+
+void GraphicsContext3D::disable(GC3Denum cap)
+{
+ makeContextCurrent();
+ ::glDisable(cap);
+}
+
+void GraphicsContext3D::disableVertexAttribArray(GC3Duint index)
+{
+ makeContextCurrent();
+ ::glDisableVertexAttribArray(index);
+}
+
+void GraphicsContext3D::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count)
+{
+ makeContextCurrent();
+ ::glDrawArrays(mode, first, count);
+}
+
+void GraphicsContext3D::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
+{
+ makeContextCurrent();
+ ::glDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)));
+}
+
+void GraphicsContext3D::enable(GC3Denum cap)
+{
+ makeContextCurrent();
+ ::glEnable(cap);
+}
+
+void GraphicsContext3D::enableVertexAttribArray(GC3Duint index)
+{
+ makeContextCurrent();
+ ::glEnableVertexAttribArray(index);
+}
+
+void GraphicsContext3D::finish()
+{
+ makeContextCurrent();
+ ::glFinish();
+}
+
+void GraphicsContext3D::flush()
+{
+ makeContextCurrent();
+ ::glFlush();
+}
+
+void GraphicsContext3D::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, Platform3DObject buffer)
+{
+ makeContextCurrent();
+ ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer);
+}
+
+void GraphicsContext3D::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject texture, GC3Dint level)
+{
+ makeContextCurrent();
+ ::glFramebufferTexture2DEXT(target, attachment, textarget, texture, level);
+}
+
+void GraphicsContext3D::frontFace(GC3Denum mode)
+{
+ makeContextCurrent();
+ ::glFrontFace(mode);
+}
+
+void GraphicsContext3D::generateMipmap(GC3Denum target)
+{
+ makeContextCurrent();
+ ::glGenerateMipmapEXT(target);
+}
+
+bool GraphicsContext3D::getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo& info)
+{
+ if (!program) {
+ synthesizeGLError(INVALID_VALUE);
+ return false;
+ }
+ makeContextCurrent();
+ GLint maxAttributeSize = 0;
+ ::glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize);
+ GLchar name[maxAttributeSize]; // GL_ACTIVE_ATTRIBUTE_MAX_LENGTH includes null termination
+ GLsizei nameLength = 0;
+ GLint size = 0;
+ GLenum type = 0;
+ ::glGetActiveAttrib(program, index, maxAttributeSize, &nameLength, &size, &type, name);
+ if (!nameLength)
+ return false;
+ info.name = String(name, nameLength);
+ info.type = type;
+ info.size = size;
+ return true;
+}
+
+bool GraphicsContext3D::getActiveUniform(Platform3DObject program, GC3Duint index, ActiveInfo& info)
+{
+ if (!program) {
+ synthesizeGLError(INVALID_VALUE);
+ return false;
+ }
+ makeContextCurrent();
+ GLint maxUniformSize = 0;
+ ::glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformSize);
+ GLchar name[maxUniformSize]; // GL_ACTIVE_UNIFORM_MAX_LENGTH includes null termination
+ GLsizei nameLength = 0;
+ GLint size = 0;
+ GLenum type = 0;
+ ::glGetActiveUniform(program, index, maxUniformSize, &nameLength, &size, &type, name);
+ if (!nameLength)
+ return false;
+ info.name = String(name, nameLength);
+ info.type = type;
+ info.size = size;
+ return true;
+}
+
+void GraphicsContext3D::getAttachedShaders(Platform3DObject program, GC3Dsizei maxCount, GC3Dsizei* count, Platform3DObject* shaders)
+{
+ if (!program) {
+ synthesizeGLError(INVALID_VALUE);
+ return;
+ }
+ makeContextCurrent();
+ ::glGetAttachedShaders(program, maxCount, count, shaders);
+}
+
+int GraphicsContext3D::getAttribLocation(Platform3DObject program, const String& name)
+{
+ if (!program)
+ return -1;
+
+ makeContextCurrent();
+ return ::glGetAttribLocation(program, name.utf8().data());
+}
+
+GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes()
+{
+ return m_attrs;
+}
+
+GC3Denum GraphicsContext3D::getError()
+{
+ if (m_syntheticErrors.size() > 0) {
+ ListHashSet<GC3Denum>::iterator iter = m_syntheticErrors.begin();
+ GC3Denum err = *iter;
+ m_syntheticErrors.remove(iter);
+ return err;
+ }
+
+ makeContextCurrent();
+ return ::glGetError();
+}
+
+String GraphicsContext3D::getString(GC3Denum name)
+{
+ makeContextCurrent();
+ return String((const char*) ::glGetString(name));
+}
+
+void GraphicsContext3D::hint(GC3Denum target, GC3Denum mode)
+{
+ makeContextCurrent();
+ ::glHint(target, mode);
+}
+
+GC3Dboolean GraphicsContext3D::isBuffer(Platform3DObject buffer)
+{
+ if (!buffer)
+ return GL_FALSE;
+
+ makeContextCurrent();
+ return ::glIsBuffer(buffer);
+}
+
+GC3Dboolean GraphicsContext3D::isEnabled(GC3Denum cap)
+{
+ makeContextCurrent();
+ return ::glIsEnabled(cap);
+}
+
+GC3Dboolean GraphicsContext3D::isFramebuffer(Platform3DObject framebuffer)
+{
+ if (!framebuffer)
+ return GL_FALSE;
+
+ makeContextCurrent();
+ return ::glIsFramebufferEXT(framebuffer);
+}
+
+GC3Dboolean GraphicsContext3D::isProgram(Platform3DObject program)
+{
+ if (!program)
+ return GL_FALSE;
+
+ makeContextCurrent();
+ return ::glIsProgram(program);
+}
+
+GC3Dboolean GraphicsContext3D::isRenderbuffer(Platform3DObject renderbuffer)
+{
+ if (!renderbuffer)
+ return GL_FALSE;
+
+ makeContextCurrent();
+ return ::glIsRenderbufferEXT(renderbuffer);
+}
+
+GC3Dboolean GraphicsContext3D::isShader(Platform3DObject shader)
+{
+ if (!shader)
+ return GL_FALSE;
+
+ makeContextCurrent();
+ return ::glIsShader(shader);
+}
+
+GC3Dboolean GraphicsContext3D::isTexture(Platform3DObject texture)
+{
+ if (!texture)
+ return GL_FALSE;
+
+ makeContextCurrent();
+ return ::glIsTexture(texture);
+}
+
+void GraphicsContext3D::lineWidth(GC3Dfloat width)
+{
+ makeContextCurrent();
+ ::glLineWidth(width);
+}
+
+void GraphicsContext3D::linkProgram(Platform3DObject program)
+{
+ ASSERT(program);
+ makeContextCurrent();
+ ::glLinkProgram(program);
+}
+
+void GraphicsContext3D::pixelStorei(GC3Denum pname, GC3Dint param)
+{
+ makeContextCurrent();
+ ::glPixelStorei(pname, param);
+}
+
+void GraphicsContext3D::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
+{
+ makeContextCurrent();
+ ::glPolygonOffset(factor, units);
+}
+
+void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data)
+{
+ // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e.,
+ // all previous rendering calls should be done before reading pixels.
+ makeContextCurrent();
+ ::glFlush();
+ if (m_attrs.antialias && m_boundFBO == m_multisampleFBO) {
+ ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO);
+ ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo);
+ ::glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ ::glFlush();
+ }
+ ::glReadPixels(x, y, width, height, format, type, data);
+ if (m_attrs.antialias && m_boundFBO == m_multisampleFBO)
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
+}
+
+void GraphicsContext3D::releaseShaderCompiler()
+{
+ // FIXME: This is not implemented on desktop OpenGL. We need to have ifdefs for the different GL variants
+ makeContextCurrent();
+ //::glReleaseShaderCompiler();
+}
+
+void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
+{
+ makeContextCurrent();
+ switch (internalformat) {
+ case DEPTH_STENCIL:
+ internalformat = GL_DEPTH24_STENCIL8_EXT;
+ break;
+ case DEPTH_COMPONENT16:
+ internalformat = GL_DEPTH_COMPONENT;
+ break;
+ case RGBA4:
+ case RGB5_A1:
+ internalformat = GL_RGBA;
+ break;
+ case RGB565:
+ internalformat = GL_RGB;
+ break;
+ }
+ ::glRenderbufferStorageEXT(target, internalformat, width, height);
+}
+
+void GraphicsContext3D::sampleCoverage(GC3Dclampf value, GC3Dboolean invert)
+{
+ makeContextCurrent();
+ ::glSampleCoverage(value, invert);
+}
+
+void GraphicsContext3D::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+ makeContextCurrent();
+ ::glScissor(x, y, width, height);
+}
+
+void GraphicsContext3D::shaderSource(Platform3DObject shader, const String& string)
+{
+ ASSERT(shader);
+
+ makeContextCurrent();
+
+ ShaderSourceEntry entry;
+
+ entry.source = string;
+
+ m_shaderSourceMap.set(shader, entry);
+}
+
+void GraphicsContext3D::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+ makeContextCurrent();
+ ::glStencilFunc(func, ref, mask);
+}
+
+void GraphicsContext3D::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+ makeContextCurrent();
+ ::glStencilFuncSeparate(face, func, ref, mask);
+}
+
+void GraphicsContext3D::stencilMask(GC3Duint mask)
+{
+ makeContextCurrent();
+ ::glStencilMask(mask);
+}
+
+void GraphicsContext3D::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
+{
+ makeContextCurrent();
+ ::glStencilMaskSeparate(face, mask);
+}
+
+void GraphicsContext3D::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+ makeContextCurrent();
+ ::glStencilOp(fail, zfail, zpass);
+}
+
+void GraphicsContext3D::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+ makeContextCurrent();
+ ::glStencilOpSeparate(face, fail, zfail, zpass);
+}
+
+void GraphicsContext3D::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat value)
+{
+ makeContextCurrent();
+ ::glTexParameterf(target, pname, value);
+}
+
+void GraphicsContext3D::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint value)
+{
+ makeContextCurrent();
+ ::glTexParameteri(target, pname, value);
+}
+
+void GraphicsContext3D::uniform1f(GC3Dint location, GC3Dfloat v0)
+{
+ makeContextCurrent();
+ ::glUniform1f(location, v0);
+}
+
+void GraphicsContext3D::uniform1fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ makeContextCurrent();
+ ::glUniform1fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform2f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1)
+{
+ makeContextCurrent();
+ ::glUniform2f(location, v0, v1);
+}
+
+void GraphicsContext3D::uniform2fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ // FIXME: length needs to be a multiple of 2
+ makeContextCurrent();
+ ::glUniform2fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform3f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
+{
+ makeContextCurrent();
+ ::glUniform3f(location, v0, v1, v2);
+}
+
+void GraphicsContext3D::uniform3fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ // FIXME: length needs to be a multiple of 3
+ makeContextCurrent();
+ ::glUniform3fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform4f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+ makeContextCurrent();
+ ::glUniform4f(location, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::uniform4fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ // FIXME: length needs to be a multiple of 4
+ makeContextCurrent();
+ ::glUniform4fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform1i(GC3Dint location, GC3Dint v0)
+{
+ makeContextCurrent();
+ ::glUniform1i(location, v0);
+}
+
+void GraphicsContext3D::uniform1iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ makeContextCurrent();
+ ::glUniform1iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform2i(GC3Dint location, GC3Dint v0, GC3Dint v1)
+{
+ makeContextCurrent();
+ ::glUniform2i(location, v0, v1);
+}
+
+void GraphicsContext3D::uniform2iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ // FIXME: length needs to be a multiple of 2
+ makeContextCurrent();
+ ::glUniform2iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform3i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2)
+{
+ makeContextCurrent();
+ ::glUniform3i(location, v0, v1, v2);
+}
+
+void GraphicsContext3D::uniform3iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ // FIXME: length needs to be a multiple of 3
+ makeContextCurrent();
+ ::glUniform3iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform4i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2, GC3Dint v3)
+{
+ makeContextCurrent();
+ ::glUniform4i(location, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::uniform4iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ // FIXME: length needs to be a multiple of 4
+ makeContextCurrent();
+ ::glUniform4iv(location, size, array);
+}
+
+void GraphicsContext3D::uniformMatrix2fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size)
+{
+ // FIXME: length needs to be a multiple of 4
+ makeContextCurrent();
+ ::glUniformMatrix2fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::uniformMatrix3fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size)
+{
+ // FIXME: length needs to be a multiple of 9
+ makeContextCurrent();
+ ::glUniformMatrix3fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::uniformMatrix4fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size)
+{
+ // FIXME: length needs to be a multiple of 16
+ makeContextCurrent();
+ ::glUniformMatrix4fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::useProgram(Platform3DObject program)
+{
+ makeContextCurrent();
+ ::glUseProgram(program);
+}
+
+void GraphicsContext3D::validateProgram(Platform3DObject program)
+{
+ ASSERT(program);
+
+ makeContextCurrent();
+ ::glValidateProgram(program);
+}
+
+void GraphicsContext3D::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
+{
+ makeContextCurrent();
+ ::glVertexAttrib1f(index, v0);
+}
+
+void GraphicsContext3D::vertexAttrib1fv(GC3Duint index, GC3Dfloat* array)
+{
+ makeContextCurrent();
+ ::glVertexAttrib1fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
+{
+ makeContextCurrent();
+ ::glVertexAttrib2f(index, v0, v1);
+}
+
+void GraphicsContext3D::vertexAttrib2fv(GC3Duint index, GC3Dfloat* array)
+{
+ makeContextCurrent();
+ ::glVertexAttrib2fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
+{
+ makeContextCurrent();
+ ::glVertexAttrib3f(index, v0, v1, v2);
+}
+
+void GraphicsContext3D::vertexAttrib3fv(GC3Duint index, GC3Dfloat* array)
+{
+ makeContextCurrent();
+ ::glVertexAttrib3fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+ makeContextCurrent();
+ ::glVertexAttrib4f(index, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::vertexAttrib4fv(GC3Duint index, GC3Dfloat* array)
+{
+ makeContextCurrent();
+ ::glVertexAttrib4fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset)
+{
+ makeContextCurrent();
+ ::glVertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)));
+}
+
+void GraphicsContext3D::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+ makeContextCurrent();
+ ::glViewport(x, y, width, height);
+}
+
+void GraphicsContext3D::getBooleanv(GC3Denum pname, GC3Dboolean* value)
+{
+ makeContextCurrent();
+ ::glGetBooleanv(pname, value);
+}
+
+void GraphicsContext3D::getBufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value)
+{
+ makeContextCurrent();
+ ::glGetBufferParameteriv(target, pname, value);
+}
+
+void GraphicsContext3D::getFloatv(GC3Denum pname, GC3Dfloat* value)
+{
+ makeContextCurrent();
+ ::glGetFloatv(pname, value);
+}
+
+void GraphicsContext3D::getFramebufferAttachmentParameteriv(GC3Denum target, GC3Denum attachment, GC3Denum pname, GC3Dint* value)
+{
+ makeContextCurrent();
+ if (attachment == DEPTH_STENCIL_ATTACHMENT)
+ attachment = DEPTH_ATTACHMENT; // Or STENCIL_ATTACHMENT, either works.
+ ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value);
+}
+
+void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value)
+{
+ // Need to emulate MAX_FRAGMENT/VERTEX_UNIFORM_VECTORS and MAX_VARYING_VECTORS
+ // because desktop GL's corresponding queries return the number of components
+ // whereas GLES2 return the number of vectors (each vector has 4 components).
+ // Therefore, the value returned by desktop GL needs to be divided by 4.
+ makeContextCurrent();
+ switch (pname) {
+ case MAX_FRAGMENT_UNIFORM_VECTORS:
+ ::glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, value);
+ *value /= 4;
+ break;
+ case MAX_VERTEX_UNIFORM_VECTORS:
+ ::glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, value);
+ *value /= 4;
+ break;
+ case MAX_VARYING_VECTORS:
+ ::glGetIntegerv(GL_MAX_VARYING_FLOATS, value);
+ *value /= 4;
+ break;
+ default:
+ ::glGetIntegerv(pname, value);
+ }
+}
+
+void GraphicsContext3D::getProgramiv(Platform3DObject program, GC3Denum pname, GC3Dint* value)
+{
+ makeContextCurrent();
+ ::glGetProgramiv(program, pname, value);
+}
+
+String GraphicsContext3D::getProgramInfoLog(Platform3DObject program)
+{
+ ASSERT(program);
+
+ makeContextCurrent();
+ GLint length;
+ ::glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
+ if (!length)
+ return "";
+
+ GLsizei size;
+ GLchar* info = (GLchar*) fastMalloc(length);
+
+ ::glGetProgramInfoLog(program, length, &size, info);
+ String s(info);
+ fastFree(info);
+ return s;
+}
+
+void GraphicsContext3D::getRenderbufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value)
+{
+ makeContextCurrent();
+ ::glGetRenderbufferParameterivEXT(target, pname, value);
+}
+
+void GraphicsContext3D::getShaderiv(Platform3DObject shader, GC3Denum pname, GC3Dint* value)
+{
+ ASSERT(shader);
+
+ makeContextCurrent();
+
+ HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader);
+
+ switch (pname) {
+ case DELETE_STATUS:
+ case SHADER_TYPE:
+ // Let OpenGL handle these.
+
+ ::glGetShaderiv(shader, pname, value);
+ break;
+
+ case COMPILE_STATUS:
+ if (result == m_shaderSourceMap.end()) {
+ (*value) = static_cast<int>(false);
+ return;
+ }
+
+ (*value) = static_cast<int>(result->second.isValid);
+ break;
+
+ case INFO_LOG_LENGTH:
+ if (result == m_shaderSourceMap.end()) {
+ (*value) = 0;
+ return;
+ }
+
+ (*value) = getShaderInfoLog(shader).length();
+ break;
+
+ case SHADER_SOURCE_LENGTH:
+ (*value) = getShaderSource(shader).length();
+ break;
+
+ default:
+ synthesizeGLError(INVALID_ENUM);
+ }
+}
+
+String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader)
+{
+ ASSERT(shader);
+
+ makeContextCurrent();
+
+ HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader);
+
+ if (result == m_shaderSourceMap.end())
+ return "";
+
+ ShaderSourceEntry entry = result->second;
+
+ if (entry.isValid) {
+ GLint length;
+ ::glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
+ if (!length)
+ return "";
+
+ GLsizei size;
+ GLchar* info = (GLchar*) fastMalloc(length);
+
+ ::glGetShaderInfoLog(shader, length, &size, info);
+
+ String s(info);
+ fastFree(info);
+ return s;
+ } else
+ return entry.log;
+}
+
+String GraphicsContext3D::getShaderSource(Platform3DObject shader)
+{
+ ASSERT(shader);
+
+ makeContextCurrent();
+
+ HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader);
+
+ if (result == m_shaderSourceMap.end())
+ return "";
+
+ return result->second.source;
+}
+
+
+void GraphicsContext3D::getTexParameterfv(GC3Denum target, GC3Denum pname, GC3Dfloat* value)
+{
+ makeContextCurrent();
+ ::glGetTexParameterfv(target, pname, value);
+}
+
+void GraphicsContext3D::getTexParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value)
+{
+ makeContextCurrent();
+ ::glGetTexParameteriv(target, pname, value);
+}
+
+void GraphicsContext3D::getUniformfv(Platform3DObject program, GC3Dint location, GC3Dfloat* value)
+{
+ makeContextCurrent();
+ ::glGetUniformfv(program, location, value);
+}
+
+void GraphicsContext3D::getUniformiv(Platform3DObject program, GC3Dint location, GC3Dint* value)
+{
+ makeContextCurrent();
+ ::glGetUniformiv(program, location, value);
+}
+
+GC3Dint GraphicsContext3D::getUniformLocation(Platform3DObject program, const String& name)
+{
+ ASSERT(program);
+
+ makeContextCurrent();
+ return ::glGetUniformLocation(program, name.utf8().data());
+}
+
+void GraphicsContext3D::getVertexAttribfv(GC3Duint index, GC3Denum pname, GC3Dfloat* value)
+{
+ makeContextCurrent();
+ ::glGetVertexAttribfv(index, pname, value);
+}
+
+void GraphicsContext3D::getVertexAttribiv(GC3Duint index, GC3Denum pname, GC3Dint* value)
+{
+ makeContextCurrent();
+ ::glGetVertexAttribiv(index, pname, value);
+}
+
+GC3Dsizeiptr GraphicsContext3D::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
+{
+ makeContextCurrent();
+
+ GLvoid* pointer = 0;
+ ::glGetVertexAttribPointerv(index, pname, &pointer);
+ return static_cast<GC3Dsizeiptr>(reinterpret_cast<intptr_t>(pointer));
+}
+
+bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels)
+{
+ if (width && height && !pixels) {
+ synthesizeGLError(INVALID_VALUE);
+ return false;
+ }
+ makeContextCurrent();
+ GC3Denum openGLInternalFormat = internalformat;
+ if (type == GL_FLOAT) {
+ if (format == GL_RGBA)
+ openGLInternalFormat = GL_RGBA32F_ARB;
+ else if (format == GL_RGB)
+ openGLInternalFormat = GL_RGB32F_ARB;
+ }
+
+ ::glTexImage2D(target, level, openGLInternalFormat, width, height, border, format, type, pixels);
+ return true;
+}
+
+void GraphicsContext3D::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoff, GC3Dint yoff, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels)
+{
+ makeContextCurrent();
+
+ // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
+ ::glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels);
+}
+
+Platform3DObject GraphicsContext3D::createBuffer()
+{
+ makeContextCurrent();
+ GLuint o = 0;
+ glGenBuffers(1, &o);
+ return o;
+}
+
+Platform3DObject GraphicsContext3D::createFramebuffer()
+{
+ makeContextCurrent();
+ GLuint o = 0;
+ glGenFramebuffersEXT(1, &o);
+ return o;
+}
+
+Platform3DObject GraphicsContext3D::createProgram()
+{
+ makeContextCurrent();
+ return glCreateProgram();
+}
+
+Platform3DObject GraphicsContext3D::createRenderbuffer()
+{
+ makeContextCurrent();
+ GLuint o = 0;
+ glGenRenderbuffersEXT(1, &o);
+ return o;
+}
+
+Platform3DObject GraphicsContext3D::createShader(GC3Denum type)
+{
+ makeContextCurrent();
+ return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER);
+}
+
+Platform3DObject GraphicsContext3D::createTexture()
+{
+ makeContextCurrent();
+ GLuint o = 0;
+ glGenTextures(1, &o);
+ return o;
+}
+
+void GraphicsContext3D::deleteBuffer(Platform3DObject buffer)
+{
+ makeContextCurrent();
+ glDeleteBuffers(1, &buffer);
+}
+
+void GraphicsContext3D::deleteFramebuffer(Platform3DObject framebuffer)
+{
+ makeContextCurrent();
+ glDeleteFramebuffersEXT(1, &framebuffer);
+}
+
+void GraphicsContext3D::deleteProgram(Platform3DObject program)
+{
+ makeContextCurrent();
+ glDeleteProgram(program);
+}
+
+void GraphicsContext3D::deleteRenderbuffer(Platform3DObject renderbuffer)
+{
+ makeContextCurrent();
+ glDeleteRenderbuffersEXT(1, &renderbuffer);
+}
+
+void GraphicsContext3D::deleteShader(Platform3DObject shader)
+{
+ makeContextCurrent();
+ glDeleteShader(shader);
+}
+
+void GraphicsContext3D::deleteTexture(Platform3DObject texture)
+{
+ makeContextCurrent();
+ glDeleteTextures(1, &texture);
+}
+
+uint32_t GraphicsContext3D::sizeInBytes(GC3Denum type)
+{
+ switch (type) {
+ case GL_BYTE:
+ return sizeof(GLbyte);
+ case GL_UNSIGNED_BYTE:
+ return sizeof(GLubyte);
+ case GL_SHORT:
+ return sizeof(GLshort);
+ case GL_UNSIGNED_SHORT:
+ return sizeof(GLushort);
+ case GL_INT:
+ return sizeof(GLint);
+ case GL_UNSIGNED_INT:
+ return sizeof(GLuint);
+ case GL_FLOAT:
+ return sizeof(GLfloat);
+ default:
+ return 0;
+ }
+}
+
+void GraphicsContext3D::synthesizeGLError(GC3Denum error)
+{
+ m_syntheticErrors.add(error);
+}
+
+Extensions3D* GraphicsContext3D::getExtensions()
+{
+ if (!m_extensions)
+ m_extensions = adoptPtr(new Extensions3DOpenGL);
+ return m_extensions.get();
+}
+
+}
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp
new file mode 100644
index 0000000..03f9b7c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp
@@ -0,0 +1,663 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "TextureMapperGL.h"
+
+#include "GraphicsContext.h"
+#include "HashMap.h"
+#include "Image.h"
+#include "PassRefPtr.h"
+#include "RefCounted.h"
+#include "Timer.h"
+
+#if defined(TEXMAP_OPENGL_ES_2)
+#include <GLES2/gl2.h>
+#elif OS(MAC_OS_X)
+#include <AGL/agl.h>
+#include <gl.h>
+#else
+#if OS(UNIX)
+#include <GL/glx.h>
+#endif
+#include <GL/gl.h>
+#endif
+
+#ifndef TEXMAP_OPENGL_ES2
+extern "C" {
+ void glUniform1f(GLint, GLfloat);
+ void glUniform1i(GLint, GLint);
+ void glVertexAttribPointer(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);
+ void glUniform4f(GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+ void glShaderSource(GLuint, GLsizei, const char**, const GLint*);
+ GLuint glCreateShader(GLenum);
+ void glShaderSource(GLuint, GLsizei, const char**, const GLint*);
+ void glCompileShader(GLuint);
+ void glDeleteShader(GLuint);
+ void glUniformMatrix4fv(GLint, GLsizei, GLboolean, const GLfloat*);
+ GLuint glCreateProgram();
+ void glAttachShader(GLuint, GLuint);
+ void glLinkProgram(GLuint);
+ void glUseProgram(GLuint);
+ void glDisableVertexAttribArray(GLuint);
+ void glEnableVertexAttribArray(GLuint);
+ void glBindFramebuffer(GLenum target, GLuint framebuffer);
+ void glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
+ void glGenFramebuffers(GLsizei n, GLuint* framebuffers);
+ void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+ void glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+ void glBindBuffer(GLenum, GLuint);
+ void glDeleteBuffers(GLsizei, const GLuint*);
+ void glGenBuffers(GLsizei, GLuint*);
+ void glBufferData(GLenum, GLsizeiptr, const GLvoid*, GLenum);
+ void glBufferSubData(GLenum, GLsizeiptr, GLsizeiptr, const GLvoid*);
+ void glGetProgramInfoLog(GLuint program, GLsizei, GLsizei*, GLchar*);
+
+#if !OS(MAC_OS_X)
+ GLint glGetUniformLocation(GLuint, const GLchar*);
+ GLint glBindAttribLocation(GLuint, GLuint, const GLchar*);
+#endif
+}
+#endif
+
+namespace WebCore {
+
+inline static void debugGLCommand(const char* command, int line)
+{
+ const GLenum err = glGetError();
+ if (!err)
+ return;
+ WTFReportError(__FILE__, line, WTF_PRETTY_FUNCTION, "[TextureMapper GL] Command failed: %s (%x)\n", command, err);
+}
+
+#define DEBUG_GL_COMMANDS
+
+#ifdef DEBUG_GL_COMMANDS
+#define GL_CMD(x) {x, debugGLCommand(#x, __LINE__); }
+#else
+#define GL_CMD(x) x
+#endif
+
+static const GLuint gInVertexAttributeIndex = 0;
+
+struct TextureMapperGLData {
+ static struct ShaderInfo {
+ enum ShaderProgramIndex {
+ SimpleProgram,
+ OpacityAndMaskProgram,
+ TargetProgram,
+
+ ProgramCount
+ };
+
+ enum ShaderVariableIndex {
+ InMatrixVariable,
+ InSourceMatrixVariable,
+ InMaskMatrixVariable,
+ OpacityVariable,
+ SourceTextureVariable,
+ MaskTextureVariable,
+
+ VariableCount
+ };
+
+ struct ProgramInfo {
+ GLuint id;
+ GLint vars[VariableCount];
+ };
+
+ GLint getUniformLocation(ShaderProgramIndex prog, ShaderVariableIndex var, const char* name)
+ {
+ return programs[prog].vars[var] = glGetUniformLocation(programs[prog].id, name);
+ }
+
+ void createShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource, ShaderProgramIndex index)
+ {
+ GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
+ GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+ GL_CMD(glShaderSource(vertexShader, 1, &vertexShaderSource, 0))
+ GL_CMD(glShaderSource(fragmentShader, 1, &fragmentShaderSource, 0))
+ GLuint programID = glCreateProgram();
+ GL_CMD(glCompileShader(vertexShader))
+ GL_CMD(glCompileShader(fragmentShader))
+ GL_CMD(glAttachShader(programID, vertexShader))
+ GL_CMD(glAttachShader(programID, fragmentShader))
+ GL_CMD(glBindAttribLocation(programID, gInVertexAttributeIndex, "InVertex"))
+ GL_CMD(glLinkProgram(programID))
+ programs[index].id = programID;
+#ifdef PRINT_PROGRAM_INFO_LOG
+ char infoLog[1024];
+ int len;
+ GL_CMD(glGetProgramInfoLog(programID, 1024, &len, infoLog));
+ LOG(Graphics, "Compiled program for texture mapper. Log: %s\n", infoLog);
+#endif
+ }
+
+ ProgramInfo programs[ProgramCount];
+
+ } shaderInfo;
+
+ struct DirectlyCompositedImageRepository {
+ struct Entry {
+ GLuint texture;
+ int refCount;
+ };
+ HashMap<NativeImagePtr, Entry> imageToTexture;
+
+ GLuint findOrCreate(NativeImagePtr image, bool& found)
+ {
+ HashMap<NativeImagePtr, Entry>::iterator it = imageToTexture.find(image);
+ found = false;
+ if (it != imageToTexture.end()) {
+ it->second.refCount++;
+ found = true;
+ return it->second.texture;
+ }
+ Entry entry;
+ GL_CMD(glGenTextures(1, &entry.texture));
+ entry.refCount = 1;
+ imageToTexture.add(image, entry);
+ return entry.texture;
+ }
+
+ bool deref(NativeImagePtr image)
+ {
+ HashMap<NativeImagePtr, Entry>::iterator it = imageToTexture.find(image);
+ if (it != imageToTexture.end()) {
+ if (it->second.refCount < 2) {
+ imageToTexture.remove(it);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ DirectlyCompositedImageRepository()
+ {
+ }
+
+ ~DirectlyCompositedImageRepository()
+ {
+ for (HashMap<NativeImagePtr, Entry>::iterator it = imageToTexture.begin(); it != imageToTexture.end(); ++it) {
+ GLuint texture = it->second.texture;
+ if (texture)
+ GL_CMD(glDeleteTextures(1, &texture));
+ }
+
+ }
+ } directlyCompositedImages;
+
+ TextureMapperGLData()
+ : currentProgram(TextureMapperGLData::ShaderInfo::TargetProgram)
+ { }
+
+ TransformationMatrix projectionMatrix;
+ int currentProgram;
+
+#if OS(MAC_OS_X)
+ AGLContext aglContext;
+#elif OS(UNIX)
+ Drawable glxDrawable;
+ GLXContext glxContext;
+#endif
+};
+
+TextureMapperGLData::ShaderInfo TextureMapperGLData::shaderInfo;
+
+class BitmapTextureGL : public BitmapTexture {
+public:
+ virtual void destroy();
+ virtual IntSize size() const;
+ virtual bool isValid() const;
+ virtual void reset(const IntSize&, bool opaque);
+ virtual PlatformGraphicsContext* beginPaint(const IntRect& dirtyRect);
+ virtual void endPaint();
+ virtual void setContentsToImage(Image*);
+ ~BitmapTextureGL() { destroy(); }
+
+private:
+ GLuint m_id;
+ NativeImagePtr m_image;
+ FloatSize m_relativeSize;
+ bool m_opaque;
+ IntSize m_textureSize;
+ RefPtr<RGBA32PremultimpliedBuffer> m_buffer;
+ IntRect m_dirtyRect;
+ GLuint m_fbo;
+ IntSize m_actualSize;
+ bool m_surfaceNeedsReset;
+ TextureMapperGL* m_textureMapper;
+ BitmapTextureGL()
+ : m_id(0)
+ , m_image(0)
+ , m_opaque(false)
+ , m_fbo(0)
+ , m_surfaceNeedsReset(true)
+ , m_textureMapper(0)
+ {
+ }
+
+ friend class TextureMapperGL;
+};
+
+#define TEXMAP_GET_SHADER_VAR_LOCATION(prog, var) \
+ if (TextureMapperGLData::shaderInfo.getUniformLocation(TextureMapperGLData::shaderInfo.prog##Program, TextureMapperGLData::shaderInfo.var##Variable, #var) < 0) \
+ LOG_ERROR("Couldn't find variable "#var" in program "#prog"\n");
+
+#define TEXMAP_BUILD_SHADER(program) \
+ TextureMapperGLData::shaderInfo.createShaderProgram(vertexShaderSource##program, fragmentShaderSource##program, TextureMapperGLData::shaderInfo.program##Program);
+
+TextureMapperGL::TextureMapperGL()
+ : m_data(new TextureMapperGLData)
+{
+ static bool shadersCompiled = false;
+ obtainCurrentContext();
+ if (shadersCompiled)
+ return;
+ shadersCompiled = true;
+#ifndef TEXMAP_OPENGL_ES2
+#define OES2_PRECISION_DEFINITIONS \
+ "#define lowp\n#define highp\n"
+#else
+#define OES2_PRECISION_DEFINITIONS
+#endif
+
+ const char* fragmentShaderSourceOpacityAndMask =
+ OES2_PRECISION_DEFINITIONS
+" uniform sampler2D SourceTexture, MaskTexture; \n"
+" uniform lowp float Opacity; \n"
+" varying highp vec2 OutTexCoordSource, OutTexCoordMask; \n"
+" void main(void) \n"
+" { \n"
+" lowp vec4 color = texture2D(SourceTexture, OutTexCoordSource); \n"
+" lowp vec4 maskColor = texture2D(MaskTexture, OutTexCoordMask); \n"
+" lowp float o = Opacity * maskColor.a; \n"
+" gl_FragColor = vec4(color.rgb * o, color.a * o); \n"
+" } \n";
+
+ const char* vertexShaderSourceOpacityAndMask =
+ OES2_PRECISION_DEFINITIONS
+" uniform mat4 InMatrix, InSourceMatrix, InMaskMatrix; \n"
+" attribute vec4 InVertex; \n"
+" varying highp vec2 OutTexCoordSource, OutTexCoordMask; \n"
+" void main(void) \n"
+" { \n"
+" OutTexCoordSource = vec2(InSourceMatrix * InVertex); \n"
+" OutTexCoordMask = vec2(InMaskMatrix * InVertex); \n"
+" gl_Position = InMatrix * InVertex; \n"
+" } \n";
+
+ const char* fragmentShaderSourceSimple =
+ OES2_PRECISION_DEFINITIONS
+" uniform sampler2D SourceTexture; \n"
+" uniform lowp float Opacity; \n"
+" varying highp vec2 OutTexCoordSource; \n"
+" void main(void) \n"
+" { \n"
+" lowp vec4 color = texture2D(SourceTexture, OutTexCoordSource); \n"
+" gl_FragColor = vec4(color.rgb * Opacity, color.a * Opacity); \n"
+" } \n";
+
+ const char* vertexShaderSourceSimple =
+ OES2_PRECISION_DEFINITIONS
+" uniform mat4 InMatrix, InSourceMatrix; \n"
+" attribute vec4 InVertex; \n"
+" varying highp vec2 OutTexCoordSource; \n"
+" void main(void) \n"
+" { \n"
+" OutTexCoordSource = vec2(InSourceMatrix * InVertex); \n"
+" gl_Position = InMatrix * InVertex; \n"
+" } \n";
+
+ const char* fragmentShaderSourceTarget =
+ OES2_PRECISION_DEFINITIONS
+" uniform sampler2D SourceTexture; \n"
+" uniform lowp float Opacity; \n"
+" varying highp vec2 OutTexCoordSource; \n"
+" void main(void) \n"
+" { \n"
+" lowp vec4 color = texture2D(SourceTexture, OutTexCoordSource); \n"
+" gl_FragColor = vec4(color.bgr * Opacity, color.a * Opacity); \n"
+" } \n";
+
+ const char* vertexShaderSourceTarget = vertexShaderSourceSimple;
+
+ TEXMAP_BUILD_SHADER(Simple)
+ TEXMAP_BUILD_SHADER(OpacityAndMask)
+ TEXMAP_BUILD_SHADER(Target)
+
+ TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, InMatrix)
+ TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, InSourceMatrix)
+ TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, InMaskMatrix)
+ TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, SourceTexture)
+ TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, MaskTexture)
+ TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, Opacity)
+
+ TEXMAP_GET_SHADER_VAR_LOCATION(Simple, InSourceMatrix)
+ TEXMAP_GET_SHADER_VAR_LOCATION(Simple, InMatrix)
+ TEXMAP_GET_SHADER_VAR_LOCATION(Simple, SourceTexture)
+ TEXMAP_GET_SHADER_VAR_LOCATION(Simple, Opacity)
+
+ TEXMAP_GET_SHADER_VAR_LOCATION(Target, InSourceMatrix)
+ TEXMAP_GET_SHADER_VAR_LOCATION(Target, InMatrix)
+ TEXMAP_GET_SHADER_VAR_LOCATION(Target, SourceTexture)
+ TEXMAP_GET_SHADER_VAR_LOCATION(Target, Opacity)
+}
+
+void TextureMapperGL::drawTexture(const BitmapTexture& texture, const IntRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture)
+{
+ if (!texture.isValid())
+ return;
+
+ const BitmapTextureGL& textureGL = static_cast<const BitmapTextureGL&>(texture);
+
+ TextureMapperGLData::ShaderInfo::ShaderProgramIndex program;
+ if (maskTexture)
+ program = TextureMapperGLData::ShaderInfo::OpacityAndMaskProgram;
+ else
+ program = TextureMapperGLData::ShaderInfo::SimpleProgram;
+
+ const TextureMapperGLData::ShaderInfo::ProgramInfo& programInfo = data().shaderInfo.programs[program];
+ if (data().currentProgram != program) {
+ GL_CMD(glUseProgram(programInfo.id))
+ GL_CMD(glDisableVertexAttribArray(gInVertexAttributeIndex))
+ data().currentProgram = program;
+ GL_CMD(glEnableVertexAttribArray(gInVertexAttributeIndex))
+ }
+
+ GL_CMD(glDisable(GL_DEPTH_TEST))
+ GL_CMD(glDisable(GL_STENCIL_TEST))
+
+ GL_CMD(glActiveTexture(GL_TEXTURE0))
+ GL_CMD(glBindTexture(GL_TEXTURE_2D, textureGL.m_id))
+ GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0))
+ const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1};
+ GL_CMD(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, unitRect))
+
+ TransformationMatrix matrix = TransformationMatrix(data().projectionMatrix).multLeft(modelViewMatrix).multLeft(TransformationMatrix(
+ targetRect.width(), 0, 0, 0,
+ 0, targetRect.height(), 0, 0,
+ 0, 0, 1, 0,
+ targetRect.x(), targetRect.y(), 0, 1));
+
+ const GLfloat m4[] = {
+ matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(),
+ matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(),
+ matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(),
+ matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44()
+ };
+ const GLfloat m4src[] = {textureGL.m_relativeSize.width(), 0, 0, 0,
+ 0, textureGL.m_relativeSize.height(), 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1};
+ GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InMatrixVariable], 1, GL_FALSE, m4))
+ GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InSourceMatrixVariable], 1, GL_FALSE, m4src))
+ GL_CMD(glUniform1i(programInfo.vars[TextureMapperGLData::ShaderInfo::SourceTextureVariable], 0))
+ GL_CMD(glUniform1f(programInfo.vars[TextureMapperGLData::ShaderInfo::OpacityVariable], opacity))
+
+ if (maskTexture && maskTexture->isValid()) {
+ const BitmapTextureGL* maskTextureGL = static_cast<const BitmapTextureGL*>(maskTexture);
+ GL_CMD(glActiveTexture(GL_TEXTURE1))
+ GL_CMD(glBindTexture(GL_TEXTURE_2D, maskTextureGL->m_id))
+ const GLfloat m4mask[] = {maskTextureGL->m_relativeSize.width(), 0, 0, 0,
+ 0, maskTextureGL->m_relativeSize.height(), 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1};
+ GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InMaskMatrixVariable], 1, GL_FALSE, m4mask));
+ GL_CMD(glUniform1i(programInfo.vars[TextureMapperGLData::ShaderInfo::MaskTextureVariable], 1))
+ GL_CMD(glActiveTexture(GL_TEXTURE0))
+ }
+
+ if (textureGL.m_opaque && opacity > 0.99 && !maskTexture)
+ GL_CMD(glDisable(GL_BLEND))
+ else {
+ GL_CMD(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA))
+ GL_CMD(glEnable(GL_BLEND))
+ }
+
+ GL_CMD(glDrawArrays(GL_TRIANGLE_FAN, 0, 4))
+}
+
+const char* TextureMapperGL::type() const
+{
+ return "OpenGL";
+}
+
+void BitmapTextureGL::reset(const IntSize& newSize, bool opaque)
+{
+ BitmapTexture::reset(newSize, opaque);
+ m_image = 0;
+ IntSize newTextureSize = nextPowerOfTwo(newSize);
+ bool justCreated = false;
+ if (!m_id) {
+ GL_CMD(glGenTextures(1, &m_id))
+ justCreated = true;
+ }
+
+ if (justCreated || newTextureSize.width() > m_textureSize.width() || newTextureSize.height() > m_textureSize.height()) {
+ m_textureSize = newTextureSize;
+ GL_CMD(glBindTexture(GL_TEXTURE_2D, m_id))
+ GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR))
+ GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR))
+ GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE))
+ GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE))
+ GL_CMD(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_textureSize.width(), m_textureSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0))
+ }
+ m_actualSize = newSize;
+ m_relativeSize = FloatSize(float(newSize.width()) / m_textureSize.width(), float(newSize.height()) / m_textureSize.height());
+ m_opaque = opaque;
+ m_surfaceNeedsReset = true;
+}
+
+PlatformGraphicsContext* BitmapTextureGL::beginPaint(const IntRect& dirtyRect)
+{
+ m_buffer = RGBA32PremultimpliedBuffer::create();
+ m_dirtyRect = dirtyRect;
+ return m_buffer->beginPaint(dirtyRect, m_opaque);
+}
+
+void BitmapTextureGL::endPaint()
+{
+ if (!m_buffer)
+ return;
+ m_buffer->endPaint();
+ GL_CMD(glBindTexture(GL_TEXTURE_2D, m_id))
+ GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirtyRect.x(), m_dirtyRect.y(), m_dirtyRect.width(), m_dirtyRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_buffer->data()))
+ m_buffer.clear();
+}
+
+void BitmapTextureGL::setContentsToImage(Image* image)
+{
+ NativeImagePtr nativeImage = image ? image->nativeImageForCurrentFrame() : 0;
+ if (!image || !nativeImage) {
+ if (m_image)
+ destroy();
+ return;
+ }
+
+ if (nativeImage == m_image)
+ return;
+ bool found = false;
+ GLuint newTextureID = m_textureMapper->data().directlyCompositedImages.findOrCreate(nativeImage, found);
+ if (newTextureID != m_id) {
+ destroy();
+ m_id = newTextureID;
+ reset(image->size(), false);
+ m_image = nativeImage;
+ if (!found) {
+ GraphicsContext context(beginPaint(IntRect(0, 0, m_textureSize.width(), m_textureSize.height())));
+ context.drawImage(image, ColorSpaceDeviceRGB, IntPoint(0, 0), CompositeCopy);
+ endPaint();
+ }
+ }
+}
+
+void BitmapTextureGL::destroy()
+{
+ if (m_id && (!m_image || !m_textureMapper->data().directlyCompositedImages.deref(m_image)))
+ GL_CMD(glDeleteTextures(1, &m_id))
+ if (m_fbo)
+ GL_CMD(glDeleteFramebuffers(1, &m_fbo))
+
+ m_fbo = 0;
+ m_id = 0;
+ m_textureSize = IntSize();
+ m_relativeSize = FloatSize(1, 1);
+}
+
+bool BitmapTextureGL::isValid() const
+{
+ return m_id;
+}
+
+IntSize BitmapTextureGL::size() const
+{
+ return m_textureSize;
+}
+
+static inline TransformationMatrix createProjectionMatrix(const IntSize& size, bool flip)
+{
+ return TransformationMatrix(2.0 / float(size.width()), 0, 0, 0,
+ 0, (flip ? -2.0 : 2.0) / float(size.height()), 0, 0,
+ 0, 0, -0.000001, 0,
+ -1, flip ? 1 : -1, 0, 1);
+}
+
+TextureMapperGL::~TextureMapperGL()
+{
+ makeContextCurrent();
+ delete m_data;
+}
+
+bool TextureMapperGL::makeContextCurrent()
+{
+#if OS(MAC_OS_X)
+ return aglSetCurrentContext(data().aglContext);
+#elif OS(UNIX)
+ Display* display = XOpenDisplay(0);
+ if (!display)
+ return false;
+ return glXMakeCurrent(display, data().glxDrawable, data().glxContext);
+#endif
+}
+
+void TextureMapperGL::obtainCurrentContext()
+{
+#if OS(MAC_OS_X)
+ data().aglContext = aglGetCurrentContext();
+#elif OS(UNIX)
+ data().glxDrawable = glXGetCurrentDrawable();
+ data().glxContext = glXGetCurrentContext();
+#endif
+}
+
+void TextureMapperGL::bindSurface(BitmapTexture *surfacePointer)
+{
+ BitmapTextureGL* surface = static_cast<BitmapTextureGL*>(surfacePointer);
+
+ if (!surface)
+ return;
+
+ TransformationMatrix matrix = createProjectionMatrix(surface->size(), false);
+ matrix.translate(-surface->offset().x(), -surface->offset().y());
+
+ if (surface->m_surfaceNeedsReset || !surface->m_fbo) {
+ if (!surface->m_fbo)
+ GL_CMD(glGenFramebuffers(1, &surface->m_fbo))
+ GL_CMD(glBindFramebuffer(GL_FRAMEBUFFER, surface->m_fbo))
+ GL_CMD(glBindTexture(GL_TEXTURE_2D, 0))
+ GL_CMD(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, surface->m_id, 0))
+ GL_CMD(glClearColor(0, 0, 0, 0))
+ GL_CMD(glClear(GL_COLOR_BUFFER_BIT))
+ surface->m_surfaceNeedsReset = false;
+ } else {
+ GL_CMD(glBindFramebuffer(GL_FRAMEBUFFER, surface->m_fbo))
+ }
+
+ GL_CMD(glViewport(0, 0, surface->size().width(), surface->size().height()))
+ data().projectionMatrix = matrix;
+}
+
+void TextureMapperGL::setClip(const IntRect& rect)
+{
+ GL_CMD(glScissor(rect.x(), rect.y(), rect.width(), rect.height()))
+ GL_CMD(glEnable(GL_SCISSOR_TEST))
+}
+
+
+void TextureMapperGL::paintToTarget(const BitmapTexture& aSurface, const IntSize& surfaceSize, const TransformationMatrix& transform, float opacity, const IntRect& visibleRect)
+{
+ const BitmapTextureGL& surface = static_cast<const BitmapTextureGL&>(aSurface);
+
+ // Create the model-view-projection matrix to display on screen.
+ TransformationMatrix matrix = createProjectionMatrix(surfaceSize, true).multLeft(transform).multLeft(
+ TransformationMatrix(
+ surface.m_actualSize.width(), 0, 0, 0,
+ 0, surface.m_actualSize.height(), 0, 0,
+ 0, 0, 1, 0,
+ surface.offset().x(), surface.offset().y(), 0, 1)
+ );
+
+ const GLfloat m4[] = {
+ matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(),
+ matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(),
+ matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(),
+ matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44()
+ };
+
+ const GLfloat m4src[] = {surface.m_relativeSize.width(), 0, 0, 0,
+ 0, surface.m_relativeSize.height(), 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1};
+
+ // We already blended the alpha in; the result is premultiplied.
+ GL_CMD(glUseProgram(data().shaderInfo.programs[TextureMapperGLData::ShaderInfo::TargetProgram].id))
+ GL_CMD(glBindFramebuffer(GL_FRAMEBUFFER, 0))
+ GL_CMD(glViewport(0, 0, surfaceSize.width(), surfaceSize.height()))
+ GL_CMD(glDisable(GL_STENCIL_TEST))
+ const TextureMapperGLData::ShaderInfo::ProgramInfo& programInfo = data().shaderInfo.programs[TextureMapperGLData::ShaderInfo::TargetProgram];
+ GL_CMD(glUniform1f(programInfo.vars[TextureMapperGLData::ShaderInfo::OpacityVariable], opacity))
+ GL_CMD(glActiveTexture(GL_TEXTURE0))
+ GL_CMD(glBindTexture(GL_TEXTURE_2D, surface.m_id))
+ GL_CMD(glUniform1i(programInfo.vars[TextureMapperGLData::ShaderInfo::SourceTextureVariable], 0))
+ GL_CMD(glEnableVertexAttribArray(gInVertexAttributeIndex))
+ GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InMatrixVariable], 1, GL_FALSE, m4))
+ GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InSourceMatrixVariable], 1, GL_FALSE, m4src))
+ GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0))
+ const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1};
+ GL_CMD(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, unitRect))
+ GL_CMD(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA))
+ GL_CMD(glEnable(GL_BLEND))
+ setClip(visibleRect);
+
+ GL_CMD(glDrawArrays(GL_TRIANGLE_FAN, 0, 4))
+ GL_CMD(glDisableVertexAttribArray(0))
+ GL_CMD(glUseProgram(0))
+ GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0))
+ data().currentProgram = TextureMapperGLData::ShaderInfo::TargetProgram;
+}
+
+PassRefPtr<BitmapTexture> TextureMapperGL::createTexture()
+{
+ BitmapTextureGL* texture = new BitmapTextureGL();
+ texture->m_textureMapper = this;
+ return adoptRef(texture);
+}
+
+};
diff --git a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h
new file mode 100644
index 0000000..8035abf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TextureMapperGL_h
+#define TextureMapperGL_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "FloatQuad.h"
+#include "IntSize.h"
+#include "TransformationMatrix.h"
+#include "texmap/TextureMapper.h"
+
+namespace WebCore {
+
+class TextureMapperGLData;
+
+// An OpenGL-ES2 implementation of TextureMapper.
+class TextureMapperGL : public TextureMapper {
+public:
+ TextureMapperGL();
+ virtual ~TextureMapperGL();
+
+ // reimps from TextureMapper
+ virtual void drawTexture(const BitmapTexture& texture, const IntRect&, const TransformationMatrix& transform, float opacity, const BitmapTexture* maskTexture);
+ virtual void bindSurface(BitmapTexture* surface);
+ virtual void setClip(const IntRect&);
+ virtual void paintToTarget(const BitmapTexture&, const IntSize&, const TransformationMatrix&, float opacity, const IntRect& visibleRect);
+ virtual bool allowSurfaceForRoot() const { return true; }
+ virtual PassRefPtr<BitmapTexture> createTexture();
+ virtual const char* type() const;
+ void obtainCurrentContext();
+ bool makeContextCurrent();
+ static PassOwnPtr<TextureMapperGL> create()
+ {
+ return new TextureMapperGL;
+ }
+
+private:
+ inline TextureMapperGLData& data() { return *m_data; }
+ TextureMapperGLData* m_data;
+ friend class BitmapTextureGL;
+};
+
+// An offscreen buffer to be rendered by software.
+class RGBA32PremultimpliedBuffer : public RefCounted<RGBA32PremultimpliedBuffer> {
+public:
+ virtual ~RGBA32PremultimpliedBuffer() {}
+ virtual PlatformGraphicsContext* beginPaint(const IntRect& dirtyRect, bool opaque) = 0;
+ virtual void endPaint() = 0;
+ virtual const void* data() const = 0;
+ static PassRefPtr<RGBA32PremultimpliedBuffer> create();
+};
+
+static inline int nextPowerOfTwo(int num)
+{
+ for (int i = 0x10000000; i > 0; i >>= 1) {
+ if (num == i)
+ return num;
+ if (num & i)
+ return (i << 1);
+ }
+ return 1;
+}
+
+static inline IntSize nextPowerOfTwo(const IntSize& size)
+{
+ return IntSize(nextPowerOfTwo(size.width()), nextPowerOfTwo(size.height()));
+}
+
+};
+
+#endif
+
+#endif
diff --git a/Source/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp b/Source/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp
new file mode 100644
index 0000000..14aed0d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#include "config.h"
+#if ENABLE(OPENTYPE_SANITIZER)
+#include "OpenTypeSanitizer.h"
+
+#include "SharedBuffer.h"
+#include "opentype-sanitiser.h"
+#include "ots-memory-stream.h"
+#include <wtf/OwnArrayPtr.h>
+
+namespace WebCore {
+
+PassRefPtr<SharedBuffer> OpenTypeSanitizer::sanitize()
+{
+ if (!m_buffer)
+ return 0;
+
+ // This is the largest web font size which we'll try to transcode.
+ static const size_t maxWebFontSize = 30 * 1024 * 1024; // 30 MB
+ if (m_buffer->size() > maxWebFontSize)
+ return 0;
+
+ // A transcoded font is usually smaller than an original font.
+ // However, it can be slightly bigger than the original one due to
+ // name table replacement and/or padding for glyf table.
+ //
+ // With WOFF fonts, however, we'll be decompressing, so the result can be
+ // much larger than the original.
+
+ ots::ExpandingMemoryStream output(m_buffer->size(), maxWebFontSize);
+ if (!ots::Process(&output, reinterpret_cast<const uint8_t*>(m_buffer->data()), m_buffer->size()))
+ return 0;
+
+ const size_t transcodeLen = output.Tell();
+ return SharedBuffer::create(static_cast<unsigned char*>(output.get()), transcodeLen);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(OPENTYPE_SANITIZER)
diff --git a/Source/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h b/Source/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h
new file mode 100644
index 0000000..3f93448
--- /dev/null
+++ b/Source/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009 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 OpenTypeSanitizer_h
+#define OpenTypeSanitizer_h
+
+#if ENABLE(OPENTYPE_SANITIZER)
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class SharedBuffer;
+
+class OpenTypeSanitizer {
+public:
+ explicit OpenTypeSanitizer(SharedBuffer* buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ PassRefPtr<SharedBuffer> sanitize();
+
+private:
+ SharedBuffer* const m_buffer;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(OPENTYPE_SANITIZER)
+#endif // OpenTypeSanitizer_h
diff --git a/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp
new file mode 100644
index 0000000..7f4547d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "OpenTypeUtilities.h"
+
+#include "SharedBuffer.h"
+
+namespace WebCore {
+
+struct BigEndianUShort {
+ operator unsigned short() const { return (v & 0x00ff) << 8 | v >> 8; }
+ BigEndianUShort(unsigned short u) : v((u & 0x00ff) << 8 | u >> 8) { }
+ unsigned short v;
+};
+
+struct BigEndianULong {
+ operator unsigned() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v & 0xff0000) >> 8 | v >> 24; }
+ BigEndianULong(unsigned u) : v((u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | u >> 24) { }
+ unsigned v;
+};
+
+#pragma pack(1)
+
+struct EOTPrefix {
+ unsigned eotSize;
+ unsigned fontDataSize;
+ unsigned version;
+ unsigned flags;
+ uint8_t fontPANOSE[10];
+ uint8_t charset;
+ uint8_t italic;
+ unsigned weight;
+ unsigned short fsType;
+ unsigned short magicNumber;
+ unsigned unicodeRange[4];
+ unsigned codePageRange[2];
+ unsigned checkSumAdjustment;
+ unsigned reserved[4];
+ unsigned short padding1;
+};
+
+struct TableDirectoryEntry {
+ BigEndianULong tag;
+ BigEndianULong checkSum;
+ BigEndianULong offset;
+ BigEndianULong length;
+};
+
+#if !PLATFORM(CG) || !defined(COREGRAPHICS_INCLUDES_CORESERVICES_HEADER)
+// Fixed type is not defined on non-CG and Windows platforms. |version| in sfntHeader
+// and headTable and |fontRevision| in headTable are of Fixed, but they're
+// not actually refered to anywhere. Therefore, we just have to match
+// the size (4 bytes). For the definition of Fixed type, see
+// http://developer.apple.com/documentation/mac/Legacy/GXEnvironment/GXEnvironment-356.html#HEADING356-6.
+typedef int32_t Fixed;
+#endif
+
+struct sfntHeader {
+ Fixed version;
+ BigEndianUShort numTables;
+ BigEndianUShort searchRange;
+ BigEndianUShort entrySelector;
+ BigEndianUShort rangeShift;
+ TableDirectoryEntry tables[1];
+};
+
+struct OS2Table {
+ BigEndianUShort version;
+ BigEndianUShort avgCharWidth;
+ BigEndianUShort weightClass;
+ BigEndianUShort widthClass;
+ BigEndianUShort fsType;
+ BigEndianUShort subscriptXSize;
+ BigEndianUShort subscriptYSize;
+ BigEndianUShort subscriptXOffset;
+ BigEndianUShort subscriptYOffset;
+ BigEndianUShort superscriptXSize;
+ BigEndianUShort superscriptYSize;
+ BigEndianUShort superscriptXOffset;
+ BigEndianUShort superscriptYOffset;
+ BigEndianUShort strikeoutSize;
+ BigEndianUShort strikeoutPosition;
+ BigEndianUShort familyClass;
+ uint8_t panose[10];
+ BigEndianULong unicodeRange[4];
+ uint8_t vendID[4];
+ BigEndianUShort fsSelection;
+ BigEndianUShort firstCharIndex;
+ BigEndianUShort lastCharIndex;
+ BigEndianUShort typoAscender;
+ BigEndianUShort typoDescender;
+ BigEndianUShort typoLineGap;
+ BigEndianUShort winAscent;
+ BigEndianUShort winDescent;
+ BigEndianULong codePageRange[2];
+ BigEndianUShort xHeight;
+ BigEndianUShort capHeight;
+ BigEndianUShort defaultChar;
+ BigEndianUShort breakChar;
+ BigEndianUShort maxContext;
+};
+
+struct headTable {
+ Fixed version;
+ Fixed fontRevision;
+ BigEndianULong checkSumAdjustment;
+ BigEndianULong magicNumber;
+ BigEndianUShort flags;
+ BigEndianUShort unitsPerEm;
+ long long created;
+ long long modified;
+ BigEndianUShort xMin;
+ BigEndianUShort xMax;
+ BigEndianUShort yMin;
+ BigEndianUShort yMax;
+ BigEndianUShort macStyle;
+ BigEndianUShort lowestRectPPEM;
+ BigEndianUShort fontDirectionHint;
+ BigEndianUShort indexToLocFormat;
+ BigEndianUShort glyphDataFormat;
+};
+
+struct nameRecord {
+ BigEndianUShort platformID;
+ BigEndianUShort encodingID;
+ BigEndianUShort languageID;
+ BigEndianUShort nameID;
+ BigEndianUShort length;
+ BigEndianUShort offset;
+};
+
+struct nameTable {
+ BigEndianUShort format;
+ BigEndianUShort count;
+ BigEndianUShort stringOffset;
+ nameRecord nameRecords[1];
+};
+
+#pragma pack()
+
+EOTHeader::EOTHeader()
+{
+ m_buffer.resize(sizeof(EOTPrefix));
+}
+
+void EOTHeader::updateEOTSize(size_t fontDataSize)
+{
+ prefix()->eotSize = m_buffer.size() + fontDataSize;
+}
+
+void EOTHeader::appendBigEndianString(const BigEndianUShort* string, unsigned short length)
+{
+ size_t oldSize = m_buffer.size();
+ m_buffer.resize(oldSize + length + 2 * sizeof(unsigned short));
+ UChar* dst = reinterpret_cast<UChar*>(m_buffer.data() + oldSize);
+ unsigned i = 0;
+ dst[i++] = length;
+ unsigned numCharacters = length / 2;
+ for (unsigned j = 0; j < numCharacters; j++)
+ dst[i++] = string[j];
+ dst[i] = 0;
+}
+
+void EOTHeader::appendPaddingShort()
+{
+ unsigned short padding = 0;
+ m_buffer.append(reinterpret_cast<uint8_t*>(&padding), sizeof(padding));
+}
+
+bool getEOTHeader(SharedBuffer* fontData, EOTHeader& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
+{
+ overlayDst = 0;
+ overlaySrc = 0;
+ overlayLength = 0;
+
+ size_t dataLength = fontData->size();
+ const char* data = fontData->data();
+
+ EOTPrefix* prefix = eotHeader.prefix();
+
+ prefix->fontDataSize = dataLength;
+ prefix->version = 0x00020001;
+ prefix->flags = 0;
+
+ if (dataLength < offsetof(sfntHeader, tables))
+ return false;
+
+ const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(data);
+
+ if (dataLength < offsetof(sfntHeader, tables) + sfnt->numTables * sizeof(TableDirectoryEntry))
+ return false;
+
+ bool haveOS2 = false;
+ bool haveHead = false;
+ bool haveName = false;
+
+ const BigEndianUShort* familyName = 0;
+ unsigned short familyNameLength = 0;
+ const BigEndianUShort* subfamilyName = 0;
+ unsigned short subfamilyNameLength = 0;
+ const BigEndianUShort* fullName = 0;
+ unsigned short fullNameLength = 0;
+ const BigEndianUShort* versionString = 0;
+ unsigned short versionStringLength = 0;
+
+ for (unsigned i = 0; i < sfnt->numTables; i++) {
+ unsigned tableOffset = sfnt->tables[i].offset;
+ unsigned tableLength = sfnt->tables[i].length;
+
+ if (dataLength < tableOffset || dataLength < tableLength || dataLength < tableOffset + tableLength)
+ return false;
+
+ unsigned tableTag = sfnt->tables[i].tag;
+ switch (tableTag) {
+ case 'OS/2':
+ {
+ if (dataLength < tableOffset + sizeof(OS2Table))
+ return false;
+
+ haveOS2 = true;
+ const OS2Table* OS2 = reinterpret_cast<const OS2Table*>(data + tableOffset);
+ for (unsigned j = 0; j < 10; j++)
+ prefix->fontPANOSE[j] = OS2->panose[j];
+ prefix->italic = OS2->fsSelection & 0x01;
+ prefix->weight = OS2->weightClass;
+ // FIXME: Should use OS2->fsType, but some TrueType fonts set it to an over-restrictive value.
+ // Since ATS does not enforce this on Mac OS X, we do not enforce it either.
+ prefix->fsType = 0;
+ for (unsigned j = 0; j < 4; j++)
+ prefix->unicodeRange[j] = OS2->unicodeRange[j];
+ for (unsigned j = 0; j < 2; j++)
+ prefix->codePageRange[j] = OS2->codePageRange[j];
+ break;
+ }
+ case 'head':
+ {
+ if (dataLength < tableOffset + sizeof(headTable))
+ return false;
+
+ haveHead = true;
+ const headTable* head = reinterpret_cast<const headTable*>(data + tableOffset);
+ prefix->checkSumAdjustment = head->checkSumAdjustment;
+ break;
+ }
+ case 'name':
+ {
+ if (dataLength < tableOffset + offsetof(nameTable, nameRecords))
+ return false;
+
+ haveName = true;
+ const nameTable* name = reinterpret_cast<const nameTable*>(data + tableOffset);
+ for (int j = 0; j < name->count; j++) {
+ if (dataLength < tableOffset + offsetof(nameTable, nameRecords) + (j + 1) * sizeof(nameRecord))
+ return false;
+ if (name->nameRecords[j].platformID == 3 && name->nameRecords[j].encodingID == 1 && name->nameRecords[j].languageID == 0x0409) {
+ if (dataLength < tableOffset + name->stringOffset + name->nameRecords[j].offset + name->nameRecords[j].length)
+ return false;
+
+ unsigned short nameLength = name->nameRecords[j].length;
+ const BigEndianUShort* nameString = reinterpret_cast<const BigEndianUShort*>(data + tableOffset + name->stringOffset + name->nameRecords[j].offset);
+
+ switch (name->nameRecords[j].nameID) {
+ case 1:
+ familyNameLength = nameLength;
+ familyName = nameString;
+ break;
+ case 2:
+ subfamilyNameLength = nameLength;
+ subfamilyName = nameString;
+ break;
+ case 4:
+ fullNameLength = nameLength;
+ fullName = nameString;
+ break;
+ case 5:
+ versionStringLength = nameLength;
+ versionString = nameString;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (haveOS2 && haveHead && haveName)
+ break;
+ }
+
+ prefix->charset = DEFAULT_CHARSET;
+ prefix->magicNumber = 0x504c;
+ prefix->reserved[0] = 0;
+ prefix->reserved[1] = 0;
+ prefix->reserved[2] = 0;
+ prefix->reserved[3] = 0;
+ prefix->padding1 = 0;
+
+ eotHeader.appendBigEndianString(familyName, familyNameLength);
+ eotHeader.appendBigEndianString(subfamilyName, subfamilyNameLength);
+ eotHeader.appendBigEndianString(versionString, versionStringLength);
+
+ // If possible, ensure that the family name is a prefix of the full name.
+ if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, familyNameLength)) {
+ overlaySrc = reinterpret_cast<const char*>(fullName) - data;
+ overlayDst = reinterpret_cast<const char*>(familyName) - data;
+ overlayLength = familyNameLength;
+ }
+ eotHeader.appendBigEndianString(fullName, fullNameLength);
+
+ eotHeader.appendPaddingShort();
+ eotHeader.updateEOTSize(fontData->size());
+
+ return true;
+}
+
+// code shared by renameFont and renameAndActivateFont
+// adds fontName to the font table in fontData, and writes the new font table to rewrittenFontTable
+// returns the size of the name table (which is used by renameAndActivateFont), or 0 on early abort
+static size_t renameFontInternal(SharedBuffer* fontData, const String& fontName, Vector<char> &rewrittenFontData)
+{
+ size_t originalDataSize = fontData->size();
+ const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(fontData->data());
+
+ unsigned t;
+ for (t = 0; t < sfnt->numTables; ++t) {
+ if (sfnt->tables[t].tag == 'name')
+ break;
+ }
+ if (t == sfnt->numTables)
+ return 0;
+
+ const int nameRecordCount = 5;
+
+ // Rounded up to a multiple of 4 to simplify the checksum calculation.
+ size_t nameTableSize = ((offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord) + fontName.length() * sizeof(UChar)) & ~3) + 4;
+
+ rewrittenFontData.resize(fontData->size() + nameTableSize);
+ char* data = rewrittenFontData.data();
+ memcpy(data, fontData->data(), originalDataSize);
+
+ // Make the table directory entry point to the new 'name' table.
+ sfntHeader* rewrittenSfnt = reinterpret_cast<sfntHeader*>(data);
+ rewrittenSfnt->tables[t].length = nameTableSize;
+ rewrittenSfnt->tables[t].offset = originalDataSize;
+
+ // Write the new 'name' table after the original font data.
+ nameTable* name = reinterpret_cast<nameTable*>(data + originalDataSize);
+ name->format = 0;
+ name->count = nameRecordCount;
+ name->stringOffset = offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord);
+ for (unsigned i = 0; i < nameRecordCount; ++i) {
+ name->nameRecords[i].platformID = 3;
+ name->nameRecords[i].encodingID = 1;
+ name->nameRecords[i].languageID = 0x0409;
+ name->nameRecords[i].offset = 0;
+ name->nameRecords[i].length = fontName.length() * sizeof(UChar);
+ }
+
+ // The required 'name' record types: Family, Style, Unique, Full and PostScript.
+ name->nameRecords[0].nameID = 1;
+ name->nameRecords[1].nameID = 2;
+ name->nameRecords[2].nameID = 3;
+ name->nameRecords[3].nameID = 4;
+ name->nameRecords[4].nameID = 6;
+
+ for (unsigned i = 0; i < fontName.length(); ++i)
+ reinterpret_cast<BigEndianUShort*>(data + originalDataSize + name->stringOffset)[i] = fontName[i];
+
+ // Update the table checksum in the directory entry.
+ rewrittenSfnt->tables[t].checkSum = 0;
+ for (unsigned i = 0; i * sizeof(BigEndianULong) < nameTableSize; ++i)
+ rewrittenSfnt->tables[t].checkSum = rewrittenSfnt->tables[t].checkSum + reinterpret_cast<BigEndianULong*>(name)[i];
+
+ return nameTableSize;
+}
+
+#if OS(WINCE)
+// AddFontMemResourceEx does not exist on WinCE, so we must handle the font data manually
+// This function just renames the font and overwrites the old font data with the new
+bool renameFont(SharedBuffer* fontData, const String& fontName)
+{
+ // abort if the data is too small to be a font header with a "tables" entry
+ if (fontData->size() < offsetof(sfntHeader, tables))
+ return false;
+
+ // abort if the data is too small to hold all the tables specified in the header
+ const sfntHeader* header = reinterpret_cast<const sfntHeader*>(fontData->data());
+ if (fontData->size() < offsetof(sfntHeader, tables) + header->numTables * sizeof(TableDirectoryEntry))
+ return false;
+
+ Vector<char> rewrittenFontData;
+ if (!renameFontInternal(fontData, fontName, rewrittenFontData))
+ return false;
+
+ fontData->clear();
+ fontData->append(rewrittenFontData.data(), rewrittenFontData.size());
+ return true;
+}
+#else
+// Rename the font and install the new font data into the system
+HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName)
+{
+ Vector<char> rewrittenFontData;
+ size_t nameTableSize = renameFontInternal(fontData, fontName, rewrittenFontData);
+ if (!nameTableSize)
+ return 0;
+
+ DWORD numFonts = 0;
+ HANDLE fontHandle = AddFontMemResourceEx(rewrittenFontData.data(), fontData->size() + nameTableSize, 0, &numFonts);
+
+ if (fontHandle && numFonts < 1) {
+ RemoveFontMemResourceEx(fontHandle);
+ return 0;
+ }
+
+ return fontHandle;
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.h b/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.h
new file mode 100644
index 0000000..0ef1b2b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 OpenTypeUtilities_h
+#define OpenTypeUtilities_h
+
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+struct BigEndianUShort;
+struct EOTPrefix;
+class SharedBuffer;
+
+#if OS(WINCE)
+typedef unsigned __int8 UInt8;
+#endif
+
+struct EOTHeader {
+ EOTHeader();
+
+ size_t size() const { return m_buffer.size(); }
+ const uint8_t* data() const { return m_buffer.data(); }
+
+ EOTPrefix* prefix() { return reinterpret_cast<EOTPrefix*>(m_buffer.data()); }
+ void updateEOTSize(size_t);
+ void appendBigEndianString(const BigEndianUShort*, unsigned short length);
+ void appendPaddingShort();
+
+private:
+ Vector<uint8_t, 512> m_buffer;
+};
+
+bool getEOTHeader(SharedBuffer* fontData, EOTHeader& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength);
+HANDLE renameAndActivateFont(SharedBuffer*, const String&);
+
+} // namespace WebCore
+
+#endif // OpenTypeUtilities_h
diff --git a/Source/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp
new file mode 100644
index 0000000..d681d75
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "EGLDisplayOpenVG.h"
+
+#include "EGLUtils.h"
+#include "IntSize.h"
+#include "SurfaceOpenVG.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+// Need to typedef this, otherwise DEFINE_STATIC_LOCAL() doesn't swallow it.
+typedef HashMap<EGLDisplay, EGLDisplayOpenVG*> EGLDisplayManagerMap;
+
+// File-static variables.
+static EGLDisplayManagerMap& displayManagers()
+{
+ DEFINE_STATIC_LOCAL(EGLDisplayManagerMap, managers, ());
+ return managers;
+}
+
+static EGLDisplayOpenVG* s_current = 0;
+
+// Static class members.
+
+SurfaceOpenVG* EGLDisplayOpenVG::currentSurface()
+{
+ EGLDisplayManagerMap& managers = displayManagers();
+ EGLDisplay currentDisplay = eglGetCurrentDisplay();
+
+ if (currentDisplay == EGL_NO_DISPLAY || !managers.contains(currentDisplay))
+ return 0;
+
+ EGLDisplayOpenVG* displayManager = managers.get(currentDisplay);
+ EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
+
+ if (currentSurface == EGL_NO_SURFACE || !displayManager->m_platformSurfaces.contains(currentSurface))
+ return 0;
+
+ return displayManager->m_platformSurfaces.get(currentSurface);
+}
+
+void EGLDisplayOpenVG::registerPlatformSurface(SurfaceOpenVG* platformSurface)
+{
+ EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
+ displayManager->m_platformSurfaces.set(platformSurface->eglSurface(), platformSurface);
+}
+
+void EGLDisplayOpenVG::unregisterPlatformSurface(SurfaceOpenVG* platformSurface)
+{
+ EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
+ displayManager->m_platformSurfaces.remove(platformSurface->eglSurface());
+}
+
+void EGLDisplayOpenVG::setCurrentDisplay(const EGLDisplay& display)
+{
+ s_current = EGLDisplayOpenVG::forDisplay(display);
+}
+
+EGLDisplayOpenVG* EGLDisplayOpenVG::current()
+{
+ if (!s_current) {
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(display, 0, 0);
+ ASSERT_EGL_NO_ERROR();
+
+ s_current = EGLDisplayOpenVG::forDisplay(display);
+ }
+ return s_current;
+}
+
+EGLDisplayOpenVG* EGLDisplayOpenVG::forDisplay(const EGLDisplay& display)
+{
+ EGLDisplayManagerMap& managers = displayManagers();
+
+ if (!managers.contains(display))
+ managers.set(display, new EGLDisplayOpenVG(display));
+
+ return managers.get(display);
+}
+
+
+// Object/instance members.
+
+EGLDisplayOpenVG::EGLDisplayOpenVG(const EGLDisplay& display)
+ : m_display(display)
+ , m_sharedPlatformSurface(0)
+ , m_pbufferConfigId(0)
+ , m_windowConfigId(0)
+{
+ eglBindAPI(EGL_OPENVG_API);
+ ASSERT_EGL_NO_ERROR();
+}
+
+EGLDisplayOpenVG::~EGLDisplayOpenVG()
+{
+ eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ ASSERT_EGL_NO_ERROR();
+
+ delete m_sharedPlatformSurface;
+
+ HashMap<EGLSurface, EGLint>::const_iterator end = m_surfaceConfigIds.end();
+ for (HashMap<EGLSurface, EGLint>::const_iterator it = m_surfaceConfigIds.begin(); it != end; ++it)
+ destroySurface((*it).first);
+
+ eglTerminate(m_display);
+ ASSERT_EGL_NO_ERROR();
+}
+
+void EGLDisplayOpenVG::setDefaultPbufferConfig(const EGLConfig& config)
+{
+ EGLint configId;
+ EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(configId != EGL_BAD_ATTRIBUTE);
+
+ m_pbufferConfigId = configId;
+}
+
+EGLConfig EGLDisplayOpenVG::defaultPbufferConfig()
+{
+ EGLConfig config;
+ EGLint numConfigs;
+
+ // Hopefully the client will have set the pbuffer config of its choice
+ // by now - if not, use a 32-bit generic one as default.
+ if (!m_pbufferConfigId) {
+ static const EGLint configAttribs[] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_ALPHA_MASK_SIZE, 1,
+ EGL_LUMINANCE_SIZE, EGL_DONT_CARE,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
+ EGL_NONE
+ };
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ } else {
+ const EGLint configAttribs[] = {
+ EGL_CONFIG_ID, m_pbufferConfigId,
+ EGL_NONE
+ };
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ }
+
+ ASSERT_EGL_NO_ERROR();
+ ASSERT(numConfigs == 1);
+ return config;
+}
+
+void EGLDisplayOpenVG::setDefaultWindowConfig(const EGLConfig& config)
+{
+ EGLint configId;
+ EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(configId != EGL_BAD_ATTRIBUTE);
+
+ m_windowConfigId = configId;
+}
+
+EGLConfig EGLDisplayOpenVG::defaultWindowConfig()
+{
+ EGLConfig config;
+ EGLint numConfigs;
+
+ // Hopefully the client will have set the window config of its choice
+ // by now - if not, use a 32-bit generic one as default.
+ if (!m_windowConfigId) {
+ static const EGLint configAttribs[] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_ALPHA_MASK_SIZE, 1,
+ EGL_LUMINANCE_SIZE, EGL_DONT_CARE,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
+ EGL_NONE
+ };
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ } else {
+ const EGLint configAttribs[] = {
+ EGL_CONFIG_ID, m_windowConfigId,
+ EGL_NONE
+ };
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ }
+
+ ASSERT_EGL_NO_ERROR();
+ ASSERT(numConfigs == 1);
+ return config;
+}
+
+SurfaceOpenVG* EGLDisplayOpenVG::sharedPlatformSurface()
+{
+ if (!m_sharedPlatformSurface) {
+ // The shared surface doesn't need to be drawn on, it just exists so
+ // that we can always make the shared context current (which in turn is
+ // the owner of long-living resources such as images, paths and fonts).
+ // We'll just make the shared surface as small as possible: 1x1 pixel.
+ EGLConfig config = defaultPbufferConfig();
+ EGLSurface surface = createPbufferSurface(IntSize(1, 1), config);
+
+ EGLContext context = eglCreateContext(m_display, config, EGL_NO_CONTEXT, 0);
+ ASSERT_EGL_NO_ERROR();
+ m_contexts.set(m_surfaceConfigIds.get(surface), context);
+
+ m_sharedPlatformSurface = new SurfaceOpenVG;
+ m_sharedPlatformSurface->m_eglDisplay = m_display;
+ m_sharedPlatformSurface->m_eglSurface = surface;
+ m_sharedPlatformSurface->m_eglContext = context;
+ m_platformSurfaces.set(surface, m_sharedPlatformSurface); // a.k.a. registerPlatformSurface()
+ }
+ return m_sharedPlatformSurface;
+}
+
+EGLSurface EGLDisplayOpenVG::createPbufferSurface(const IntSize& size, const EGLConfig& config, EGLint* errorCode)
+{
+ const EGLint attribList[] = {
+ EGL_WIDTH, size.width(),
+ EGL_HEIGHT, size.height(),
+ EGL_NONE
+ };
+ EGLSurface surface = eglCreatePbufferSurface(m_display, config, attribList);
+
+ if (errorCode)
+ *errorCode = eglGetError();
+ else
+ ASSERT_EGL_NO_ERROR();
+
+ if (surface == EGL_NO_SURFACE)
+ return EGL_NO_SURFACE;
+
+ EGLint surfaceConfigId;
+ EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
+
+ ASSERT(!m_surfaceConfigIds.contains(surface));
+ m_surfaceConfigIds.set(surface, surfaceConfigId);
+ return surface;
+}
+
+EGLSurface EGLDisplayOpenVG::createPbufferFromClientBuffer(
+ EGLClientBuffer clientBuffer, EGLenum bufferType, const EGLConfig& config, EGLint* errorCode)
+{
+ EGLSurface surface = eglCreatePbufferFromClientBuffer(m_display,
+ bufferType, clientBuffer, config, 0 /* attribList */);
+
+ if (errorCode)
+ *errorCode = eglGetError();
+ else
+ ASSERT_EGL_NO_ERROR();
+
+ if (surface == EGL_NO_SURFACE)
+ return EGL_NO_SURFACE;
+
+ EGLint surfaceConfigId;
+ EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
+
+ ASSERT(!m_surfaceConfigIds.contains(surface));
+ m_surfaceConfigIds.set(surface, surfaceConfigId);
+ return surface;
+}
+
+EGLSurface EGLDisplayOpenVG::surfaceForWindow(EGLNativeWindowType wId, const EGLConfig& config)
+{
+ if (m_windowSurfaces.contains(wId))
+ return m_windowSurfaces.get(wId);
+
+ EGLSurface surface = eglCreateWindowSurface(m_display, config, wId, 0);
+ ASSERT_EGL_NO_ERROR();
+
+ EGLint surfaceConfigId;
+ EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
+
+ ASSERT(!m_surfaceConfigIds.contains(surface));
+ m_surfaceConfigIds.set(surface, surfaceConfigId);
+ return surface;
+}
+
+bool EGLDisplayOpenVG::surfacesCompatible(const EGLSurface& surface, const EGLSurface& otherSurface)
+{
+ if (surface == EGL_NO_SURFACE || otherSurface == EGL_NO_SURFACE)
+ return false;
+
+ // Currently, we assume that all surfaces known to this object are
+ // context-compatible to each other (which is reasonable to assume,
+ // otherwise eglCreateContext() would fail with EGL_BAD_MATCH for shared
+ // context compatibility anyways.
+ return m_surfaceConfigIds.contains(surface) && m_surfaceConfigIds.contains(otherSurface);
+}
+
+void EGLDisplayOpenVG::destroySurface(const EGLSurface& surface)
+{
+ ASSERT(surface != EGL_NO_SURFACE);
+
+ if (eglGetCurrentSurface(EGL_DRAW) == surface) {
+ eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ ASSERT_EGL_NO_ERROR();
+ }
+
+ // Destroy the context associated to the surface, if we already created one.
+ if (m_surfaceConfigIds.contains(surface)) {
+ EGLint surfaceConfigId = m_surfaceConfigIds.take(surface); // take = get and remove
+ bool isContextReferenced = false;
+
+ if (m_compatibleConfigIds.contains(surfaceConfigId))
+ surfaceConfigId = m_compatibleConfigIds.get(surfaceConfigId);
+
+ HashMap<EGLSurface, EGLint>::iterator end = m_surfaceConfigIds.end();
+
+ // ...but only if there's no other surfaces associated to that context.
+ for (HashMap<EGLSurface, EGLint>::iterator it = m_surfaceConfigIds.begin(); it != end; ++it) {
+ if ((*it).second == surfaceConfigId) {
+ isContextReferenced = true;
+ break;
+ }
+ }
+ if (!isContextReferenced && m_contexts.contains(surfaceConfigId)) {
+ EGLContext context = m_contexts.take(surfaceConfigId);
+ eglDestroyContext(m_display, context);
+ ASSERT_EGL_NO_ERROR();
+ }
+ }
+
+ m_platformSurfaces.remove(surface);
+
+ HashMap<EGLNativeWindowType, EGLSurface>::iterator end = m_windowSurfaces.end();
+ for (HashMap<EGLNativeWindowType, EGLSurface>::iterator it = m_windowSurfaces.begin(); it != end; ++it) {
+ if ((*it).second == surface) {
+ m_windowSurfaces.remove(it);
+ break;
+ }
+ }
+
+ eglDestroySurface(m_display, surface);
+ ASSERT_EGL_NO_ERROR();
+}
+
+EGLContext EGLDisplayOpenVG::contextForSurface(const EGLSurface& surface)
+{
+ ASSERT(surface != EGL_NO_SURFACE);
+
+ if (m_platformSurfaces.contains(surface))
+ return m_platformSurfaces.get(surface)->eglContext();
+
+ eglBindAPI(EGL_OPENVG_API);
+ ASSERT_EGL_NO_ERROR();
+
+ EGLint surfaceConfigId;
+
+ if (m_surfaceConfigIds.contains(surface))
+ surfaceConfigId = m_surfaceConfigIds.get(surface);
+ else {
+ // Retrieve the same EGL config for context creation that was used to
+ // create the the EGL surface.
+ EGLBoolean success = eglQuerySurface(m_display, surface, EGL_CONFIG_ID, &surfaceConfigId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
+
+ m_surfaceConfigIds.set(surface, surfaceConfigId);
+ }
+
+ if (m_compatibleConfigIds.contains(surfaceConfigId))
+ surfaceConfigId = m_compatibleConfigIds.get(surfaceConfigId);
+
+ if (m_contexts.contains(surfaceConfigId))
+ return m_contexts.get(surfaceConfigId);
+
+ if (!m_sharedPlatformSurface) // shared context has not been created yet
+ sharedPlatformSurface(); // creates the shared surface & context
+
+ EGLDisplay currentDisplay = eglGetCurrentDisplay();
+ EGLSurface currentReadSurface = eglGetCurrentSurface(EGL_READ);
+ EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
+ EGLContext currentContext = eglGetCurrentContext();
+
+ // Before creating a new context, let's try whether an existing one
+ // is compatible with the surface. EGL doesn't give us a different way
+ // to check context/surface compatibility than trying it out, so let's
+ // do just that.
+ HashMap<EGLint, EGLContext>::iterator end = m_contexts.end();
+
+ for (HashMap<EGLint, EGLContext>::iterator it = m_contexts.begin(); it != end; ++it) {
+ eglMakeCurrent(m_display, surface, surface, (*it).second);
+ if (eglGetError() == EGL_SUCCESS) {
+ // Restore previous surface/context.
+ if (currentContext != EGL_NO_CONTEXT) {
+ eglMakeCurrent(currentDisplay, currentReadSurface, currentDrawSurface, currentContext);
+ ASSERT_EGL_NO_ERROR();
+ }
+ // Cool, surface is compatible to one of our existing contexts.
+ m_compatibleConfigIds.set(surfaceConfigId, (*it).first);
+ return (*it).second;
+ }
+ }
+ // Restore previous surface/context.
+ if (currentContext != EGL_NO_CONTEXT) {
+ eglMakeCurrent(currentDisplay, currentReadSurface, currentDrawSurface, currentContext);
+ ASSERT_EGL_NO_ERROR();
+ }
+
+ EGLConfig config;
+ EGLint numConfigs;
+
+ const EGLint configAttribs[] = {
+ EGL_CONFIG_ID, surfaceConfigId,
+ EGL_NONE
+ };
+
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ ASSERT_EGL_NO_ERROR();
+ ASSERT(numConfigs == 1);
+
+ // We share all of the images and paths amongst the different contexts,
+ // so that they can be used in all of them. Resources that are created
+ // while m_sharedPlatformSurface->context() is current will be
+ // accessible from all other contexts, but are not restricted to the
+ // lifetime of those contexts.
+ EGLContext context = eglCreateContext(m_display, config, m_sharedPlatformSurface->eglContext(), 0);
+ ASSERT_EGL_NO_ERROR();
+
+ ASSERT(!m_contexts.contains(surfaceConfigId));
+ m_contexts.set(surfaceConfigId, context);
+ return context;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h b/Source/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h
new file mode 100644
index 0000000..0dff6c9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EGLDisplayOpenVG_h
+#define EGLDisplayOpenVG_h
+
+#include <egl.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class IntSize;
+class SurfaceOpenVG;
+
+class EGLDisplayOpenVG {
+public:
+ friend class SurfaceOpenVG;
+
+ static SurfaceOpenVG* currentSurface();
+ static void setCurrentDisplay(const EGLDisplay&);
+ static EGLDisplayOpenVG* current();
+ static EGLDisplayOpenVG* forDisplay(const EGLDisplay&);
+
+ void setDefaultPbufferConfig(const EGLConfig&);
+ EGLConfig defaultPbufferConfig();
+ void setDefaultWindowConfig(const EGLConfig&);
+ EGLConfig defaultWindowConfig();
+
+ EGLDisplay display() const { return m_display; }
+ SurfaceOpenVG* sharedPlatformSurface();
+
+ /** Creates a pbuffer surface using the given config. If no surface
+ * could be created, EGL_NO_SURFACE is returned and errors can be
+ * checked with the value that is written to the errorCode parameter
+ * If no surface could be created and errorCode is zero, this method
+ * will trigger an assertion by itself. */
+ EGLSurface createPbufferSurface(const IntSize&, const EGLConfig&, EGLint* errorCode = 0);
+ EGLSurface createPbufferFromClientBuffer(EGLClientBuffer, EGLenum bufferType, const EGLConfig&, EGLint* errorCode = 0);
+
+ EGLSurface surfaceForWindow(EGLNativeWindowType, const EGLConfig&);
+
+ bool surfacesCompatible(const EGLSurface&, const EGLSurface&);
+
+ /** Destroy the surface and its corresponding context (unless another
+ * surface is still using the same context, in which case the context
+ * is not destroyed). */
+ void destroySurface(const EGLSurface&);
+
+ /** Return the context corresponding to the surface.
+ * If no corresponding context exists, one is created automatically. */
+ EGLContext contextForSurface(const EGLSurface&);
+
+private:
+ static void registerPlatformSurface(SurfaceOpenVG*);
+ static void unregisterPlatformSurface(SurfaceOpenVG*);
+
+ EGLDisplayOpenVG(const EGLDisplay& display);
+ ~EGLDisplayOpenVG();
+
+ EGLDisplay m_display;
+ SurfaceOpenVG* m_sharedPlatformSurface;
+ EGLint m_pbufferConfigId;
+ EGLint m_windowConfigId;
+
+ HashMap<EGLSurface, SurfaceOpenVG*> m_platformSurfaces;
+ HashMap<EGLNativeWindowType, EGLSurface> m_windowSurfaces;
+ HashMap<EGLSurface, EGLint> m_surfaceConfigIds;
+ HashMap<EGLint, EGLint> m_compatibleConfigIds;
+ HashMap<EGLint, EGLContext> m_contexts;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/openvg/EGLUtils.h b/Source/WebCore/platform/graphics/openvg/EGLUtils.h
new file mode 100644
index 0000000..6f5d793
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/EGLUtils.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EGLUtils_h
+#define EGLUtils_h
+
+#include <egl.h>
+#include <wtf/Assertions.h>
+
+static inline const char* toEGLErrorConstant(EGLint error)
+{
+ switch (error) {
+ case EGL_NOT_INITIALIZED:
+ return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS:
+ return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC:
+ return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE:
+ return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONTEXT:
+ return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CONFIG:
+ return "EGL_BAD_CONFIG";
+ case EGL_BAD_CURRENT_SURFACE:
+ return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY:
+ return "EGL_BAD_DISPLAY";
+ case EGL_BAD_SURFACE:
+ return "EGL_BAD_SURFACE";
+ case EGL_BAD_MATCH:
+ return "EGL_BAD_MATCH";
+ case EGL_BAD_PARAMETER:
+ return "EGL_BAD_PARAMETER";
+ case EGL_BAD_NATIVE_PIXMAP:
+ return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW:
+ return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_CONTEXT_LOST:
+ return "EGL_CONTEXT_LOST";
+ default:
+ return "UNKNOWN_ERROR";
+ }
+}
+
+#if ASSERT_DISABLED
+#define ASSERT_EGL_NO_ERROR() ((void)0)
+#else
+#define ASSERT_EGL_NO_ERROR() do { \
+ EGLint eglErrorCode = eglGetError(); \
+ ASSERT_WITH_MESSAGE(eglErrorCode == EGL_SUCCESS, "Found %s", toEGLErrorConstant(eglErrorCode)); \
+} while (0)
+#endif
+
+#endif
diff --git a/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp
new file mode 100644
index 0000000..6466a9c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "KURL.h"
+#include "NotImplemented.h"
+#include "PainterOpenVG.h"
+#include "SurfaceOpenVG.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(EGL)
+#include "EGLDisplayOpenVG.h"
+#include "EGLUtils.h"
+#include <egl.h>
+#endif
+
+namespace WebCore {
+
+// typedef'ing doesn't work, let's inherit from PainterOpenVG instead
+class GraphicsContextPlatformPrivate : public PainterOpenVG {
+public:
+ GraphicsContextPlatformPrivate(SurfaceOpenVG* surface)
+ : PainterOpenVG(surface)
+ {
+ }
+};
+
+void GraphicsContext::platformInit(SurfaceOpenVG* surface)
+{
+ m_data = surface ? new GraphicsContextPlatformPrivate(surface) : 0;
+ setPaintingDisabled(!surface);
+}
+
+void GraphicsContext::platformDestroy()
+{
+ delete m_data;
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ if (paintingDisabled())
+ return 0;
+
+ return m_data->baseSurface();
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ if (paintingDisabled())
+ return AffineTransform();
+
+ return m_data->transformation();
+}
+
+void GraphicsContext::savePlatformState()
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->restore();
+}
+
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawRect(rect);
+}
+
+void GraphicsContext::drawLine(const IntPoint& from, const IntPoint& to)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawLine(from, to);
+}
+
+/**
+ * Draw the largest ellipse that fits into the given rectangle.
+ */
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawEllipse(rect);
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawArc(rect, startAngle, angleSpan, VG_STROKE_PATH);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawPolygon(numPoints, points);
+
+ UNUSED_PARAM(shouldAntialias); // FIXME
+}
+
+void GraphicsContext::fillPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawPath(path, VG_FILL_PATH, m_state.fillRule);
+}
+
+void GraphicsContext::strokePath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawPath(path, VG_STROKE_PATH, m_state.fillRule);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawRect(rect, VG_FILL_PATH);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ Color oldColor = m_data->fillColor();
+ m_data->setFillColor(color);
+ m_data->drawRect(rect, VG_FILL_PATH);
+ m_data->setFillColor(oldColor);
+
+ UNUSED_PARAM(colorSpace); // FIXME
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ Color oldColor = m_data->fillColor();
+ m_data->setFillColor(color);
+ m_data->drawRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight, VG_FILL_PATH);
+ m_data->setFillColor(oldColor);
+
+ UNUSED_PARAM(colorSpace); // FIXME
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->intersectClipRect(rect);
+}
+
+void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->clipPath(path, PainterOpenVG::IntersectClip, clipRule);
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (rects.isEmpty())
+ return;
+
+ // FIXME: We just unite all focus ring rects into one for now.
+ // We should outline the edge of the full region.
+ offset += (width - 1) / 2;
+ IntRect finalFocusRect;
+
+ for (unsigned i = 0; i < rects.size(); i++) {
+ IntRect focusRect = rects[i];
+ focusRect.inflate(offset);
+ finalFocusRect.unite(focusRect);
+ }
+
+ StrokeStyle oldStyle = m_data->strokeStyle();
+ Color oldStrokeColor = m_data->strokeColor();
+ m_data->setStrokeStyle(DashedStroke);
+ m_data->setStrokeColor(color);
+ strokeRect(FloatRect(finalFocusRect), 1.f);
+ m_data->setStrokeStyle(oldStyle);
+ m_data->setStrokeColor(oldStrokeColor);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ if (width <= 0)
+ return;
+
+ StrokeStyle oldStyle = m_data->strokeStyle();
+ m_data->setStrokeStyle(SolidStroke);
+ drawLine(origin, origin + IntSize(width, 0));
+ m_data->setStrokeStyle(oldStyle);
+
+ UNUSED_PARAM(printing);
+}
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(origin);
+ UNUSED_PARAM(width);
+ UNUSED_PARAM(style);
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return FloatRect();
+
+ return FloatRect(enclosingIntRect(m_data->transformation().mapRect(rect)));
+}
+
+void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(size);
+ UNUSED_PARAM(blur);
+ UNUSED_PARAM(color);
+ UNUSED_PARAM(colorSpace);
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(opacity);
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ CompositeOperator op = m_data->compositeOperation();
+ m_data->setCompositeOperation(CompositeClear);
+ m_data->drawRect(rect, VG_FILL_PATH);
+ m_data->setCompositeOperation(op);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ float oldThickness = m_data->strokeThickness();
+ m_data->setStrokeThickness(lineWidth);
+ m_data->drawRect(rect, VG_STROKE_PATH);
+ m_data->setStrokeThickness(oldThickness);
+}
+
+void GraphicsContext::setLineCap(LineCap lc)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setLineCap(lc);
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setLineDash(dashes, dashOffset);
+}
+
+void GraphicsContext::setLineJoin(LineJoin lj)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setLineJoin(lj);
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setMiterLimit(limit);
+}
+
+void GraphicsContext::setAlpha(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setOpacity(opacity);
+}
+
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setCompositeOperation(op);
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->clipPath(path, PainterOpenVG::IntersectClip, m_state.fillRule);
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->clipPath(path, PainterOpenVG::SubtractClip, m_state.fillRule);
+}
+
+void GraphicsContext::scale(const FloatSize& scaleFactors)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->scale(scaleFactors);
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->rotate(radians);
+}
+
+void GraphicsContext::translate(float dx, float dy)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->translate(dx, dy);
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ Path path;
+ path.addRect(rect);
+ m_data->clipPath(path, PainterOpenVG::SubtractClip, m_state.fillRule);
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer* imageBuffer)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(rect);
+ UNUSED_PARAM(imageBuffer);
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ Path path;
+ path.addEllipse(rect);
+ path.addEllipse(FloatRect(rect.x() + thickness, rect.y() + thickness,
+ rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
+
+ m_data->clipPath(path, PainterOpenVG::IntersectClip, m_state.fillRule);
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transformation)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->concatTransformation(transformation);
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ notImplemented();
+ UNUSED_PARAM(link);
+ UNUSED_PARAM(destRect);
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setStrokeColor(color);
+
+ UNUSED_PARAM(colorSpace); // FIXME
+}
+
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setStrokeStyle(strokeStyle);
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setStrokeThickness(thickness);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setFillColor(color);
+
+ UNUSED_PARAM(colorSpace); // FIXME
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setAntialiasingEnabled(enable);
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+ notImplemented();
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ notImplemented();
+ return InterpolationDefault;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/openvg/ImageOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/ImageOpenVG.cpp
new file mode 100644
index 0000000..4c1932a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/ImageOpenVG.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageDecoder.h"
+#include "ImageObserver.h"
+#include "IntSize.h"
+#include "NotImplemented.h"
+#include "PainterOpenVG.h"
+#include "SurfaceOpenVG.h"
+#include "TiledImageOpenVG.h"
+#include "VGUtils.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ delete m_frame;
+ m_frame = 0;
+ return true;
+ }
+ return false;
+}
+
+BitmapImage::BitmapImage(TiledImageOpenVG* tiledImage, ImageObserver* observer)
+ : Image(observer)
+ , m_size(tiledImage->size())
+ , m_currentFrame(0)
+ , m_frames(1)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_desiredFrameStartTime(0)
+ , m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
+ , m_animationFinished(false)
+ , m_allDataReceived(false)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_hasUniformFrameSize(true)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ ASSERT(m_size.width() > 0);
+ ASSERT(m_size.height() > 0);
+
+ m_decodedSize = m_size.width() * m_size.height() * 4;
+
+ m_frames[0].m_frame = tiledImage;
+ m_frames[0].m_hasAlpha = true;
+ m_frames[0].m_isComplete = true;
+ m_frames[0].m_haveMetadata = true;
+ checkForSolidColor();
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ TiledImageOpenVG* tiledImage = 0;
+
+ if (m_frameCount == 1 && m_size.width() == 1 && m_size.height() == 1)
+ tiledImage = nativeImageForCurrentFrame();
+
+ if (tiledImage) {
+ m_isSolidColor = true;
+ RGBA32 pixel;
+ vgGetImageSubData(tiledImage->tile(0, 0), &pixel, 0, VG_sARGB_8888, 0, 0, 1, 1);
+ ASSERT_VG_NO_ERROR();
+ m_solidColor.setRGB(pixel);
+ } else
+ m_isSolidColor = false;
+
+ m_checkedForSolidColor = true;
+}
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
+static void adjustSourceRectForDownSampling(FloatRect& srcRect, const IntSize& origSize, const IntSize& scaledSize)
+{
+ // We assume down-sampling zoom rates in X direction and in Y direction are same.
+ if (origSize.width() == scaledSize.width())
+ return;
+
+ // Image has been down sampled.
+ double rate = static_cast<double>(scaledSize.width()) / origSize.width();
+ double temp = srcRect.right() * rate;
+ srcRect.setX(srcRect.x() * rate);
+ srcRect.setWidth(temp - srcRect.x());
+ temp = srcRect.bottom() * rate;
+ srcRect.setY(srcRect.y() * rate);
+ srcRect.setHeight(temp - srcRect.y());
+}
+#endif
+
+void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ if (dst.isEmpty() || src.isEmpty())
+ return;
+
+ NativeImagePtr image = nativeImageForCurrentFrame();
+ if (!image)
+ return;
+
+ startAnimation();
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+ context->save();
+
+ // Set the compositing operation.
+ if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame))
+ context->setCompositeOperation(CompositeCopy);
+ else
+ context->setCompositeOperation(op);
+
+ FloatRect srcRectLocal(src);
+#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
+ adjustSourceRectForDownSampling(srcRectLocal, size(), image->size());
+#endif
+
+ context->platformContext()->activePainter()->drawImage(image, dst, srcRectLocal);
+ context->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void Image::drawPattern(GraphicsContext* context, const FloatRect& src,
+ const AffineTransform& patternTransformation,
+ const FloatPoint& phase, ColorSpace styleColorSpace,
+ CompositeOperator op, const FloatRect& dst)
+{
+ if (dst.isEmpty() || src.isEmpty())
+ return;
+
+ NativeImagePtr image = nativeImageForCurrentFrame();
+ if (!image)
+ return;
+
+ startAnimation();
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+ notImplemented();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(char const* name)
+{
+ notImplemented();
+ return 0;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/openvg/PainterOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/PainterOpenVG.cpp
new file mode 100644
index 0000000..3e2b92c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/PainterOpenVG.cpp
@@ -0,0 +1,1242 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "PainterOpenVG.h"
+
+#include "AffineTransform.h"
+#include "Color.h"
+#include "DashArray.h"
+#include "FloatPoint.h"
+#include "FloatQuad.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "IntSize.h"
+#include "NotImplemented.h"
+#include "PlatformPathOpenVG.h"
+#include "SurfaceOpenVG.h"
+#include "TiledImageOpenVG.h"
+#include "VGUtils.h"
+
+#if PLATFORM(EGL)
+#include "EGLUtils.h"
+#endif
+
+#include <vgu.h>
+
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+static bool isNonRotatedAffineTransformation(const AffineTransform& t)
+{
+ return t.b() <= FLT_EPSILON && t.c() <= FLT_EPSILON;
+}
+
+static VGCapStyle toVGCapStyle(LineCap lineCap)
+{
+ switch (lineCap) {
+ case RoundCap:
+ return VG_CAP_ROUND;
+ case SquareCap:
+ return VG_CAP_SQUARE;
+ case ButtCap:
+ default:
+ return VG_CAP_BUTT;
+ }
+}
+
+static VGJoinStyle toVGJoinStyle(LineJoin lineJoin)
+{
+ switch (lineJoin) {
+ case RoundJoin:
+ return VG_JOIN_ROUND;
+ case BevelJoin:
+ return VG_JOIN_BEVEL;
+ case MiterJoin:
+ default:
+ return VG_JOIN_MITER;
+ }
+}
+
+static VGFillRule toVGFillRule(WindRule fillRule)
+{
+ return fillRule == RULE_EVENODD ? VG_EVEN_ODD : VG_NON_ZERO;
+}
+
+static VGuint colorToVGColor(const Color& color)
+{
+ VGuint vgColor = color.red();
+ vgColor = (vgColor << 8) | color.green();
+ vgColor = (vgColor << 8) | color.blue();
+ vgColor = (vgColor << 8) | color.alpha();
+ return vgColor;
+}
+
+static void setVGSolidColor(VGPaintMode paintMode, const Color& color)
+{
+ VGPaint paint = vgCreatePaint();
+ vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+ vgSetColor(paint, colorToVGColor(color));
+ vgSetPaint(paint, paintMode);
+ vgDestroyPaint(paint);
+ ASSERT_VG_NO_ERROR();
+}
+
+
+struct PlatformPainterState {
+ AffineTransform surfaceTransformation;
+ CompositeOperator compositeOperation;
+ float opacity;
+
+ bool scissoringEnabled;
+ FloatRect scissorRect;
+#ifdef OPENVG_VERSION_1_1
+ bool maskingChangedAndEnabled;
+ VGMaskLayer mask;
+#endif
+
+ Color fillColor;
+ StrokeStyle strokeStyle;
+ Color strokeColor;
+ float strokeThickness;
+ LineCap strokeLineCap;
+ LineJoin strokeLineJoin;
+ float strokeMiterLimit;
+ DashArray strokeDashArray;
+ float strokeDashOffset;
+
+ TextDrawingModeFlags textDrawingMode;
+ bool antialiasingEnabled;
+
+ PlatformPainterState()
+ : compositeOperation(CompositeSourceOver)
+ , opacity(1.0)
+ , scissoringEnabled(false)
+#ifdef OPENVG_VERSION_1_1
+ , maskingChangedAndEnabled(false)
+ , mask(VG_INVALID_HANDLE)
+#endif
+ , fillColor(Color::black)
+ , strokeStyle(NoStroke)
+ , strokeThickness(0.0)
+ , strokeLineCap(ButtCap)
+ , strokeLineJoin(MiterJoin)
+ , strokeMiterLimit(4.0)
+ , strokeDashOffset(0.0)
+ , textDrawingMode(TextModeFill)
+ , antialiasingEnabled(true)
+ {
+ }
+
+ ~PlatformPainterState()
+ {
+#ifdef OPENVG_VERSION_1_1
+ if (maskingChangedAndEnabled && mask != VG_INVALID_HANDLE) {
+ vgDestroyMaskLayer(mask);
+ ASSERT_VG_NO_ERROR();
+ mask = VG_INVALID_HANDLE;
+ }
+#endif
+ }
+
+ PlatformPainterState(const PlatformPainterState& state)
+ {
+ surfaceTransformation = state.surfaceTransformation;
+
+ scissoringEnabled = state.scissoringEnabled;
+ scissorRect = state.scissorRect;
+#ifdef OPENVG_VERSION_1_1
+ maskingChangedAndEnabled = false;
+ mask = state.mask;
+#endif
+ copyPaintState(&state);
+ }
+
+ inline bool maskingEnabled()
+ {
+ return maskingChangedAndEnabled || mask != VG_INVALID_HANDLE;
+ }
+
+ void copyPaintState(const PlatformPainterState* other)
+ {
+ compositeOperation = other->compositeOperation;
+ opacity = other->opacity;
+
+ fillColor = other->fillColor;
+ strokeStyle = other->strokeStyle;
+ strokeColor = other->strokeColor;
+ strokeThickness = other->strokeThickness;
+ strokeLineCap = other->strokeLineCap;
+ strokeLineJoin = other->strokeLineJoin;
+ strokeMiterLimit = other->strokeMiterLimit;
+ strokeDashArray = other->strokeDashArray;
+ strokeDashOffset = other->strokeDashOffset;
+
+ textDrawingMode = other->textDrawingMode;
+ antialiasingEnabled = other->antialiasingEnabled;
+ }
+
+ void applyState(PainterOpenVG* painter)
+ {
+ ASSERT(painter);
+
+ setVGSolidColor(VG_FILL_PATH, fillColor);
+ setVGSolidColor(VG_STROKE_PATH, strokeColor);
+
+ vgSetf(VG_STROKE_LINE_WIDTH, strokeThickness);
+ vgSeti(VG_STROKE_CAP_STYLE, toVGCapStyle(strokeLineCap));
+ vgSeti(VG_STROKE_JOIN_STYLE, toVGJoinStyle(strokeLineJoin));
+ vgSetf(VG_STROKE_MITER_LIMIT, strokeMiterLimit);
+
+ if (antialiasingEnabled)
+ vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER);
+ else
+ vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+
+ applyBlending(painter);
+ applyStrokeStyle();
+
+ applyTransformation(painter);
+ applyScissorRect();
+
+#ifdef OPENVG_VERSION_1_1
+ if (maskingEnabled()) {
+ vgSeti(VG_MASKING, VG_TRUE);
+ if (mask != VG_INVALID_HANDLE)
+ vgMask(mask, VG_SET_MASK, 0, 0, painter->surface()->width(), painter->surface()->height());
+ } else
+ vgSeti(VG_MASKING, VG_FALSE);
+#endif
+ ASSERT_VG_NO_ERROR();
+ }
+
+ void applyBlending(PainterOpenVG* painter)
+ {
+ VGBlendMode blendMode = VG_BLEND_SRC_OVER;
+
+ switch (compositeOperation) {
+ case CompositeClear: {
+ // Clear means "set to fully transparent regardless of SRC".
+ // We implement that by multiplying DST with white color
+ // (= no changes) and an alpha of 1.0 - opacity, so the destination
+ // pixels will be fully transparent when opacity == 1.0 and
+ // unchanged when opacity == 0.0.
+ blendMode = VG_BLEND_DST_IN;
+ const VGfloat values[] = { 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 - opacity };
+ vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values);
+ vgSeti(VG_COLOR_TRANSFORM, VG_TRUE);
+ ASSERT_VG_NO_ERROR();
+ break;
+ }
+ case CompositeCopy:
+ blendMode = VG_BLEND_SRC;
+ break;
+ case CompositeSourceOver:
+ blendMode = VG_BLEND_SRC_OVER;
+ break;
+ case CompositeSourceIn:
+ blendMode = VG_BLEND_SRC_IN;
+ break;
+ case CompositeSourceOut:
+ notImplemented();
+ break;
+ case CompositeSourceAtop:
+ notImplemented();
+ break;
+ case CompositeDestinationOver:
+ blendMode = VG_BLEND_DST_OVER;
+ break;
+ case CompositeDestinationIn:
+ blendMode = VG_BLEND_DST_IN;
+ break;
+ case CompositeDestinationOut:
+ notImplemented();
+ break;
+ case CompositeDestinationAtop:
+ notImplemented();
+ break;
+ case CompositeXOR:
+ notImplemented();
+ break;
+ case CompositePlusDarker:
+ blendMode = VG_BLEND_DARKEN;
+ break;
+ case CompositeHighlight:
+ notImplemented();
+ break;
+ case CompositePlusLighter:
+ blendMode = VG_BLEND_LIGHTEN;
+ break;
+ }
+
+ if (compositeOperation != CompositeClear) {
+ if (opacity >= (1.0 - FLT_EPSILON))
+ vgSeti(VG_COLOR_TRANSFORM, VG_FALSE);
+ else if (blendMode == VG_BLEND_SRC) {
+ blendMode = VG_BLEND_SRC_OVER;
+ VGfloat values[] = { 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, opacity };
+ vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values);
+ vgSeti(VG_COLOR_TRANSFORM, VG_TRUE);
+ } else {
+ VGfloat values[] = { 1.0, 1.0, 1.0, opacity, 0.0, 0.0, 0.0, 0.0 };
+ vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values);
+ vgSeti(VG_COLOR_TRANSFORM, VG_TRUE);
+ }
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgSeti(VG_BLEND_MODE, blendMode);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ void applyTransformation(PainterOpenVG* painter)
+ {
+ // There are *five* separate transforms that can be applied to OpenVG as of 1.1
+ // but it is not clear that we need to set them separately. Instead we set them
+ // all right here and let this be a call to essentially set the world transformation!
+ VGMatrix vgMatrix(surfaceTransformation);
+ const VGfloat* vgFloatArray = vgMatrix.toVGfloat();
+
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+ vgLoadMatrix(vgFloatArray);
+ ASSERT_VG_NO_ERROR();
+
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(vgFloatArray);
+ ASSERT_VG_NO_ERROR();
+
+#ifdef OPENVG_VERSION_1_1
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
+ vgLoadMatrix(vgFloatArray);
+ ASSERT_VG_NO_ERROR();
+#endif
+ }
+
+ void applyScissorRect()
+ {
+ if (scissoringEnabled) {
+ vgSeti(VG_SCISSORING, VG_TRUE);
+ vgSetfv(VG_SCISSOR_RECTS, 4, VGRect(scissorRect).toVGfloat());
+ } else
+ vgSeti(VG_SCISSORING, VG_FALSE);
+
+ ASSERT_VG_NO_ERROR();
+ }
+
+ void applyStrokeStyle()
+ {
+ if (strokeStyle == DottedStroke) {
+ VGfloat vgFloatArray[2] = { 1.0, 1.0 };
+ vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray);
+ vgSetf(VG_STROKE_DASH_PHASE, 0.0);
+ } else if (strokeStyle == DashedStroke) {
+ if (!strokeDashArray.size()) {
+ VGfloat vgFloatArray[2] = { 4.0, 3.0 };
+ vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray);
+ } else {
+ Vector<VGfloat> vgFloatArray(strokeDashArray.size());
+ for (int i = 0; i < strokeDashArray.size(); ++i)
+ vgFloatArray[i] = strokeDashArray[i];
+
+ vgSetfv(VG_STROKE_DASH_PATTERN, vgFloatArray.size(), vgFloatArray.data());
+ }
+ vgSetf(VG_STROKE_DASH_PHASE, strokeDashOffset);
+ } else {
+ vgSetfv(VG_STROKE_DASH_PATTERN, 0, 0);
+ vgSetf(VG_STROKE_DASH_PHASE, 0.0);
+ }
+
+ ASSERT_VG_NO_ERROR();
+ }
+
+ inline bool strokeDisabled() const
+ {
+ return (compositeOperation == CompositeSourceOver
+ && (strokeStyle == NoStroke || !strokeColor.alpha()));
+ }
+
+ inline bool fillDisabled() const
+ {
+ return (compositeOperation == CompositeSourceOver && !fillColor.alpha());
+ }
+
+ void saveMaskIfNecessary(PainterOpenVG* painter)
+ {
+#ifdef OPENVG_VERSION_1_1
+ if (maskingChangedAndEnabled) {
+ if (mask != VG_INVALID_HANDLE) {
+ vgDestroyMaskLayer(mask);
+ ASSERT_VG_NO_ERROR();
+ }
+ mask = vgCreateMaskLayer(painter->surface()->width(), painter->surface()->height());
+ ASSERT(mask != VG_INVALID_HANDLE);
+ vgCopyMask(mask, 0, 0, 0, 0, painter->surface()->width(), painter->surface()->height());
+ ASSERT_VG_NO_ERROR();
+ }
+#endif
+ }
+};
+
+
+PainterOpenVG::PainterOpenVG()
+ : m_state(0)
+ , m_surface(0)
+{
+}
+
+PainterOpenVG::PainterOpenVG(SurfaceOpenVG* surface)
+ : m_state(0)
+ , m_surface(0)
+{
+ ASSERT(surface);
+ begin(surface);
+}
+
+PainterOpenVG::~PainterOpenVG()
+{
+ end();
+}
+
+void PainterOpenVG::begin(SurfaceOpenVG* surface)
+{
+ if (surface == m_surface)
+ return;
+
+ ASSERT(surface);
+ ASSERT(!m_state);
+
+ m_surface = surface;
+
+ m_stateStack.append(new PlatformPainterState());
+ m_state = m_stateStack.last();
+
+ m_surface->setActivePainter(this);
+ m_surface->makeCurrent();
+}
+
+void PainterOpenVG::end()
+{
+ if (!m_surface)
+ return;
+
+ m_surface->setActivePainter(0);
+ m_surface = 0;
+
+ destroyPainterStates();
+}
+
+void PainterOpenVG::destroyPainterStates()
+{
+ PlatformPainterState* state = 0;
+ while (!m_stateStack.isEmpty()) {
+ state = m_stateStack.last();
+ m_stateStack.removeLast();
+ delete state;
+ }
+ m_state = 0;
+}
+
+// Called by friend SurfaceOpenVG, private otherwise.
+void PainterOpenVG::applyState()
+{
+ ASSERT(m_state);
+ m_state->applyState(this);
+}
+
+/**
+ * Copy the current back buffer image onto the surface.
+ *
+ * Call this method when all painting operations have been completed,
+ * otherwise the surface won't visibly change.
+ */
+void PainterOpenVG::blitToSurface()
+{
+ ASSERT(m_state); // implies m_surface
+ m_surface->flush();
+}
+
+AffineTransform PainterOpenVG::transformation() const
+{
+ ASSERT(m_state);
+ return m_state->surfaceTransformation;
+}
+
+void PainterOpenVG::concatTransformation(const AffineTransform& transformation)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ // We do the multiplication ourself using WebCore's AffineTransform rather
+ // than offloading this to VG via vgMultMatrix() to keep things simple and
+ // so we can maintain state ourselves.
+ m_state->surfaceTransformation.multLeft(transformation);
+ m_state->applyTransformation(this);
+}
+
+void PainterOpenVG::setTransformation(const AffineTransform& transformation)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->surfaceTransformation = transformation;
+ m_state->applyTransformation(this);
+}
+
+void PainterOpenVG::transformPath(VGPath dst, VGPath src, const AffineTransform& transformation)
+{
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+
+ // Save the transform state
+ VGfloat currentMatrix[9];
+ vgGetMatrix(currentMatrix);
+ ASSERT_VG_NO_ERROR();
+
+ // Load the new transform
+ vgLoadMatrix(VGMatrix(transformation).toVGfloat());
+ ASSERT_VG_NO_ERROR();
+
+ // Apply the new transform
+ vgTransformPath(dst, src);
+ ASSERT_VG_NO_ERROR();
+
+ // Restore the transform state
+ vgLoadMatrix(currentMatrix);
+ ASSERT_VG_NO_ERROR();
+}
+
+CompositeOperator PainterOpenVG::compositeOperation() const
+{
+ ASSERT(m_state);
+ return m_state->compositeOperation;
+}
+
+void PainterOpenVG::setCompositeOperation(CompositeOperator op)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->compositeOperation = op;
+ m_state->applyBlending(this);
+}
+
+float PainterOpenVG::opacity() const
+{
+ ASSERT(m_state);
+ return m_state->opacity;
+}
+
+void PainterOpenVG::setOpacity(float opacity)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->opacity = opacity;
+ m_state->applyBlending(this);
+}
+
+float PainterOpenVG::strokeThickness() const
+{
+ ASSERT(m_state);
+ return m_state->strokeThickness;
+}
+
+void PainterOpenVG::setStrokeThickness(float thickness)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeThickness = thickness;
+ vgSetf(VG_STROKE_LINE_WIDTH, thickness);
+ ASSERT_VG_NO_ERROR();
+}
+
+StrokeStyle PainterOpenVG::strokeStyle() const
+{
+ ASSERT(m_state);
+ return m_state->strokeStyle;
+}
+
+void PainterOpenVG::setStrokeStyle(StrokeStyle style)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeStyle = style;
+ m_state->applyStrokeStyle();
+}
+
+void PainterOpenVG::setLineDash(const DashArray& dashArray, float dashOffset)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeDashArray = dashArray;
+ m_state->strokeDashOffset = dashOffset;
+ m_state->applyStrokeStyle();
+}
+
+void PainterOpenVG::setLineCap(LineCap lineCap)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeLineCap = lineCap;
+ vgSeti(VG_STROKE_CAP_STYLE, toVGCapStyle(lineCap));
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::setLineJoin(LineJoin lineJoin)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeLineJoin = lineJoin;
+ vgSeti(VG_STROKE_JOIN_STYLE, toVGJoinStyle(lineJoin));
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::setMiterLimit(float miterLimit)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeMiterLimit = miterLimit;
+ vgSetf(VG_STROKE_MITER_LIMIT, miterLimit);
+ ASSERT_VG_NO_ERROR();
+}
+
+Color PainterOpenVG::strokeColor() const
+{
+ ASSERT(m_state);
+ return m_state->strokeColor;
+}
+
+void PainterOpenVG::setStrokeColor(const Color& color)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeColor = color;
+ setVGSolidColor(VG_STROKE_PATH, color);
+}
+
+Color PainterOpenVG::fillColor() const
+{
+ ASSERT(m_state);
+ return m_state->fillColor;
+}
+
+void PainterOpenVG::setFillColor(const Color& color)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->fillColor = color;
+ setVGSolidColor(VG_FILL_PATH, color);
+}
+
+TextDrawingModeFlags PainterOpenVG::textDrawingMode() const
+{
+ ASSERT(m_state);
+ return m_state->textDrawingMode;
+}
+
+void PainterOpenVG::setTextDrawingMode(TextDrawingModeFlags mode)
+{
+ ASSERT(m_state);
+ m_state->textDrawingMode = mode;
+}
+
+bool PainterOpenVG::antialiasingEnabled() const
+{
+ ASSERT(m_state);
+ return m_state->antialiasingEnabled;
+}
+
+void PainterOpenVG::setAntialiasingEnabled(bool enabled)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->antialiasingEnabled = enabled;
+
+ if (enabled)
+ vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER);
+ else
+ vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+}
+
+void PainterOpenVG::scale(const FloatSize& scaleFactors)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ AffineTransform transformation = m_state->surfaceTransformation;
+ transformation.scaleNonUniform(scaleFactors.width(), scaleFactors.height());
+ setTransformation(transformation);
+}
+
+void PainterOpenVG::rotate(float radians)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ AffineTransform transformation = m_state->surfaceTransformation;
+ transformation.rotate(rad2deg(radians));
+ setTransformation(transformation);
+}
+
+void PainterOpenVG::translate(float dx, float dy)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ AffineTransform transformation = m_state->surfaceTransformation;
+ transformation.translate(dx, dy);
+ setTransformation(transformation);
+}
+
+void PainterOpenVG::drawPath(const Path& path, VGbitfield specifiedPaintModes, WindRule fillRule)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ vgSeti(VG_FILL_RULE, toVGFillRule(fillRule));
+ vgDrawPath(path.platformPath()->vgPath(), paintModes);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::intersectScissorRect(const FloatRect& rect)
+{
+ // Scissor rectangles are defined by float values, but e.g. painting
+ // something red to a float-clipped rectangle and then painting something
+ // white to the same rectangle will leave some red remnants as it is
+ // rendered to full pixels in between. Also, some OpenVG implementations
+ // are likely to clip to integer coordinates anyways because of the above
+ // effect. So considering the above (and confirming through tests) the
+ // visual result is better if we clip to the enclosing integer rectangle
+ // rather than the exact float rectangle for scissoring.
+ if (m_state->scissoringEnabled)
+ m_state->scissorRect.intersect(FloatRect(enclosingIntRect(rect)));
+ else {
+ m_state->scissoringEnabled = true;
+ m_state->scissorRect = FloatRect(enclosingIntRect(rect));
+ }
+
+ m_state->applyScissorRect();
+}
+
+void PainterOpenVG::intersectClipRect(const FloatRect& rect)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ if (m_state->surfaceTransformation.isIdentity()) {
+ // No transformation required, skip all the complex stuff.
+ intersectScissorRect(rect);
+ return;
+ }
+
+ // Check if the actual destination rectangle is still rectilinear (can be
+ // represented as FloatRect) so we could apply scissoring instead of
+ // (potentially more expensive) path clipping. Note that scissoring is not
+ // subject to transformations, so we need to do the transformation to
+ // surface coordinates by ourselves.
+ FloatQuad effectiveScissorQuad = m_state->surfaceTransformation.mapQuad(FloatQuad(rect));
+
+ if (effectiveScissorQuad.isRectilinear())
+ intersectScissorRect(effectiveScissorQuad.boundingBox());
+ else {
+ // The transformed scissorRect cannot be represented as FloatRect
+ // anymore, so we need to perform masking instead.
+ Path scissorRectPath;
+ scissorRectPath.addRect(rect);
+ clipPath(scissorRectPath, PainterOpenVG::IntersectClip);
+ }
+}
+
+void PainterOpenVG::clipPath(const Path& path, PainterOpenVG::ClipOperation maskOp, WindRule clipRule)
+{
+#ifdef OPENVG_VERSION_1_1
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ if (m_state->mask != VG_INVALID_HANDLE && !m_state->maskingChangedAndEnabled) {
+ // The parent's mask has been inherited - dispose the handle so that
+ // it won't be overwritten.
+ m_state->maskingChangedAndEnabled = true;
+ m_state->mask = VG_INVALID_HANDLE;
+ } else if (!m_state->maskingEnabled()) {
+ // None of the parent painter states had a mask enabled yet.
+ m_state->maskingChangedAndEnabled = true;
+ vgSeti(VG_MASKING, VG_TRUE);
+ // Make sure not to inherit previous mask state from previously written
+ // (but disabled) masks. For VG_FILL_MASK the first argument is ignored,
+ // we pass VG_INVALID_HANDLE which is what the OpenVG spec suggests.
+ vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, m_surface->width(), m_surface->height());
+ }
+
+ // Intersect the path from the mask, or subtract it from there.
+ // (In either case we always decrease the visible area, never increase it,
+ // which means masking never has to modify scissor rectangles.)
+ vgSeti(VG_FILL_RULE, toVGFillRule(clipRule));
+ vgRenderToMask(path.platformPath()->vgPath(), VG_FILL_PATH, (VGMaskOperation) maskOp);
+ ASSERT_VG_NO_ERROR();
+#else
+ notImplemented();
+#endif
+}
+
+void PainterOpenVG::drawRect(const FloatRect& rect, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 5 /* expected number of segments */,
+ 5 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ if (vguRect(path, rect.x(), rect.y(), rect.width(), rect.height()) == VGU_NO_ERROR) {
+ vgDrawPath(path, paintModes);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawRoundedRect(const FloatRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 10 /* expected number of segments */,
+ 25 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ // clamp corner arc sizes
+ FloatSize clampedTopLeft = FloatSize(topLeft).shrunkTo(rect.size()).expandedTo(FloatSize());
+ FloatSize clampedTopRight = FloatSize(topRight).shrunkTo(rect.size()).expandedTo(FloatSize());
+ FloatSize clampedBottomLeft = FloatSize(bottomLeft).shrunkTo(rect.size()).expandedTo(FloatSize());
+ FloatSize clampedBottomRight = FloatSize(bottomRight).shrunkTo(rect.size()).expandedTo(FloatSize());
+
+ // As OpenVG's coordinate system is flipped in comparison to WebKit's,
+ // we have to specify the opposite value for the "clockwise" value.
+ static const VGubyte pathSegments[] = {
+ VG_MOVE_TO_ABS,
+ VG_HLINE_TO_REL,
+ VG_SCCWARC_TO_REL,
+ VG_VLINE_TO_REL,
+ VG_SCCWARC_TO_REL,
+ VG_HLINE_TO_REL,
+ VG_SCCWARC_TO_REL,
+ VG_VLINE_TO_REL,
+ VG_SCCWARC_TO_REL,
+ VG_CLOSE_PATH
+ };
+ // Also, the rounded rectangle path proceeds from the top to the bottom,
+ // requiring height distances and clamped radius sizes to be flipped.
+ const VGfloat pathData[] = {
+ rect.x() + clampedTopLeft.width(), rect.y(),
+ rect.width() - clampedTopLeft.width() - clampedTopRight.width(),
+ clampedTopRight.width(), clampedTopRight.height(), 0, clampedTopRight.width(), clampedTopRight.height(),
+ rect.height() - clampedTopRight.height() - clampedBottomRight.height(),
+ clampedBottomRight.width(), clampedBottomRight.height(), 0, -clampedBottomRight.width(), clampedBottomRight.height(),
+ -(rect.width() - clampedBottomLeft.width() - clampedBottomRight.width()),
+ clampedBottomLeft.width(), clampedBottomLeft.height(), 0, -clampedBottomLeft.width(), -clampedBottomLeft.height(),
+ -(rect.height() - clampedTopLeft.height() - clampedBottomLeft.height()),
+ clampedTopLeft.width(), clampedTopLeft.height(), 0, clampedTopLeft.width(), -clampedTopLeft.height(),
+ };
+
+ vgAppendPathData(path, 10, pathSegments, pathData);
+ vgDrawPath(path, paintModes);
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawLine(const IntPoint& from, const IntPoint& to)
+{
+ ASSERT(m_state);
+
+ if (m_state->strokeDisabled())
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 2 /* expected number of segments */,
+ 4 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ VGUErrorCode errorCode;
+
+ // Try to align lines to pixels, centering them between pixels for odd thickness values.
+ if (fmod(m_state->strokeThickness + 0.5, 2.0) < 1.0)
+ errorCode = vguLine(path, from.x(), from.y(), to.x(), to.y());
+ else if ((to.y() - from.y()) > (to.x() - from.x())) // more vertical than horizontal
+ errorCode = vguLine(path, from.x() + 0.5, from.y(), to.x() + 0.5, to.y());
+ else
+ errorCode = vguLine(path, from.x(), from.y() + 0.5, to.x(), to.y() + 0.5);
+
+ if (errorCode == VGU_NO_ERROR) {
+ vgDrawPath(path, VG_STROKE_PATH);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawArc(const IntRect& rect, int startAngle, int angleSpan, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 2 /* expected number of segments */,
+ 4 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ if (vguArc(path, rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0, rect.width(), rect.height(), -startAngle, -angleSpan, VGU_ARC_OPEN) == VGU_NO_ERROR) {
+ vgDrawPath(path, VG_STROKE_PATH);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawEllipse(const IntRect& rect, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 4 /* expected number of segments */,
+ 12 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ if (vguEllipse(path, rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0, rect.width(), rect.height()) == VGU_NO_ERROR) {
+ vgDrawPath(path, paintModes);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawPolygon(size_t numPoints, const FloatPoint* points, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ // Path segments: all points + "close path".
+ const VGint numSegments = numPoints + 1;
+ const VGint numCoordinates = numPoints * 2;
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ numSegments /* expected number of segments */,
+ numCoordinates /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ Vector<VGfloat> vgPoints(numCoordinates);
+ for (int i = 0; i < numPoints; ++i) {
+ vgPoints[i*2] = points[i].x();
+ vgPoints[i*2 + 1] = points[i].y();
+ }
+
+ if (vguPolygon(path, vgPoints.data(), numPoints, VG_TRUE /* closed */) == VGU_NO_ERROR) {
+ vgDrawPath(path, paintModes);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawImage(TiledImageOpenVG* tiledImage, const FloatRect& dst, const FloatRect& src)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ // If buffers can be larger than the maximum OpenVG image sizes,
+ // we split them into tiles.
+ IntRect drawnTiles = tiledImage->tilesInRect(src);
+ AffineTransform srcToDstTransformation = makeMapBetweenRects(
+ FloatRect(FloatPoint(0.0, 0.0), src.size()), dst);
+ srcToDstTransformation.translate(-src.x(), -src.y());
+
+ for (int yIndex = drawnTiles.y(); yIndex < drawnTiles.bottom(); ++yIndex) {
+ for (int xIndex = drawnTiles.x(); xIndex < drawnTiles.right(); ++xIndex) {
+ // The srcTile rectangle is an aligned tile cropped by the src rectangle.
+ FloatRect tile(tiledImage->tileRect(xIndex, yIndex));
+ FloatRect srcTile = intersection(src, tile);
+
+ save();
+
+ // If the image is drawn in full, all we need is the proper transformation
+ // in order to get it drawn at the right spot on the surface.
+ concatTransformation(AffineTransform(srcToDstTransformation).translate(tile.x(), tile.y()));
+
+ // If only a part of the tile is drawn, we also need to clip the surface.
+ if (srcTile != tile) {
+ // Put boundaries relative to tile origin, as we already
+ // translated to (x, y) with the transformation matrix.
+ srcTile.move(-tile.x(), -tile.y());
+ intersectClipRect(srcTile);
+ }
+
+ VGImage image = tiledImage->tile(xIndex, yIndex);
+ if (image != VG_INVALID_HANDLE) {
+ vgDrawImage(image);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ restore();
+ }
+ }
+}
+
+#ifdef OPENVG_VERSION_1_1
+void PainterOpenVG::drawText(VGFont vgFont, Vector<VGuint>& characters, VGfloat* adjustmentsX, VGfloat* adjustmentsY, const FloatPoint& point)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+
+ if (m_state->textDrawingMode & TextModeClip)
+ return; // unsupported for every port except CG at the time of writing
+ if (m_state->textDrawingMode & TextModeFill && !m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+ if (m_state->textDrawingMode & TextModeStroke && !m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+
+ m_surface->makeCurrent();
+
+ FloatPoint effectivePoint = m_state->surfaceTransformation.mapPoint(point);
+ FloatPoint p = point;
+ AffineTransform* originalTransformation = 0;
+
+ // In case the font isn't drawn at a pixel-exact baseline and we can easily
+ // fix that (which is the case for non-rotated affine transforms), let's
+ // align the starting point to the pixel boundary in order to prevent
+ // font rendering issues such as glyphs that appear off by a pixel.
+ // This causes us to have inconsistent spacing between baselines in a
+ // larger paragraph, but that seems to be the least of all evils.
+ if ((fmod(effectivePoint.x() + 0.01, 1.0) > 0.02 || fmod(effectivePoint.y() + 0.01, 1.0) > 0.02)
+ && isNonRotatedAffineTransformation(m_state->surfaceTransformation))
+ {
+ originalTransformation = new AffineTransform(m_state->surfaceTransformation);
+ setTransformation(AffineTransform(
+ m_state->surfaceTransformation.a(), 0,
+ 0, m_state->surfaceTransformation.d(),
+ roundf(effectivePoint.x()), roundf(effectivePoint.y())));
+ p = FloatPoint();
+ }
+
+ const VGfloat vgPoint[2] = { p.x(), p.y() };
+ vgSetfv(VG_GLYPH_ORIGIN, 2, vgPoint);
+ ASSERT_VG_NO_ERROR();
+
+ vgDrawGlyphs(vgFont, characters.size(), characters.data(),
+ adjustmentsX, adjustmentsY, paintModes, VG_TRUE /* allow autohinting */);
+ ASSERT_VG_NO_ERROR();
+
+ if (originalTransformation) {
+ setTransformation(*originalTransformation);
+ delete originalTransformation;
+ }
+}
+#endif
+
+TiledImageOpenVG* PainterOpenVG::asNewNativeImage(const IntRect& src, VGImageFormat format)
+{
+ ASSERT(m_state);
+ m_surface->sharedSurface()->makeCurrent();
+
+ const IntSize vgMaxImageSize(vgGeti(VG_MAX_IMAGE_WIDTH), vgGeti(VG_MAX_IMAGE_HEIGHT));
+ ASSERT_VG_NO_ERROR();
+
+ const IntRect rect = intersection(src, IntRect(0, 0, m_surface->width(), m_surface->height()));
+ TiledImageOpenVG* tiledImage = new TiledImageOpenVG(rect.size(), vgMaxImageSize);
+
+ const int numColumns = tiledImage->numColumns();
+ const int numRows = tiledImage->numRows();
+
+ // Create the images as resources of the shared surface/context.
+ for (int yIndex = 0; yIndex < numRows; ++yIndex) {
+ for (int xIndex = 0; xIndex < numColumns; ++xIndex) {
+ IntRect tileRect = tiledImage->tileRect(xIndex, yIndex);
+ VGImage image = vgCreateImage(format, tileRect.width(), tileRect.height(), VG_IMAGE_QUALITY_FASTER);
+ ASSERT_VG_NO_ERROR();
+
+ tiledImage->setTile(xIndex, yIndex, image);
+ }
+ }
+
+ // Fill the image contents with our own surface/context being current.
+ m_surface->makeCurrent();
+
+ for (int yIndex = 0; yIndex < numRows; ++yIndex) {
+ for (int xIndex = 0; xIndex < numColumns; ++xIndex) {
+ IntRect tileRect = tiledImage->tileRect(xIndex, yIndex);
+
+ vgGetPixels(tiledImage->tile(xIndex, yIndex), 0, 0,
+ rect.x() + tileRect.x(), rect.y() + tileRect.y(),
+ tileRect.width(), tileRect.height());
+ ASSERT_VG_NO_ERROR();
+ }
+ }
+
+ return tiledImage;
+}
+
+void PainterOpenVG::save(PainterOpenVG::SaveMode saveMode)
+{
+ ASSERT(m_state);
+
+ // If the underlying context/surface was switched away by someone without
+ // telling us, it might not correspond to the one assigned to this painter.
+ // Switch back so we can save the state properly. (Should happen rarely.)
+ // Use DontSaveOrApplyPainterState mode in order to avoid recursion.
+ m_surface->makeCurrent(SurfaceOpenVG::DontSaveOrApplyPainterState);
+
+ if (saveMode == PainterOpenVG::CreateNewState) {
+ m_state->saveMaskIfNecessary(this);
+ PlatformPainterState* state = new PlatformPainterState(*m_state);
+ m_stateStack.append(state);
+ m_state = m_stateStack.last();
+ } else if (saveMode == PainterOpenVG::CreateNewStateWithPaintStateOnly) {
+ m_state->saveMaskIfNecessary(this);
+ PlatformPainterState* state = new PlatformPainterState();
+ state->copyPaintState(m_state);
+ m_stateStack.append(state);
+ m_state = m_stateStack.last();
+ } else // if (saveMode == PainterOpenVG::KeepCurrentState)
+ m_state->saveMaskIfNecessary(this);
+}
+
+void PainterOpenVG::restore()
+{
+ ASSERT(m_stateStack.size() >= 2);
+ m_surface->makeCurrent(SurfaceOpenVG::DontApplyPainterState);
+
+ PlatformPainterState* state = m_stateStack.last();
+ m_stateStack.removeLast();
+ delete state;
+
+ m_state = m_stateStack.last();
+ m_state->applyState(this);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/openvg/PainterOpenVG.h b/Source/WebCore/platform/graphics/openvg/PainterOpenVG.h
new file mode 100644
index 0000000..32f1fe5
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/PainterOpenVG.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PainterOpenVG_h
+#define PainterOpenVG_h
+
+#include "Color.h"
+#include "GraphicsContext.h"
+
+#include <openvg.h>
+
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class AffineTransform;
+class FloatPoint;
+class FloatRect;
+class IntRect;
+class IntSize;
+class Path;
+class SurfaceOpenVG;
+class TiledImageOpenVG;
+
+struct PlatformPainterState;
+
+class PainterOpenVG : public Noncopyable {
+public:
+ friend class SurfaceOpenVG;
+ friend struct PlatformPainterState;
+
+ enum SaveMode {
+ CreateNewState,
+ KeepCurrentState,
+ CreateNewStateWithPaintStateOnly // internal usage only, do not use outside PainterOpenVG
+ };
+ enum ClipOperation {
+ IntersectClip = VG_INTERSECT_MASK,
+ SubtractClip = VG_SUBTRACT_MASK
+ };
+
+ PainterOpenVG();
+ PainterOpenVG(SurfaceOpenVG*);
+ ~PainterOpenVG();
+
+ void begin(SurfaceOpenVG*);
+ void end();
+
+ AffineTransform transformation() const;
+ void setTransformation(const AffineTransform&);
+ void concatTransformation(const AffineTransform&);
+
+ static void transformPath(VGPath dst, VGPath src, const AffineTransform&);
+
+ CompositeOperator compositeOperation() const;
+ void setCompositeOperation(CompositeOperator);
+ float opacity() const;
+ void setOpacity(float);
+
+ float strokeThickness() const;
+ void setStrokeThickness(float);
+ StrokeStyle strokeStyle() const;
+ void setStrokeStyle(StrokeStyle);
+
+ void setLineDash(const DashArray&, float dashOffset);
+ void setLineCap(LineCap);
+ void setLineJoin(LineJoin);
+ void setMiterLimit(float);
+
+ Color strokeColor() const;
+ void setStrokeColor(const Color&);
+
+ Color fillColor() const;
+ void setFillColor(const Color&);
+
+ int textDrawingMode() const;
+ void setTextDrawingMode(int mode);
+
+ bool antialiasingEnabled() const;
+ void setAntialiasingEnabled(bool);
+
+ void drawRect(const FloatRect&, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH));
+ void drawRoundedRect(const FloatRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH));
+ void drawLine(const IntPoint& from, const IntPoint& to);
+ void drawArc(const IntRect& ellipseBounds, int startAngle, int angleSpan, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH));
+ void drawEllipse(const IntRect& bounds, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH));
+ void drawPolygon(size_t numPoints, const FloatPoint* points, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH));
+ void drawImage(TiledImageOpenVG*, const FloatRect& dst, const FloatRect& src);
+#ifdef OPENVG_VERSION_1_1
+ void drawText(VGFont, Vector<VGuint>& characters, VGfloat* adjustmentsX, VGfloat* adjustmentsY, const FloatPoint&);
+#endif
+
+ void scale(const FloatSize& scaleFactors);
+ void rotate(float radians);
+ void translate(float dx, float dy);
+
+ void drawPath(const Path&, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH), WindRule fillRule = RULE_NONZERO);
+
+ void intersectClipRect(const FloatRect&);
+ void clipPath(const Path&, PainterOpenVG::ClipOperation, WindRule clipRule = RULE_NONZERO);
+
+ TiledImageOpenVG* asNewNativeImage(const IntRect& src, VGImageFormat);
+
+ void save(PainterOpenVG::SaveMode saveMode = CreateNewState);
+ void restore();
+
+ SurfaceOpenVG* surface() { return m_surface; }
+ void blitToSurface();
+
+private:
+ void destroyPainterStates();
+ void applyState();
+
+ void intersectScissorRect(const FloatRect&);
+
+private:
+ Vector<PlatformPainterState*> m_stateStack;
+ PlatformPainterState* m_state;
+ SurfaceOpenVG* m_surface;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/openvg/PathOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/PathOpenVG.cpp
new file mode 100644
index 0000000..39a4b06
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/PathOpenVG.cpp
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "PainterOpenVG.h"
+#include "PlatformPathOpenVG.h"
+#include "PlatformString.h"
+#include "StrokeStyleApplier.h"
+#include "VGUtils.h"
+
+#include <openvg.h>
+#include <wtf/MathExtras.h>
+
+#define WEBKIT_VG_PATH_CAPABILITIES VG_PATH_CAPABILITY_ALL
+
+#define FUZZY_COMPARE(number, reference, delta) \
+ (number >= (reference - delta) && number <= (reference + delta))
+
+namespace WebCore {
+
+PlatformPathOpenVG::PlatformPathOpenVG()
+ : SharedResourceOpenVG()
+{
+ createPath();
+}
+
+PlatformPathOpenVG::PlatformPathOpenVG(const PlatformPathOpenVG& other)
+ : SharedResourceOpenVG()
+ , m_currentPoint(other.m_currentPoint)
+ , m_subpathStartPoint(other.m_subpathStartPoint)
+{
+ createPath();
+ // makeCompatibleContextCurrent() is called by createPath(), so not necessary here.
+ vgAppendPath(m_vgPath, other.m_vgPath);
+ ASSERT_VG_NO_ERROR();
+}
+
+PlatformPathOpenVG& PlatformPathOpenVG::operator=(const PlatformPathOpenVG& other)
+{
+ if (&other != this) {
+ clear();
+ // makeCompatibleContextCurrent() is called by clear(), so not necessary here.
+ vgAppendPath(m_vgPath, other.m_vgPath);
+ ASSERT_VG_NO_ERROR();
+ }
+ return *this;
+}
+
+PlatformPathOpenVG::~PlatformPathOpenVG()
+{
+ makeCompatibleContextCurrent();
+
+ vgDestroyPath(m_vgPath);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PlatformPathOpenVG::clear()
+{
+ makeCompatibleContextCurrent();
+
+ vgClearPath(m_vgPath, WEBKIT_VG_PATH_CAPABILITIES);
+ ASSERT_VG_NO_ERROR();
+
+ m_subpathStartPoint.setX(0);
+ m_subpathStartPoint.setY(0);
+ m_currentPoint = m_subpathStartPoint;
+}
+
+void PlatformPathOpenVG::createPath()
+{
+ makeSharedContextCurrent();
+
+ m_vgPath = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 0 /* expected number of segments */,
+ 0 /* expected number of total coordinates */,
+ WEBKIT_VG_PATH_CAPABILITIES);
+ ASSERT_VG_NO_ERROR();
+}
+
+
+Path::Path()
+{
+ m_path = new PlatformPathOpenVG();
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path::Path(const Path& other)
+{
+ m_path = new PlatformPathOpenVG(*(other.m_path));
+}
+
+Path& Path::operator=(const Path& other)
+{
+ *m_path = *(other.m_path);
+ return *this;
+}
+
+FloatPoint Path::currentPoint() const
+{
+ // FIXME: is this the way to return the current point of the subpath?
+ return m_currentPoint;
+}
+
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ notImplemented();
+
+ // OpenVG has no path-contains function, so for now we approximate by
+ // using the bounding rect of the path.
+ return boundingRect().contains(point);
+}
+
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ notImplemented();
+
+ // OpenVG has no path-contains function, so for now we approximate by
+ // using the stroke bounding rect of the path.
+ return (const_cast<Path*>(this))->strokeBoundingRect().contains(point);
+}
+
+void Path::translate(const FloatSize& size)
+{
+ AffineTransform transformation;
+ transformation.translate(size.width(), size.height());
+ transform(transformation);
+}
+
+FloatRect Path::boundingRect() const
+{
+ VGfloat minX;
+ VGfloat minY;
+ VGfloat width;
+ VGfloat height;
+
+ m_path->makeCompatibleContextCurrent();
+ vgPathBounds(m_path->vgPath(), &minX, &minY, &width, &height);
+ ASSERT_VG_NO_ERROR();
+
+ return FloatRect(FloatPoint(minX, minY), FloatSize(width, height));
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ notImplemented();
+
+ // vgPathBounds() ignores stroke parameters, and we don't currently have
+ // an approximation that takes stroke parameters into account.
+ return boundingRect();
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ static const VGubyte pathSegments[] = { VG_MOVE_TO_ABS };
+ const VGfloat pathData[] = { point.x(), point.y() };
+
+ m_path->makeCompatibleContextCurrent();
+ vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
+ ASSERT_VG_NO_ERROR();
+
+ m_path->m_currentPoint = m_path->m_subpathStartPoint = point;
+}
+
+void Path::addLineTo(const FloatPoint& point)
+{
+ static const VGubyte pathSegments[] = { VG_LINE_TO_ABS };
+ const VGfloat pathData[] = { point.x(), point.y() };
+
+ m_path->makeCompatibleContextCurrent();
+ vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
+ ASSERT_VG_NO_ERROR();
+
+ m_path->m_currentPoint = point;
+}
+
+void Path::addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& endPoint)
+{
+ static const VGubyte pathSegments[] = { VG_QUAD_TO_ABS };
+ const VGfloat pathData[] = { controlPoint.x(), controlPoint.y(), endPoint.x(), endPoint.y() };
+
+ m_path->makeCompatibleContextCurrent();
+ vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
+ ASSERT_VG_NO_ERROR();
+
+ m_path->m_currentPoint = endPoint;
+}
+
+void Path::addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& endPoint)
+{
+ static const VGubyte pathSegments[] = { VG_CUBIC_TO_ABS };
+ const VGfloat pathData[] = { controlPoint1.x(), controlPoint1.y(), controlPoint2.x(), controlPoint2.y(), endPoint.x(), endPoint.y() };
+
+ m_path->makeCompatibleContextCurrent();
+ vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
+ ASSERT_VG_NO_ERROR();
+
+ m_path->m_currentPoint = endPoint;
+}
+
+void Path::addArcTo(const FloatPoint& point1, const FloatPoint& point2, float radius)
+{
+ // See http://philip.html5.org/tests/canvas/suite/tests/spec.html#arcto.
+
+ const FloatPoint& point0 = m_path->m_currentPoint;
+ if (!radius || point0 == point1 || point1 == point2) {
+ addLineTo(point1);
+ return;
+ }
+
+ FloatSize v01 = point0 - point1;
+ FloatSize v21 = point2 - point1;
+
+ // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A)
+ double cross = v01.width() * v21.height() - v01.height() * v21.width();
+
+ if (fabs(cross) < 1E-10) {
+ // on one line
+ addLineTo(point1);
+ return;
+ }
+
+ double d01 = hypot(v01.width(), v01.height());
+ double d21 = hypot(v21.width(), v21.height());
+ double angle = (piDouble - fabs(asin(cross / (d01 * d21)))) * 0.5;
+ double span = radius * tan(angle);
+ double rate = span / d01;
+ FloatPoint startPoint = FloatPoint(point1.x() + v01.width() * rate,
+ point1.y() + v01.height() * rate);
+ rate = span / d21;
+ FloatPoint endPoint = FloatPoint(point1.x() + v21.width() * rate,
+ point1.y() + v21.height() * rate);
+
+ // Fa: large arc flag, makes the difference between SCWARC_TO and LCWARC_TO
+ // respectively SCCWARC_TO and LCCWARC_TO arcs. We always use small
+ // arcs for arcTo(), as the arc is defined as the "shortest arc" of the
+ // circle specified in HTML 5.
+
+ // Fs: sweep flag, specifying whether the arc is drawn in increasing (true)
+ // or decreasing (0) direction.
+ const bool anticlockwise = cross < 0;
+
+ // Translate the large arc and sweep flags into an OpenVG segment command.
+ const VGubyte segmentCommand = anticlockwise ? VG_SCCWARC_TO_ABS : VG_SCWARC_TO_ABS;
+
+ const VGubyte pathSegments[] = {
+ VG_LINE_TO_ABS,
+ segmentCommand
+ };
+ const VGfloat pathData[] = {
+ startPoint.x(), startPoint.y(),
+ radius, radius, 0, endPoint.x(), endPoint.y()
+ };
+
+ m_path->makeCompatibleContextCurrent();
+ vgAppendPathData(m_path->vgPath(), 2, pathSegments, pathData);
+ ASSERT_VG_NO_ERROR();
+
+ m_path->m_currentPoint = endPoint;
+}
+
+void Path::closeSubpath()
+{
+ static const VGubyte pathSegments[] = { VG_CLOSE_PATH };
+ // pathData must not be 0, but certain compilers also don't create
+ // zero-size arrays. So let's use a random aligned value (sizeof(VGfloat)),
+ // it won't be accessed anyways as VG_CLOSE_PATH doesn't take coordinates.
+ static const VGfloat* pathData = reinterpret_cast<VGfloat*>(sizeof(VGfloat));
+
+ m_path->makeCompatibleContextCurrent();
+ vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
+ ASSERT_VG_NO_ERROR();
+
+ m_path->m_currentPoint = m_path->m_subpathStartPoint;
+}
+
+void Path::addArc(const FloatPoint& center, float radius, float startAngle, float endAngle, bool anticlockwise)
+{
+ // The OpenVG spec says nothing about inf as radius or start/end angle.
+ // WebKit seems to pass those (e.g. https://bugs.webkit.org/show_bug.cgi?id=16449),
+ // so abort instead of risking undefined behavior.
+ if (!isfinite(radius) || !isfinite(startAngle) || !isfinite(endAngle))
+ return;
+
+ // For some reason, the HTML 5 spec defines the angle as going clockwise
+ // from the positive X axis instead of going standard anticlockwise.
+ // So let's make it a proper angle in order to keep sanity.
+ startAngle = fmod((2.0 * piDouble) - startAngle, 2.0 * piDouble);
+ endAngle = fmod((2.0 * piDouble) - endAngle, 2.0 * piDouble);
+
+ // Make it so that endAngle > startAngle. fmod() above takes care of
+ // keeping the difference below 360 degrees.
+ if (endAngle <= startAngle)
+ endAngle += 2.0 * piDouble;
+
+ const VGfloat angleDelta = anticlockwise
+ ? (endAngle - startAngle)
+ : (startAngle - endAngle + (2.0 * piDouble));
+
+ // OpenVG uses endpoint parameterization while this method receives its
+ // values in center parameterization. It lacks an ellipse rotation
+ // parameter so we use 0 for that, and also the radius is only a single
+ // value which makes for rh == rv. In order to convert from endpoint to
+ // center parameterization, we use the formulas from the OpenVG/SVG specs:
+
+ // (x,y) = (cos rot, -sin rot; sin rot, -cos rot) * (rh * cos angle, rv * sin angle) + (center.x, center.y)
+ // rot is 0, which simplifies this a bit:
+ // (x,y) = (1, 0; 0, -1) * (rh * cos angle, rv * sin angle) + (center.x, center.y)
+ // = (1 * rh * cos angle + 0 * rv * sin angle, 0 * rh * cos angle + -1 * rv * sin angle) + (center.x, center.y)
+ // = (rh * cos angle, -rv * sin angle) + (center.x, center.y)
+ // (Set angle = {startAngle, endAngle} to retrieve the respective endpoints.)
+
+ const VGfloat startX = radius * cos(startAngle) + center.x();
+ const VGfloat startY = -radius * sin(startAngle) + center.y();
+ const VGfloat endX = radius * cos(endAngle) + center.x();
+ const VGfloat endY = -radius * sin(endAngle) + center.y();
+
+ // Fa: large arc flag, makes the difference between SCWARC_TO and LCWARC_TO
+ // respectively SCCWARC_TO and LCCWARC_TO arcs.
+ const bool largeArc = (angleDelta > piDouble);
+
+ // Fs: sweep flag, specifying whether the arc is drawn in increasing (true)
+ // or decreasing (0) direction. No need to calculate this value, as it
+ // we already get it passed as a parameter (Fs == !anticlockwise).
+
+ // Translate the large arc and sweep flags into an OpenVG segment command.
+ // As OpenVG thinks of everything upside down, we need to reverse the
+ // anticlockwise parameter in order to get the specified rotation.
+ const VGubyte segmentCommand = !anticlockwise
+ ? (largeArc ? VG_LCCWARC_TO_ABS : VG_SCCWARC_TO_ABS)
+ : (largeArc ? VG_LCWARC_TO_ABS : VG_SCWARC_TO_ABS);
+
+ // So now, we've got all the parameters in endpoint parameterization format
+ // as OpenVG requires it. Which means we can just pass it like this.
+ const VGubyte pathSegments[] = {
+ hasCurrentPoint() ? VG_LINE_TO_ABS : VG_MOVE_TO_ABS,
+ segmentCommand
+ };
+ const VGfloat pathData[] = {
+ startX, startY,
+ radius, radius, 0, endX, endY
+ };
+
+ m_path->makeCompatibleContextCurrent();
+ vgAppendPathData(m_path->vgPath(), 2, pathSegments, pathData);
+ ASSERT_VG_NO_ERROR();
+
+ m_path->m_currentPoint.setX(endX);
+ m_path->m_currentPoint.setY(endY);
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+ static const VGubyte pathSegments[] = {
+ VG_MOVE_TO_ABS,
+ VG_HLINE_TO_REL,
+ VG_VLINE_TO_REL,
+ VG_HLINE_TO_REL,
+ VG_CLOSE_PATH
+ };
+ const VGfloat pathData[] = {
+ rect.x(), rect.y(),
+ rect.width(),
+ rect.height(),
+ -rect.width()
+ };
+
+ m_path->makeCompatibleContextCurrent();
+ vgAppendPathData(m_path->vgPath(), 5, pathSegments, pathData);
+ ASSERT_VG_NO_ERROR();
+
+ m_path->m_currentPoint = m_path->m_subpathStartPoint = rect.location();
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+ static const VGubyte pathSegments[] = {
+ VG_MOVE_TO_ABS,
+ VG_SCCWARC_TO_REL,
+ VG_SCCWARC_TO_REL,
+ VG_CLOSE_PATH
+ };
+ const VGfloat pathData[] = {
+ rect.x() + rect.width() / 2.0, rect.y(),
+ rect.width() / 2.0, rect.height() / 2.0, 0, 0, rect.height(),
+ rect.width() / 2.0, rect.height() / 2.0, 0, 0, -rect.height()
+ };
+
+ m_path->makeCompatibleContextCurrent();
+ vgAppendPathData(m_path->vgPath(), 4, pathSegments, pathData);
+ ASSERT_VG_NO_ERROR();
+}
+
+void Path::clear()
+{
+ m_path->clear();
+}
+
+bool Path::isEmpty() const
+{
+ m_path->makeCompatibleContextCurrent();
+ return !vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS);
+}
+
+bool Path::hasCurrentPoint() const
+{
+ m_path->makeCompatibleContextCurrent();
+ return vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS) > 0;
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ // OpenVG provides no means to retrieve path segment information.
+ // This is *very* unfortunate, we might need to store the segments in
+ // memory if we want to implement this function properly.
+ // See http://www.khronos.org/message_boards/viewtopic.php?f=6&t=1887
+ notImplemented();
+}
+
+void Path::transform(const AffineTransform& transformation)
+{
+ PlatformPathOpenVG* dst = new PlatformPathOpenVG();
+ // dst->makeCompatibleContextCurrent() is called by the platform path
+ // constructor, therefore not necessary to call it again here.
+ PainterOpenVG::transformPath(dst->vgPath(), m_path->vgPath(), transformation);
+ delete m_path;
+ m_path = dst;
+
+ m_path->m_currentPoint = transformation.mapPoint(m_path->m_currentPoint);
+ m_path->m_subpathStartPoint = transformation.mapPoint(m_path->m_subpathStartPoint);
+}
+
+
+// Path::length(), Path::pointAtLength() and Path::normalAngleAtLength() are
+// reimplemented here instead of in Path.cpp, because OpenVG has its own
+// functions and Path::apply() doesn't really work as long as we rely on VGPath
+// as primary path storage.
+
+float Path::length()
+{
+ m_path->makeCompatibleContextCurrent();
+ VGfloat length = vgPathLength(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS));
+ ASSERT_VG_NO_ERROR();
+ return length;
+}
+
+FloatPoint Path::pointAtLength(float length, bool& ok)
+{
+ VGfloat x = 0, y = 0;
+ m_path->makeCompatibleContextCurrent();
+
+ vgPointAlongPath(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS),
+ length, &x, &y, 0, 0);
+ ok = (vgGetError() == VG_NO_ERROR);
+ return FloatPoint(x, y);
+}
+
+float Path::normalAngleAtLength(float length, bool& ok)
+{
+ VGfloat tangentX, tangentY;
+ m_path->makeCompatibleContextCurrent();
+
+ vgPointAlongPath(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS),
+ length, 0, 0, &tangentX, &tangentY);
+ ok = (vgGetError() == VG_NO_ERROR);
+ return atan2f(tangentY, tangentX) * 180.0 / piFloat; // convert to degrees
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/openvg/PlatformPathOpenVG.h b/Source/WebCore/platform/graphics/openvg/PlatformPathOpenVG.h
new file mode 100644
index 0000000..286da53
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/PlatformPathOpenVG.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PlatformPathOpenVG_h
+#define PlatformPathOpenVG_h
+
+#include "FloatPoint.h"
+#include "SharedResourceOpenVG.h"
+
+#include <openvg.h>
+
+namespace WebCore {
+
+class PlatformPathOpenVG : public SharedResourceOpenVG {
+public:
+ PlatformPathOpenVG();
+ PlatformPathOpenVG(const PlatformPathOpenVG&);
+ ~PlatformPathOpenVG();
+
+ PlatformPathOpenVG& operator=(const PlatformPathOpenVG&);
+
+ VGPath vgPath() { return m_vgPath; }
+ void clear();
+
+public:
+ FloatPoint m_currentPoint;
+ FloatPoint m_subpathStartPoint;
+
+private:
+ void createPath();
+
+ VGPath m_vgPath;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/openvg/SharedResourceOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/SharedResourceOpenVG.cpp
new file mode 100644
index 0000000..a843db5
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/SharedResourceOpenVG.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "SharedResourceOpenVG.h"
+
+#include "SurfaceOpenVG.h"
+
+#if PLATFORM(EGL)
+#include "EGLDisplayOpenVG.h"
+#endif
+
+namespace WebCore {
+
+void SharedResourceOpenVG::makeSharedContextCurrent()
+{
+#if PLATFORM(EGL)
+ EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent();
+#endif
+}
+
+void SharedResourceOpenVG::makeCompatibleContextCurrent()
+{
+#if PLATFORM(EGL)
+ EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCompatibleCurrent();
+#endif
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/openvg/SharedResourceOpenVG.h b/Source/WebCore/platform/graphics/openvg/SharedResourceOpenVG.h
new file mode 100644
index 0000000..436ae90
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/SharedResourceOpenVG.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SharedResourceOpenVG_h
+#define SharedResourceOpenVG_h
+
+namespace WebCore {
+
+class SharedResourceOpenVG {
+public:
+ void makeSharedContextCurrent();
+ void makeCompatibleContextCurrent();
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp
new file mode 100644
index 0000000..6700c6f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "SurfaceOpenVG.h"
+
+#include "IntSize.h"
+#include "PainterOpenVG.h"
+
+#if PLATFORM(EGL)
+#include "EGLDisplayOpenVG.h"
+#include "EGLUtils.h"
+#endif
+
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+PainterOpenVG* SurfaceOpenVG::s_currentPainter = 0;
+
+SurfaceOpenVG* SurfaceOpenVG::currentSurface()
+{
+#if PLATFORM(EGL)
+ return EGLDisplayOpenVG::currentSurface();
+#else
+ ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+#if PLATFORM(EGL)
+SurfaceOpenVG::SurfaceOpenVG(const IntSize& size, const EGLDisplay& display, EGLConfig* confPtr, EGLint* errorCode)
+ : m_activePainter(0)
+ , m_eglDisplay(display)
+ , m_eglSurface(EGL_NO_SURFACE)
+ , m_eglContext(EGL_NO_CONTEXT)
+{
+ ASSERT(m_eglDisplay != EGL_NO_DISPLAY);
+
+ EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(m_eglDisplay);
+ EGLConfig config = confPtr ? (*confPtr) : displayManager->defaultPbufferConfig();
+ m_eglSurface = displayManager->createPbufferSurface(size, config, errorCode);
+
+ if (m_eglSurface == EGL_NO_SURFACE)
+ return;
+
+ m_eglContext = displayManager->contextForSurface(m_eglSurface);
+ EGLDisplayOpenVG::registerPlatformSurface(this);
+}
+
+SurfaceOpenVG::SurfaceOpenVG(EGLClientBuffer buffer, EGLenum bufferType, const EGLDisplay& display, EGLConfig* confPtr, EGLint* errorCode)
+ : m_activePainter(0)
+ , m_eglDisplay(display)
+ , m_eglSurface(EGL_NO_SURFACE)
+ , m_eglContext(EGL_NO_CONTEXT)
+{
+ ASSERT(m_eglDisplay != EGL_NO_DISPLAY);
+
+ EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(m_eglDisplay);
+ EGLConfig config = confPtr ? (*confPtr) : displayManager->defaultPbufferConfig();
+ m_eglSurface = displayManager->createPbufferFromClientBuffer(buffer, bufferType, config, errorCode);
+
+ if (m_eglSurface == EGL_NO_SURFACE)
+ return;
+
+ m_eglContext = displayManager->contextForSurface(m_eglSurface);
+ EGLDisplayOpenVG::registerPlatformSurface(this);
+}
+
+SurfaceOpenVG::SurfaceOpenVG(EGLNativeWindowType window, const EGLDisplay& display, EGLConfig* confPtr)
+ : m_activePainter(0)
+ , m_eglDisplay(display)
+ , m_eglSurface(EGL_NO_SURFACE)
+ , m_eglContext(EGL_NO_CONTEXT)
+{
+ ASSERT(m_eglDisplay != EGL_NO_DISPLAY);
+
+ EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(m_eglDisplay);
+ EGLConfig config = confPtr ? (*confPtr) : displayManager->defaultWindowConfig();
+ m_eglSurface = displayManager->surfaceForWindow(window, config);
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ m_eglContext = displayManager->contextForSurface(m_eglSurface);
+ EGLDisplayOpenVG::registerPlatformSurface(this);
+}
+
+// Constructor only accessible to EGLDisplayOpenVG for shared context
+// initialization. The parameter types might define to void* like in the
+// window surface constructor, so it can't be overloaded with all the required
+// arguments and EGLDisplayOpenVG basically implements the constructor
+// by itself.
+SurfaceOpenVG::SurfaceOpenVG()
+ : m_activePainter(0)
+ , m_eglDisplay(EGL_NO_DISPLAY)
+ , m_eglSurface(EGL_NO_SURFACE)
+ , m_eglContext(EGL_NO_CONTEXT)
+{
+}
+#endif
+
+SurfaceOpenVG::~SurfaceOpenVG()
+{
+ if (!isValid())
+ return;
+
+ if (m_activePainter && this == m_activePainter->baseSurface())
+ m_activePainter->end();
+
+#if PLATFORM(EGL)
+ EGLDisplayOpenVG::forDisplay(m_eglDisplay)->destroySurface(m_eglSurface);
+ EGLDisplayOpenVG::unregisterPlatformSurface(this);
+#else
+ ASSERT_NOT_REACHED();
+#endif
+}
+
+bool SurfaceOpenVG::isValid() const
+{
+#if PLATFORM(EGL)
+ return (m_eglSurface != EGL_NO_SURFACE);
+#else
+ ASSERT_NOT_REACHED();
+ return false;
+#endif
+}
+
+int SurfaceOpenVG::width() const
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ EGLint width;
+ eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH, &width);
+ ASSERT_EGL_NO_ERROR();
+ return width;
+#else
+ ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+int SurfaceOpenVG::height() const
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ EGLint height;
+ eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &height);
+ ASSERT_EGL_NO_ERROR();
+ return height;
+#else
+ ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+SurfaceOpenVG* SurfaceOpenVG::sharedSurface() const
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+ return EGLDisplayOpenVG::forDisplay(m_eglDisplay)->sharedPlatformSurface();
+#else
+ ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+void SurfaceOpenVG::makeCurrent(MakeCurrentMode mode)
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ eglBindAPI(EGL_OPENVG_API);
+ ASSERT_EGL_NO_ERROR();
+ EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
+ ASSERT_EGL_NO_ERROR();
+
+ if (currentSurface != m_eglSurface) {
+ // Save other context before switching over.
+ if (s_currentPainter && mode != DontSaveOrApplyPainterState
+ && s_currentPainter->surface()->m_eglSurface == currentSurface)
+ s_currentPainter->save(PainterOpenVG::KeepCurrentState);
+
+ eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
+ ASSERT_EGL_NO_ERROR();
+ s_currentPainter = 0;
+ }
+#endif
+
+ if (m_activePainter && mode == ApplyPainterStateOnSurfaceSwitch
+ && s_currentPainter != m_activePainter) {
+ m_activePainter->applyState();
+ s_currentPainter = m_activePainter;
+ }
+}
+
+void SurfaceOpenVG::makeCompatibleCurrent()
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ eglBindAPI(EGL_OPENVG_API);
+ ASSERT_EGL_NO_ERROR();
+ EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
+ ASSERT_EGL_NO_ERROR();
+
+ if (currentSurface == m_eglSurface) {
+ if (m_activePainter && s_currentPainter != m_activePainter) {
+ m_activePainter->applyState();
+ s_currentPainter = m_activePainter;
+ }
+ } else if (!EGLDisplayOpenVG::forDisplay(m_eglDisplay)->surfacesCompatible(currentSurface, m_eglSurface)) {
+ // Save other context before switching over.
+ if (s_currentPainter && s_currentPainter->surface()->m_eglSurface == currentSurface)
+ s_currentPainter->save(PainterOpenVG::KeepCurrentState);
+
+ eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
+ ASSERT_EGL_NO_ERROR();
+ s_currentPainter = 0;
+ }
+ // else: surfaces compatible, no need to switch contexts
+#endif
+}
+
+void SurfaceOpenVG::flush()
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ eglSwapBuffers(m_eglDisplay, m_eglSurface);
+ ASSERT_EGL_NO_ERROR();
+#endif
+}
+
+void SurfaceOpenVG::setActivePainter(PainterOpenVG* painter)
+{
+ ASSERT(isValid());
+
+ // If painter is non-zero, we want to make sure there was no previous painter set.
+ ASSERT(!painter || !m_activePainter);
+
+ // Make sure a disabled painter isn't marked as global current painter anymore.
+ if (!painter && s_currentPainter == m_activePainter)
+ s_currentPainter = 0;
+
+ m_activePainter = painter;
+}
+
+PainterOpenVG* SurfaceOpenVG::activePainter()
+{
+ ASSERT(isValid());
+ return m_activePainter;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/openvg/SurfaceOpenVG.h b/Source/WebCore/platform/graphics/openvg/SurfaceOpenVG.h
new file mode 100644
index 0000000..46d1646
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/SurfaceOpenVG.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SurfaceOpenVG_h
+#define SurfaceOpenVG_h
+
+#if PLATFORM(EGL)
+#include <egl.h>
+#endif
+
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+#if PLATFORM(EGL)
+class EGLDisplayOpenVG;
+#endif
+class PainterOpenVG;
+class IntSize;
+
+/**
+ * SurfaceOpenVG provides the functionality of surfaces and contexts that are
+ * underlying the OpenVG implementation. In the vast majority of cases, that
+ * underlying technology is EGL, but OpenVG doesn't depend on EGL per se.
+ * Wrapping surface/context functionality into a separate class avoids lots
+ * of #ifdefs and should make it easy to add different surface/context
+ * implementations than EGL.
+ */
+class SurfaceOpenVG : public Noncopyable {
+public:
+ enum MakeCurrentMode {
+ ApplyPainterStateOnSurfaceSwitch,
+ DontApplyPainterState,
+ DontSaveOrApplyPainterState
+ };
+
+ static SurfaceOpenVG* currentSurface();
+
+#if PLATFORM(EGL)
+ friend class EGLDisplayOpenVG;
+
+ /**
+ * Create a new EGL pbuffer surface with the specified size and config on
+ * the given display. If config is not specified, the display's default
+ * pbuffer config is used.
+ *
+ * This constructor will trigger an assertion if creation of the surface
+ * fails, unless you pledge to manually process the error code by passing
+ * a non-zero pointer as errorCode parameter. The error code returned by
+ * eglGetError() will be written to that variable.
+ */
+ SurfaceOpenVG(const IntSize& size, const EGLDisplay& display, EGLConfig* config = 0, EGLint* errorCode = 0);
+
+ /**
+ * Create a new EGL pbuffer surface that will be bound to the given
+ * client buffer (read: VGImage), with the specified config on the
+ * given display. If config is not specified, the display's default
+ * pbuffer config is used.
+ *
+ * After the surface is created, you will only be able to access the
+ * client buffer image if the surface is not current. The recommended way
+ * to ensure this is to call surface->sharedSurface()->makeCurrent() if you
+ * simply want to access the image's pixel contents, or if you intend to
+ * draw the image directly, making the draw target surface current.
+ *
+ * This constructor will trigger an assertion if creation of the surface
+ * fails, unless you pledge to manually process the error code by passing
+ * a non-zero pointer as errorCode parameter. The error code returned by
+ * eglGetError() will be written to that variable.
+ */
+ SurfaceOpenVG(EGLClientBuffer buffer, EGLenum bufferType,
+ const EGLDisplay& display, EGLConfig* config = 0, EGLint* errorCode = 0);
+
+ /**
+ * Create a new EGL window surface with the specified native window handle
+ * and config on the given display. If config is not specified, the
+ * display's default window config is used.
+ */
+ SurfaceOpenVG(EGLNativeWindowType window, const EGLDisplay& display, EGLConfig* config = 0);
+
+ EGLDisplay eglDisplay() const { return m_eglDisplay; }
+ EGLSurface eglSurface() const { return m_eglSurface; }
+ EGLContext eglContext() const { return m_eglContext; }
+#endif
+
+ ~SurfaceOpenVG();
+
+ /**
+ * If a surface is invalid (could not be created), all method calls will
+ * crash horribly.
+ */
+ bool isValid() const;
+
+ int width() const;
+ int height() const;
+
+ SurfaceOpenVG* sharedSurface() const;
+
+ /**
+ * Make the associated GL/EGL context the current one, so that subsequent
+ * OpenVG commands apply to it.
+ */
+ void makeCurrent(MakeCurrentMode mode = ApplyPainterStateOnSurfaceSwitch);
+
+ /**
+ * Make a surface/context combination current that is "compatible"
+ * (i.e. can access its shared resources) to the given one. If no
+ * surface/context is current, the given one is made current.
+ *
+ * This method is meant to avoid context changes if they're not
+ * necessary, particularly tailored for the case where something
+ * compatible to the shared surface is requested while actual painting
+ * happens on another surface.
+ */
+ void makeCompatibleCurrent();
+
+ /**
+ * Empty the OpenVG pipeline and make sure all the performed paint
+ * operations show up on the surface as actual drawn pixels.
+ */
+ void flush();
+
+ void setActivePainter(PainterOpenVG*);
+ PainterOpenVG* activePainter();
+
+private:
+ PainterOpenVG* m_activePainter;
+ static PainterOpenVG* s_currentPainter; // global currently active painter
+
+#if PLATFORM(EGL)
+ SurfaceOpenVG(); // for EGLDisplayOpenVG
+
+ EGLDisplay m_eglDisplay;
+ EGLSurface m_eglSurface;
+ EGLContext m_eglContext;
+#endif
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/openvg/TiledImageOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/TiledImageOpenVG.cpp
new file mode 100644
index 0000000..64d94c9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/TiledImageOpenVG.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "TiledImageOpenVG.h"
+
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "VGUtils.h"
+
+namespace WebCore {
+
+TiledImageOpenVG::TiledImageOpenVG(const IntSize& size, const IntSize& tileSize)
+ : SharedResourceOpenVG()
+ , m_size(size)
+ , m_maxTileSize(tileSize)
+ , m_numColumns((m_size.width() - 1) / m_maxTileSize.width() + 1)
+ , m_tiles(((m_size.height() - 1) / m_maxTileSize.height() + 1) * m_numColumns, VG_INVALID_HANDLE)
+{
+}
+
+TiledImageOpenVG::TiledImageOpenVG(const TiledImageOpenVG& other)
+ : SharedResourceOpenVG()
+ , m_size(other.m_size)
+ , m_maxTileSize(other.m_maxTileSize)
+ , m_numColumns(other.m_numColumns)
+ , m_tiles(other.m_tiles)
+{
+ detachTiles();
+}
+
+TiledImageOpenVG& TiledImageOpenVG::operator=(const TiledImageOpenVG& other)
+{
+ if (&other != this) {
+ destroyTiles();
+
+ m_size = other.m_size;
+ m_maxTileSize = other.m_maxTileSize;
+ m_numColumns = other.m_numColumns;
+ m_tiles = other.m_tiles;
+
+ detachTiles();
+ }
+ return *this;
+}
+
+TiledImageOpenVG::~TiledImageOpenVG()
+{
+ destroyTiles();
+}
+
+int TiledImageOpenVG::numTiles() const
+{
+ return m_tiles.size();
+}
+
+int TiledImageOpenVG::numColumns() const
+{
+ return m_numColumns;
+}
+
+int TiledImageOpenVG::numRows() const
+{
+ return m_tiles.size() / m_numColumns;
+}
+
+void TiledImageOpenVG::setTile(int xIndex, int yIndex, VGImage image)
+{
+ ASSERT(xIndex < m_numColumns);
+ int i = (yIndex * m_numColumns) + xIndex;
+ ASSERT(i < m_tiles.size());
+ m_tiles.at(i) = image;
+}
+
+IntRect TiledImageOpenVG::tilesInRect(const FloatRect& rect) const
+{
+ int leftIndex = static_cast<int>(rect.x()) / m_maxTileSize.width();
+ int topIndex = static_cast<int>(rect.y()) / m_maxTileSize.height();
+
+ if (leftIndex < 0)
+ leftIndex = 0;
+ if (topIndex < 0)
+ topIndex = 0;
+
+ // Round rect edges up to get the outer pixel boundaries.
+ int rightIndex = (static_cast<int>(ceil(rect.right())) - 1) / m_maxTileSize.width();
+ int bottomIndex = (static_cast<int>(ceil(rect.bottom())) - 1) / m_maxTileSize.height();
+ int columns = (rightIndex - leftIndex) + 1;
+ int rows = (bottomIndex - topIndex) + 1;
+
+ return IntRect(leftIndex, topIndex,
+ (columns <= m_numColumns) ? columns : m_numColumns,
+ (rows <= (m_tiles.size() / m_numColumns)) ? rows : (m_tiles.size() / m_numColumns));
+}
+
+VGImage TiledImageOpenVG::tile(int xIndex, int yIndex) const
+{
+ ASSERT(xIndex < m_numColumns);
+ int i = (yIndex * m_numColumns) + xIndex;
+ ASSERT(i < m_tiles.size());
+ return m_tiles.at(i);
+}
+
+IntRect TiledImageOpenVG::tileRect(int xIndex, int yIndex) const
+{
+ ASSERT(xIndex < m_numColumns);
+ ASSERT((yIndex * m_numColumns) + xIndex < m_tiles.size());
+
+ int x = xIndex * m_maxTileSize.width();
+ int y = yIndex * m_maxTileSize.height();
+
+ return IntRect(x, y,
+ ((m_maxTileSize.width() < m_size.width() - x) ? m_maxTileSize.width() : (m_size.width() - x)),
+ ((m_maxTileSize.height() < m_size.height() - y) ? m_maxTileSize.height() : (m_size.height() - y)));
+}
+
+void TiledImageOpenVG::detachTiles()
+{
+ makeSharedContextCurrent(); // because we create new images
+
+ int numTiles = m_tiles.size();
+ VGImage newTile, originalTile;
+
+ for (int i = 0; i < numTiles; ++i) {
+ originalTile = m_tiles.at(i);
+
+ if (originalTile == VG_INVALID_HANDLE)
+ continue;
+
+ VGImageFormat format = (VGImageFormat) vgGetParameteri(originalTile, VG_IMAGE_FORMAT);
+ VGint width = vgGetParameteri(originalTile, VG_IMAGE_WIDTH);
+ VGint height = vgGetParameteri(originalTile, VG_IMAGE_HEIGHT);
+ ASSERT_VG_NO_ERROR();
+
+ newTile = vgCreateImage(format, width, height, VG_IMAGE_QUALITY_FASTER);
+ ASSERT_VG_NO_ERROR();
+
+ vgCopyImage(newTile, 0, 0, originalTile, 0, 0, width, height, VG_FALSE /* dither */);
+ ASSERT_VG_NO_ERROR();
+
+ m_tiles.at(i) = newTile;
+ }
+}
+
+void TiledImageOpenVG::destroyTiles()
+{
+ makeCompatibleContextCurrent();
+
+ Vector<VGImage>::const_iterator it = m_tiles.begin();
+ Vector<VGImage>::const_iterator end = m_tiles.end();
+
+ for (; it != end; ++it) {
+ if (*it != VG_INVALID_HANDLE)
+ vgDestroyImage(*it);
+ }
+ ASSERT_VG_NO_ERROR();
+
+ m_tiles.fill(VG_INVALID_HANDLE);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/openvg/TiledImageOpenVG.h b/Source/WebCore/platform/graphics/openvg/TiledImageOpenVG.h
new file mode 100644
index 0000000..c8f55d2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/TiledImageOpenVG.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TiledImageOpenVG_h
+#define TiledImageOpenVG_h
+
+#include "IntRect.h"
+#include "IntSize.h"
+#include "SharedResourceOpenVG.h"
+
+#include <openvg.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class FloatRect;
+
+class TiledImageOpenVG : public SharedResourceOpenVG {
+public:
+ TiledImageOpenVG(const IntSize& size, const IntSize& tileSize);
+ TiledImageOpenVG(const TiledImageOpenVG&);
+ ~TiledImageOpenVG();
+
+ TiledImageOpenVG& operator=(const TiledImageOpenVG&);
+
+ const IntSize& size() const { return m_size; }
+ const IntSize& maxTileSize() const { return m_maxTileSize; }
+
+ int numTiles() const;
+ int numColumns() const;
+ int numRows() const;
+
+ IntRect tilesInRect(const FloatRect&) const;
+
+ void setTile(int xIndex, int yIndex, VGImage);
+ VGImage tile(int xIndex, int yIndex) const;
+ IntRect tileRect(int xIndex, int yIndex) const;
+
+private:
+ void detachTiles();
+ void destroyTiles();
+
+ IntSize m_size;
+ IntSize m_maxTileSize;
+
+ int m_numColumns;
+
+ Vector<VGImage> m_tiles;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/openvg/VGUtils.cpp b/Source/WebCore/platform/graphics/openvg/VGUtils.cpp
new file mode 100644
index 0000000..2559aaf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/VGUtils.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "VGUtils.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "TransformationMatrix.h"
+
+namespace WebCore {
+
+VGMatrix::VGMatrix(const VGfloat data[9])
+{
+ m_data[0] = data[0];
+ m_data[1] = data[1];
+ m_data[2] = data[2];
+ m_data[3] = data[3];
+ m_data[4] = data[4];
+ m_data[5] = data[5];
+ m_data[6] = data[6];
+ m_data[7] = data[7];
+ m_data[8] = data[8];
+}
+
+VGMatrix::VGMatrix(const AffineTransform& transformation)
+{
+ m_data[0] = transformation.a();
+ m_data[1] = transformation.b();
+ m_data[2] = 0;
+ m_data[3] = transformation.c();
+ m_data[4] = transformation.d();
+ m_data[5] = 0;
+ m_data[6] = transformation.e();
+ m_data[7] = transformation.f();
+ m_data[8] = 1;
+}
+
+VGMatrix::VGMatrix(const TransformationMatrix& matrix)
+{
+ m_data[0] = matrix.m11();
+ m_data[1] = matrix.m12();
+ m_data[2] = matrix.m14();
+ m_data[3] = matrix.m21();
+ m_data[4] = matrix.m22();
+ m_data[5] = matrix.m24();
+ m_data[6] = matrix.m41();
+ m_data[7] = matrix.m42();
+ m_data[8] = matrix.m44();
+}
+
+VGMatrix::operator AffineTransform() const
+{
+ AffineTransform transformation(
+ m_data[0], m_data[1],
+ m_data[3], m_data[4],
+ m_data[6], m_data[7]);
+ return transformation;
+}
+
+VGMatrix::operator TransformationMatrix() const
+{
+ TransformationMatrix matrix(
+ m_data[0], m_data[1], 0, m_data[2],
+ m_data[3], m_data[4], 0, m_data[5],
+ 0, 0, 1, 0,
+ m_data[6], m_data[7], 0, m_data[8]);
+ return matrix;
+}
+
+AffineTransform::operator VGMatrix() const
+{
+ return VGMatrix(*this);
+}
+
+TransformationMatrix::operator VGMatrix() const
+{
+ return VGMatrix(*this);
+}
+
+VGRect::VGRect(const VGfloat data[4])
+{
+ m_data[0] = data[0];
+ m_data[1] = data[1];
+ m_data[2] = data[2];
+ m_data[3] = data[3];
+}
+
+VGRect::VGRect(const FloatRect& rect)
+{
+ m_data[0] = rect.x();
+ m_data[1] = rect.y();
+ m_data[2] = rect.width();
+ m_data[3] = rect.height();
+}
+
+VGRect::operator FloatRect() const
+{
+ return FloatRect(m_data[0], m_data[1], m_data[2], m_data[3]);
+}
+
+FloatRect::operator VGRect() const
+{
+ return VGRect(*this);
+}
+
+int VGUtils::bytesForImage(VGImageFormat format, VGint width, VGint height)
+{
+ return width * height * imageFormatBitsPerPixel(format) / 8;
+}
+
+int VGUtils::bytesForImageScanline(VGImageFormat format, VGint width)
+{
+ int bits = width * imageFormatBitsPerPixel(format);
+ if (bits % 8 > 1) // If unaligned, round up to the next byte.
+ bits += 8 - (bits % 8);
+
+ return bits / 8;
+}
+
+int VGUtils::imageFormatBitsPerPixel(VGImageFormat format)
+{
+ switch (format) {
+ case VG_sRGBX_8888:
+ case VG_sRGBA_8888:
+ case VG_sRGBA_8888_PRE:
+ case VG_lRGBX_8888:
+ case VG_lRGBA_8888:
+ case VG_lRGBA_8888_PRE:
+ case VG_sXRGB_8888:
+ case VG_sARGB_8888:
+ case VG_sARGB_8888_PRE:
+ case VG_lXRGB_8888:
+ case VG_lARGB_8888:
+ case VG_lARGB_8888_PRE:
+ case VG_sBGRX_8888:
+ case VG_sBGRA_8888:
+ case VG_sBGRA_8888_PRE:
+ case VG_lBGRX_8888:
+ case VG_lBGRA_8888:
+ case VG_lBGRA_8888_PRE:
+ case VG_sXBGR_8888:
+ case VG_sABGR_8888:
+ case VG_sABGR_8888_PRE:
+ case VG_lXBGR_8888:
+ case VG_lABGR_8888:
+ case VG_lABGR_8888_PRE:
+ return 32;
+
+ case VG_sRGB_565:
+ case VG_sRGBA_5551:
+ case VG_sRGBA_4444:
+ case VG_sARGB_1555:
+ case VG_sARGB_4444:
+ case VG_sBGR_565:
+ case VG_sBGRA_5551:
+ case VG_sBGRA_4444:
+ case VG_sABGR_1555:
+ case VG_sABGR_4444:
+ return 16;
+
+ case VG_sL_8:
+ case VG_lL_8:
+ case VG_A_8:
+ return 8;
+
+ case VG_A_4:
+ return 4;
+
+ case VG_BW_1:
+ case VG_A_1:
+ return 1;
+
+ default: // Will only happen when OpenVG extends the enum and we don't.
+ ASSERT(false);
+ return 0;
+ }
+}
+
+#ifndef WTF_PLATFORM_BIG_ENDIAN
+VGImageFormat VGUtils::endianAwareImageFormat(VGImageFormat bigEndianFormat)
+{
+ switch (bigEndianFormat) {
+ case VG_sRGBX_8888: return VG_sXBGR_8888;
+ case VG_sRGBA_8888: return VG_sABGR_8888;
+ case VG_sRGBA_8888_PRE: return VG_sABGR_8888_PRE;
+ case VG_lRGBX_8888: return VG_lXBGR_8888;
+ case VG_lRGBA_8888: return VG_lABGR_8888;
+ case VG_lRGBA_8888_PRE: return VG_lABGR_8888_PRE;
+ case VG_sXRGB_8888: return VG_sBGRX_8888;
+ case VG_sARGB_8888: return VG_sBGRA_8888;
+ case VG_sARGB_8888_PRE: return VG_sBGRA_8888_PRE;
+ case VG_lXRGB_8888: return VG_lBGRX_8888;
+ case VG_lARGB_8888: return VG_lBGRA_8888;
+ case VG_lARGB_8888_PRE: return VG_lBGRA_8888_PRE;
+ case VG_sBGRX_8888: return VG_sXRGB_8888;
+ case VG_sBGRA_8888: return VG_sARGB_8888;
+ case VG_sBGRA_8888_PRE: return VG_sARGB_8888_PRE;
+ case VG_lBGRX_8888: return VG_lXRGB_8888;
+ case VG_lBGRA_8888: return VG_lARGB_8888;
+ case VG_lBGRA_8888_PRE: return VG_lARGB_8888_PRE;
+ case VG_sXBGR_8888: return VG_sRGBX_8888;
+ case VG_sABGR_8888: return VG_sRGBA_8888;
+ case VG_sABGR_8888_PRE: return VG_sRGBA_8888_PRE;
+ case VG_lXBGR_8888: return VG_lRGBX_8888;
+ case VG_lABGR_8888: return VG_lRGBA_8888;
+ case VG_lABGR_8888_PRE: return VG_lRGBA_8888_PRE;
+ default: ASSERT(false);
+ return (VGImageFormat) 0;
+ }
+}
+#else
+VGImageFormat VGUtils::endianAwareImageFormat(VGImageFormat bigEndianFormat)
+{
+ return bigEndianFormat;
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/openvg/VGUtils.h b/Source/WebCore/platform/graphics/openvg/VGUtils.h
new file mode 100644
index 0000000..06d5fea
--- /dev/null
+++ b/Source/WebCore/platform/graphics/openvg/VGUtils.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef VGUtils_h
+#define VGUtils_h
+
+#include <openvg.h>
+#include <wtf/Assertions.h>
+
+static inline const char* toVGErrorConstant(VGErrorCode error)
+{
+ switch (error) {
+ case VG_BAD_HANDLE_ERROR:
+ return "VG_BAD_HANDLE_ERROR";
+ case VG_ILLEGAL_ARGUMENT_ERROR:
+ return "VG_ILLEGAL_ARGUMENT_ERROR";
+ case VG_OUT_OF_MEMORY_ERROR:
+ return "VG_OUT_OF_MEMORY_ERROR";
+ case VG_PATH_CAPABILITY_ERROR:
+ return "VG_PATH_CAPABILITY_ERROR";
+ case VG_UNSUPPORTED_IMAGE_FORMAT_ERROR:
+ return "VG_UNSUPPORTED_IMAGE_FORMAT_ERROR";
+ case VG_UNSUPPORTED_PATH_FORMAT_ERROR:
+ return "VG_UNSUPPORTED_PATH_FORMAT_ERROR";
+ case VG_IMAGE_IN_USE_ERROR:
+ return "VG_IMAGE_IN_USE_ERROR";
+ case VG_NO_CONTEXT_ERROR:
+ return "VG_NO_CONTEXT_ERROR";
+ default:
+ return "UNKNOWN_ERROR";
+ }
+}
+
+#if ASSERT_DISABLED
+#define ASSERT_VG_NO_ERROR() ((void)0)
+#else
+#define ASSERT_VG_NO_ERROR() do { \
+ VGErrorCode vgErrorCode = vgGetError(); \
+ ASSERT_WITH_MESSAGE(vgErrorCode == VG_NO_ERROR, "Found %s", toVGErrorConstant(vgErrorCode)); \
+} while (0)
+#endif
+
+
+namespace WebCore {
+
+class AffineTransform;
+class FloatRect;
+class TransformationMatrix;
+
+class VGMatrix {
+public:
+ VGMatrix(const VGfloat data[9]);
+ VGMatrix(const AffineTransform&);
+ VGMatrix(const TransformationMatrix&);
+ const VGfloat* toVGfloat() const { return m_data; }
+ operator AffineTransform() const;
+ operator TransformationMatrix() const;
+private:
+ VGfloat m_data[9];
+};
+
+class VGRect {
+public:
+ VGRect(const VGfloat data[4]);
+ VGRect(const FloatRect&);
+ const VGfloat* toVGfloat() const { return m_data; }
+ operator FloatRect() const;
+private:
+ VGfloat m_data[4];
+};
+
+class VGUtils {
+public:
+ static int bytesForImage(VGImageFormat, VGint width, VGint height);
+ static int bytesForImageScanline(VGImageFormat, VGint width);
+ static int imageFormatBitsPerPixel(VGImageFormat);
+
+ /**
+ * Return a flipped VGImageFormat if the platform is little endian
+ * (e.g. VG_ABGR_8888 for a given VG_RGBA_8888), or return the image format
+ * as is if the platform is big endian.
+ *
+ * OpenVG itself is indifferent to endianness, it will always work on a
+ * single machine word with the bytes going from left to right as specified
+ * in the image format, no matter which one of the bytes is most or least
+ * significant.
+ *
+ * However, if you interface with vgImageSubData()/vgGetImageSubData()
+ * using a byte array then you want to make sure the byte order is
+ * appropriate for the given platform (otherwise the byte indexes need
+ * to be swapped depending on endianness). So, use this function when
+ * interfacing with byte arrays, and don't use it otherwise.
+ */
+ static VGImageFormat endianAwareImageFormat(VGImageFormat bigEndianFormat);
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/pango/FontCachePango.cpp b/Source/WebCore/platform/graphics/pango/FontCachePango.cpp
new file mode 100644
index 0000000..fad29e0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/pango/FontCachePango.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "CString.h"
+#include "Font.h"
+#include "OwnPtrCairo.h"
+#include "SimpleFontData.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+ if (!FontPlatformData::init())
+ ASSERT_NOT_REACHED();
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ // FIXME: Would be even better to somehow get the user's default font here.
+ // For now we'll pick the default that the user would get without changing any prefs.
+ static AtomicString timesStr("Times New Roman");
+ return getCachedFontData(fontDescription, timesStr);
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ return new FontPlatformData(fontDescription, family);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp b/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp
new file mode 100644
index 0000000..a158689
--- /dev/null
+++ b/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode)
+{
+ return FontPlatformData(m_fontFace, size, bold, italic);
+}
+
+static void releaseData(void* data)
+{
+ static_cast<SharedBuffer*>(data)->deref();
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ // FIXME: we need support in pango to read fonts from memory to implement this.y
+ return 0;
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& /* format */)
+{
+ return false;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/pango/FontPlatformData.h b/Source/WebCore/platform/graphics/pango/FontPlatformData.h
new file mode 100644
index 0000000..2929a3f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/pango/FontPlatformData.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformDataPango_h
+#define FontPlatformDataPango_h
+
+#include "FontDescription.h"
+#include "FontOrientation.h"
+#include "GlyphBuffer.h"
+#include <cairo.h>
+#include <pango/pangocairo.h>
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class FontPlatformData {
+public:
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_context(0)
+ , m_font(hashTableDeletedFontValue())
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+ { }
+
+ FontPlatformData()
+ : m_context(0)
+ , m_font(0)
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+ { }
+
+ FontPlatformData(const FontDescription&, const AtomicString& family);
+ FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic);
+ FontPlatformData(float size, bool bold, bool italic);
+ FontPlatformData(const FontPlatformData&);
+ ~FontPlatformData();
+
+ static bool init();
+ bool isFixedPitch();
+ float size() const { return m_size; }
+ void setSize(float size) { m_size = size; }
+ bool syntheticBold() const { return m_syntheticBold; }
+ bool syntheticOblique() const { return m_syntheticOblique; }
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+ cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
+
+ unsigned hash() const
+ {
+ uintptr_t hashCodes[1] = { reinterpret_cast<uintptr_t>(m_scaledFont) };
+ return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+ }
+
+ bool operator==(const FontPlatformData&) const;
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool isHashTableDeletedValue() const
+ {
+ return m_font == hashTableDeletedFontValue();
+ }
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+ static PangoFontMap* m_fontMap;
+ static GHashTable* m_hashTable;
+ PangoContext* m_context;
+ PangoFont* m_font;
+ float m_size;
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+ cairo_scaled_font_t* m_scaledFont;
+private:
+ static PangoFont *hashTableDeletedFontValue() { return reinterpret_cast<PangoFont*>(-1); }
+};
+
+}
+
+#endif // FontPlatformDataPango_h
diff --git a/Source/WebCore/platform/graphics/pango/FontPlatformDataPango.cpp b/Source/WebCore/platform/graphics/pango/FontPlatformDataPango.cpp
new file mode 100644
index 0000000..03dc33d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/pango/FontPlatformDataPango.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2009 Igalia S.L.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include "FontDescription.h"
+#include <wtf/text/CString.h>
+#include <cairo.h>
+#include <assert.h>
+
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
+// Use cairo-ft i a recent enough Pango version isn't available
+#if !PANGO_VERSION_CHECK(1,18,0)
+#include <cairo-ft.h>
+#include <pango/pangofc-fontmap.h>
+#endif
+
+namespace WebCore {
+
+PangoFontMap* FontPlatformData::m_fontMap = 0;
+GHashTable* FontPlatformData::m_hashTable = 0;
+
+FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
+ : m_context(0)
+ , m_font(0)
+ , m_size(fontDescription.computedSize())
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+{
+ FontPlatformData::init();
+
+ CString stored_family = familyName.string().utf8();
+ char const* families[] = {
+ stored_family.data(),
+ NULL
+ };
+
+ switch (fontDescription.genericFamily()) {
+ case FontDescription::SerifFamily:
+ families[1] = "serif";
+ break;
+ case FontDescription::SansSerifFamily:
+ families[1] = "sans";
+ break;
+ case FontDescription::MonospaceFamily:
+ families[1] = "monospace";
+ break;
+ case FontDescription::NoFamily:
+ case FontDescription::StandardFamily:
+ default:
+ families[1] = "sans";
+ break;
+ }
+
+ PangoFontDescription* description = pango_font_description_new();
+ pango_font_description_set_absolute_size(description, fontDescription.computedSize() * PANGO_SCALE);
+
+ // FIXME: Map all FontWeight values to Pango font weights.
+ if (fontDescription.weight() >= FontWeight600)
+ pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD);
+ if (fontDescription.italic())
+ pango_font_description_set_style(description, PANGO_STYLE_ITALIC);
+
+#if PANGO_VERSION_CHECK(1,21,5) // deprecated in 1.21
+ m_context = pango_font_map_create_context(m_fontMap);
+#else
+ m_context = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(m_fontMap));
+#endif
+ for (unsigned int i = 0; !m_font && i < G_N_ELEMENTS(families); i++) {
+ pango_font_description_set_family(description, families[i]);
+ pango_context_set_font_description(m_context, description);
+ m_font = pango_font_map_load_font(m_fontMap, m_context, description);
+ }
+
+#if PANGO_VERSION_CHECK(1,18,0)
+ if (m_font)
+ m_scaledFont = cairo_scaled_font_reference(pango_cairo_font_get_scaled_font(PANGO_CAIRO_FONT(m_font)));
+#else
+ // This compatibility code for older versions of Pango is not well-tested.
+ if (m_font) {
+ PangoFcFont* fcfont = PANGO_FC_FONT(m_font);
+ cairo_font_face_t* face = cairo_ft_font_face_create_for_pattern(fcfont->font_pattern);
+ double size;
+ if (FcPatternGetDouble(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
+ size = 12.0;
+ cairo_matrix_t fontMatrix;
+ cairo_matrix_init_scale(&fontMatrix, size, size);
+ cairo_font_options_t* fontOptions;
+ if (pango_cairo_context_get_font_options(m_context))
+ fontOptions = cairo_font_options_copy(pango_cairo_context_get_font_options(m_context));
+ else
+ fontOptions = cairo_font_options_create();
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity(&ctm);
+ m_scaledFont = cairo_scaled_font_create(face, &fontMatrix, &ctm, fontOptions);
+ cairo_font_options_destroy(fontOptions);
+ cairo_font_face_destroy(face);
+ }
+#endif
+ pango_font_description_free(description);
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool italic)
+ : m_context(0)
+ , m_font(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
+ , m_scaledFont(0)
+{
+}
+
+FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic)
+ : m_context(0)
+ , m_font(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
+ , m_scaledFont(0)
+{
+ cairo_matrix_t fontMatrix;
+ cairo_matrix_init_scale(&fontMatrix, size, size);
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity(&ctm);
+ cairo_font_options_t* options = cairo_font_options_create();
+
+ // We force antialiasing and disable hinting to provide consistent
+ // typographic qualities for custom fonts on all platforms.
+ cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
+
+ m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
+ cairo_font_options_destroy(options);
+}
+
+bool FontPlatformData::init()
+{
+ static bool initialized = false;
+ if (initialized)
+ return true;
+ initialized = true;
+
+ if (!m_fontMap)
+ m_fontMap = pango_cairo_font_map_get_default();
+ if (!m_hashTable) {
+ PangoFontFamily** families = 0;
+ int n_families = 0;
+
+ m_hashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ pango_font_map_list_families(m_fontMap, &families, &n_families);
+
+ for (int family = 0; family < n_families; family++)
+ g_hash_table_insert(m_hashTable,
+ g_strdup(pango_font_family_get_name(families[family])),
+ g_object_ref(families[family]));
+
+ g_free(families);
+ }
+
+ return true;
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ if (m_font && m_font != reinterpret_cast<PangoFont*>(-1)) {
+ g_object_unref(m_font);
+ m_font = 0;
+ }
+
+ if (m_context) {
+ g_object_unref(m_context);
+ m_context = 0;
+ }
+
+ if (m_scaledFont) {
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = 0;
+ }
+}
+
+bool FontPlatformData::isFixedPitch()
+{
+ PangoFontDescription* description = pango_font_describe_with_absolute_size(m_font);
+ PangoFontFamily* family = reinterpret_cast<PangoFontFamily*>(g_hash_table_lookup(m_hashTable, pango_font_description_get_family(description)));
+ pango_font_description_free(description);
+ return pango_font_family_is_monospace(family);
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ // Check for self-assignment.
+ if (this == &other)
+ return *this;
+
+ m_size = other.m_size;
+ m_syntheticBold = other.m_syntheticBold;
+ m_syntheticOblique = other.m_syntheticOblique;
+
+ if (other.m_scaledFont)
+ cairo_scaled_font_reference(other.m_scaledFont);
+ if (m_scaledFont)
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = other.m_scaledFont;
+
+ if (other.m_font)
+ g_object_ref(other.m_font);
+ if (m_font)
+ g_object_unref(m_font);
+ m_font = other.m_font;
+
+ if (other.m_context)
+ g_object_ref(other.m_context);
+ if (m_context)
+ g_object_unref(m_context);
+ m_context = other.m_context;
+
+ return *this;
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& other)
+ : m_context(0)
+ , m_font(0)
+ , m_scaledFont(0)
+{
+ *this = other;
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& other) const
+{
+ if (m_font == other.m_font)
+ return true;
+ if (m_font == 0 || m_font == reinterpret_cast<PangoFont*>(-1)
+ || other.m_font == 0 || other.m_font == reinterpret_cast<PangoFont*>(-1))
+ return false;
+ PangoFontDescription* thisDesc = pango_font_describe(m_font);
+ PangoFontDescription* otherDesc = pango_font_describe(other.m_font);
+ bool result = pango_font_description_equal(thisDesc, otherDesc);
+ pango_font_description_free(otherDesc);
+ pango_font_description_free(thisDesc);
+ return result;
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/pango/GlyphPageTreeNodePango.cpp b/Source/WebCore/platform/graphics/pango/GlyphPageTreeNodePango.cpp
new file mode 100644
index 0000000..8d0baa6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/pango/GlyphPageTreeNodePango.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+#include <pango/pango-font.h>
+
+namespace WebCore {
+
+static PangoGlyph pango_font_get_glyph(PangoFont* font, PangoContext* context, gunichar wc)
+{
+ PangoGlyph result = 0;
+ gchar buffer[7];
+
+ gint length = g_unichar_to_utf8(wc, buffer);
+ g_return_val_if_fail(length, 0);
+
+ GList* items = pango_itemize(context, buffer, 0, length, NULL, NULL);
+
+ if (g_list_length(items) == 1) {
+ PangoItem* item = reinterpret_cast<PangoItem*>(items->data);
+ PangoFont* tmpFont = item->analysis.font;
+ item->analysis.font = font;
+
+ PangoGlyphString* glyphs = pango_glyph_string_new();
+ pango_shape(buffer, length, &item->analysis, glyphs);
+
+ item->analysis.font = tmpFont;
+
+ if (glyphs->num_glyphs == 1)
+ result = glyphs->glyphs[0].glyph;
+ else
+ g_warning("didn't get 1 glyph but %d", glyphs->num_glyphs);
+
+ pango_glyph_string_free(glyphs);
+ }
+
+ g_list_foreach(items, (GFunc)pango_item_free, NULL);
+ g_list_free(items);
+
+ return result;
+}
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters.
+ // We won't support this for now.
+ if (bufferLength > GlyphPage::size)
+ return false;
+
+ if (!fontData->platformData().m_font || fontData->platformData().m_font == reinterpret_cast<PangoFont*>(-1))
+ return false;
+
+ bool haveGlyphs = false;
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = pango_font_get_glyph(fontData->platformData().m_font, fontData->platformData().m_context, buffer[i]);
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+
+ return haveGlyphs;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp b/Source/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp
new file mode 100644
index 0000000..d0bf836
--- /dev/null
+++ b/Source/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Pioneer Research Center USA, 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "FloatRect.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "FontDescription.h"
+#include "GlyphBuffer.h"
+#include <cairo.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ cairo_font_extents_t font_extents;
+ cairo_text_extents_t text_extents;
+ cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents);
+ m_ascent = static_cast<int>(lroundf(font_extents.ascent));
+ m_descent = static_cast<int>(lroundf(font_extents.descent));
+ m_lineSpacing = static_cast<int>(lroundf(font_extents.height));
+ // There seems to be some rounding error in cairo (or in how we
+ // use cairo) with some fonts, like DejaVu Sans Mono, which makes
+ // cairo report a height smaller than ascent + descent, which is
+ // wrong and confuses WebCore's layout system. Workaround this
+ // while we figure out what's going on.
+ if (m_lineSpacing < m_ascent + m_descent)
+ m_lineSpacing = m_ascent + m_descent;
+ cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents);
+ m_xHeight = text_extents.height;
+ cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents);
+ m_spaceWidth = static_cast<float>(text_extents.x_advance);
+ m_lineGap = m_lineSpacing - m_ascent - m_descent;
+ m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f;
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ m_avgCharWidth = 0.f;
+ m_maxCharWidth = 0.f;
+ initCharWidths();
+}
+
+void SimpleFontData::platformDestroy()
+{
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ FontDescription desc = FontDescription(fontDescription);
+ desc.setSpecifiedSize(scaleFactor * fontDescription.computedSize());
+ FontPlatformData platformData(desc, desc.family().family());
+ return new SimpleFontData(platformData);
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ bool result = true;
+
+ PangoCoverage* coverage = pango_font_get_coverage(m_platformData.m_font, pango_language_get_default());
+
+ for (int i = 0; i < length; i++) {
+ if (PANGO_COVERAGE_NONE == pango_coverage_get(coverage, characters[i])) {
+ result = false;
+ break;
+ }
+ }
+
+ pango_coverage_unref(coverage);
+
+ return result;
+}
+
+void SimpleFontData::determinePitch()
+{
+ if (isCustomFont()) {
+ m_treatAsFixedPitch = false;
+ return;
+ }
+
+ m_treatAsFixedPitch = m_platformData.isFixedPitch();
+}
+
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const
+{
+ return FloatRect();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ ASSERT(m_platformData.m_scaledFont);
+
+ cairo_glyph_t cglyph = { glyph, 0, 0 };
+ cairo_text_extents_t extents;
+ cairo_scaled_font_glyph_extents(m_platformData.m_scaledFont, &cglyph, 1, &extents);
+
+ float width = (float)m_spaceWidth;
+ if (cairo_scaled_font_status(m_platformData.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0)
+ width = (float)extents.x_advance;
+
+ return width;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/ColorQt.cpp b/Source/WebCore/platform/graphics/qt/ColorQt.cpp
new file mode 100644
index 0000000..151766a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ColorQt.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#include <QColor>
+
+namespace WebCore {
+
+Color::Color(const QColor& c)
+ : m_color(makeRGBA(c.red(), c.green(), c.blue(), c.alpha()))
+{
+ m_valid = c.isValid();
+}
+
+Color::operator QColor() const
+{
+ if (m_valid)
+ return QColor(red(), green(), blue(), alpha());
+ else
+ return QColor();
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp b/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp
new file mode 100644
index 0000000..834ca62
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2010 Sencha, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ContextShadow.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+#include <QPainter>
+#include <QTimerEvent>
+
+namespace WebCore {
+
+// ContextShadow needs a scratch image as the buffer for the blur filter.
+// Instead of creating and destroying the buffer for every operation,
+// we create a buffer which will be automatically purged via a timer.
+
+class ShadowBuffer: public QObject {
+public:
+ ShadowBuffer(QObject* parent = 0);
+
+ QImage* scratchImage(const QSize& size);
+
+ void schedulePurge();
+
+protected:
+ void timerEvent(QTimerEvent* event);
+
+private:
+ QImage image;
+ int timerId;
+};
+
+ShadowBuffer::ShadowBuffer(QObject* parent)
+ : QObject(parent)
+ , timerId(0)
+{
+}
+
+QImage* ShadowBuffer::scratchImage(const QSize& size)
+{
+ int width = size.width();
+ int height = size.height();
+
+ // We do not need to recreate the buffer if the buffer is reasonably
+ // larger than the requested size. However, if the requested size is
+ // much smaller than our buffer, reduce our buffer so that we will not
+ // keep too many allocated pixels for too long.
+ if (!image.isNull() && (image.width() > width) && (image.height() > height))
+ if (((2 * width) > image.width()) && ((2 * height) > image.height())) {
+ image.fill(Qt::transparent);
+ return &image;
+ }
+
+ // Round to the nearest 32 pixels so we do not grow the buffer everytime
+ // there is larger request by 1 pixel.
+ width = (1 + (width >> 5)) << 5;
+ height = (1 + (height >> 5)) << 5;
+
+ image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
+ image.fill(Qt::transparent);
+ return &image;
+}
+
+void ShadowBuffer::schedulePurge()
+{
+ static const double BufferPurgeDelay = 2; // seconds
+ killTimer(timerId);
+ timerId = startTimer(BufferPurgeDelay * 1000);
+}
+
+void ShadowBuffer::timerEvent(QTimerEvent* event)
+{
+ if (event->timerId() == timerId) {
+ killTimer(timerId);
+ image = QImage();
+ }
+ QObject::timerEvent(event);
+}
+
+Q_GLOBAL_STATIC(ShadowBuffer, scratchShadowBuffer)
+
+PlatformContext ContextShadow::beginShadowLayer(GraphicsContext* context, const FloatRect& layerArea)
+{
+ // Set m_blurDistance.
+ adjustBlurDistance(context);
+
+ PlatformContext p = context->platformContext();
+
+ QRect clipRect;
+ if (p->hasClipping())
+#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
+ clipRect = p->clipBoundingRect().toAlignedRect();
+#else
+ clipRect = p->clipRegion().boundingRect();
+#endif
+ else
+ clipRect = p->transform().inverted().mapRect(p->window());
+
+ // Set m_layerOrigin, m_layerContextTranslation, m_sourceRect.
+ IntRect clip(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
+ IntRect layerRect = calculateLayerBoundingRect(context, layerArea, clip);
+
+ // Don't paint if we are totally outside the clip region.
+ if (layerRect.isEmpty())
+ return 0;
+
+ ShadowBuffer* shadowBuffer = scratchShadowBuffer();
+ QImage* shadowImage = shadowBuffer->scratchImage(layerRect.size());
+ m_layerImage = QImage(*shadowImage);
+
+ m_layerContext = new QPainter;
+ m_layerContext->begin(&m_layerImage);
+ m_layerContext->setFont(p->font());
+ m_layerContext->translate(m_layerContextTranslation);
+ return m_layerContext;
+}
+
+void ContextShadow::endShadowLayer(GraphicsContext* context)
+{
+ m_layerContext->end();
+ delete m_layerContext;
+ m_layerContext = 0;
+
+ if (m_type == BlurShadow) {
+ blurLayerImage(m_layerImage.bits(), IntSize(m_layerImage.width(), m_layerImage.height()),
+ m_layerImage.bytesPerLine());
+ }
+
+ if (m_type != NoShadow) {
+ // "Colorize" with the right shadow color.
+ QPainter p(&m_layerImage);
+ p.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ p.fillRect(m_layerImage.rect(), m_color.rgb());
+ p.end();
+ }
+
+ context->platformContext()->drawImage(m_layerOrigin, m_layerImage, m_sourceRect);
+
+ scratchShadowBuffer()->schedulePurge();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp
new file mode 100644
index 0000000..cd28f0e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "Extensions3DQt.h"
+
+#include "GraphicsContext3D.h"
+
+namespace WebCore {
+
+Extensions3DQt::Extensions3DQt()
+{
+}
+
+Extensions3DQt::~Extensions3DQt()
+{
+}
+
+bool Extensions3DQt::supports(const String&)
+{
+ return false;
+}
+
+void Extensions3DQt::ensureEnabled(const String& name)
+{
+ ASSERT(supports(name));
+}
+
+int Extensions3DQt::getGraphicsResetStatusARB()
+{
+ return GraphicsContext3D::NO_ERROR;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.h b/Source/WebCore/platform/graphics/qt/Extensions3DQt.h
new file mode 100644
index 0000000..ae4b375
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 Extensions3DQt_h
+#define Extensions3DQt_h
+
+#include "Extensions3D.h"
+
+namespace WebCore {
+
+class Extensions3DQt : public Extensions3D {
+public:
+ virtual ~Extensions3DQt();
+
+ // Extensions3D methods.
+ virtual bool supports(const String&);
+ virtual void ensureEnabled(const String&);
+ virtual int getGraphicsResetStatusARB();
+
+private:
+ // This class only needs to be instantiated by GraphicsContext3D implementations.
+ friend class GraphicsContext3D;
+ Extensions3DQt();
+};
+
+} // namespace WebCore
+
+#endif // Extensions3DQt_h
diff --git a/Source/WebCore/platform/graphics/qt/FloatPointQt.cpp b/Source/WebCore/platform/graphics/qt/FloatPointQt.cpp
new file mode 100644
index 0000000..82093d8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FloatPointQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatPoint.h"
+
+#include <QPointF>
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const QPointF& p)
+ : m_x(p.x())
+ , m_y(p.y())
+{
+}
+
+FloatPoint::operator QPointF() const
+{
+ return QPointF(m_x, m_y);
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/FloatRectQt.cpp b/Source/WebCore/platform/graphics/qt/FloatRectQt.cpp
new file mode 100644
index 0000000..063876b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FloatRectQt.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#include <QRectF>
+
+namespace WebCore {
+
+FloatRect::FloatRect(const QRectF& r)
+ : m_location(r.topLeft())
+ , m_size(r.width()
+ , r.height())
+{
+}
+
+FloatRect::operator QRectF() const
+{
+ return QRectF(x(), y(), width(), height());
+}
+
+FloatRect FloatRect::normalized() const
+{
+ FloatRect normalizedRect = *this;
+
+ if (width() < 0) {
+ normalizedRect.setX(x() + width());
+ normalizedRect.setWidth(-width());
+ }
+ if (height() < 0) {
+ normalizedRect.setY(y() + height());
+ normalizedRect.setHeight(-height());
+ }
+ return normalizedRect;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/FontCacheQt.cpp b/Source/WebCore/platform/graphics/qt/FontCacheQt.cpp
new file mode 100644
index 0000000..c59c523
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontCacheQt.cpp
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#include "config.h"
+#include "FontCache.h"
+
+#include "FontDescription.h"
+#include "FontPlatformData.h"
+#include "Font.h"
+#include "PlatformString.h"
+#include <utility>
+#include <wtf/ListHashSet.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.h>
+
+#include <QFont>
+
+using namespace WTF;
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font&, const UChar*, int)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ const AtomicString fallbackFamily = QFont(fontDescription.family().family()).lastResortFamily();
+ return getCachedFontData(new FontPlatformData(fontDescription, fallbackFamily));
+}
+
+void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&)
+{
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
+{
+ return new FontPlatformData(fontDescription, familyName);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h
new file mode 100644
index 0000000..6c41d47
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ ~FontCustomPlatformData();
+
+ // for use with QFontDatabase::addApplicationFont/removeApplicationFont
+ int m_handle;
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+
+ static bool supportsFormat(const String&);
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+} // namespace WebCore
+
+#endif // FontCustomPlatformData_h
diff --git a/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp
new file mode 100644
index 0000000..e2f009b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "FontPlatformData.h"
+#include "SharedBuffer.h"
+#include <QFontDatabase>
+#include <QStringList>
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ QFontDatabase::removeApplicationFont(m_handle);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode)
+{
+ QFont font;
+ font.setFamily(QFontDatabase::applicationFontFamilies(m_handle)[0]);
+ font.setPixelSize(size);
+ if (bold)
+ font.setWeight(QFont::Bold);
+ font.setItalic(italic);
+
+ return FontPlatformData(font);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+ int id = QFontDatabase::addApplicationFontFromData(QByteArray(buffer->data(), buffer->size()));
+ if (id == -1)
+ return 0;
+
+ Q_ASSERT(QFontDatabase::applicationFontFamilies(id).size() > 0);
+
+ FontCustomPlatformData *data = new FontCustomPlatformData;
+ data->m_handle = id;
+ return data;
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype");
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/FontPlatformData.h b/Source/WebCore/platform/graphics/qt/FontPlatformData.h
new file mode 100644
index 0000000..1c57e29
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontPlatformData.h
@@ -0,0 +1,175 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+#include <wtf/Forward.h>
+#include "FontDescription.h"
+#include "FontOrientation.h"
+#include <QFont>
+#include <QHash>
+
+namespace WebCore {
+
+class FontPlatformDataPrivate : public Noncopyable {
+public:
+ FontPlatformDataPrivate()
+ : refCount(1)
+ , size(font.pixelSize())
+ , bold(font.bold())
+ , oblique(false)
+ {}
+ FontPlatformDataPrivate(const float size, const bool bold, const bool oblique)
+ : refCount(1)
+ , size(size)
+ , bold(bold)
+ , oblique(oblique)
+ {}
+ FontPlatformDataPrivate(const QFont& font)
+ : refCount(1)
+ , font(font)
+ , size(font.pixelSize())
+ , bold(font.bold())
+ , oblique(false)
+ {}
+ unsigned refCount;
+ QFont font;
+ float size;
+ bool bold : 1;
+ bool oblique : 1;
+};
+
+
+
+class FontPlatformData : public FastAllocBase {
+public:
+ FontPlatformData(float size, bool bold, bool oblique);
+ FontPlatformData(const FontPlatformData &);
+ FontPlatformData(const FontDescription&, const AtomicString& familyName, int wordSpacing = 0, int letterSpacing = 0);
+ FontPlatformData(const QFont& font)
+ : m_data(new FontPlatformDataPrivate(font))
+ {}
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_data(reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ {}
+
+ ~FontPlatformData();
+
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool operator==(const FontPlatformData&) const;
+
+ bool isHashTableDeletedValue() const
+ {
+ return m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1);
+ }
+
+ static inline QFont::Weight toQFontWeight(FontWeight fontWeight)
+ {
+ switch (fontWeight) {
+ case FontWeight100:
+ case FontWeight200:
+ return QFont::Light; // QFont::Light == Weight of 25
+ case FontWeight600:
+ return QFont::DemiBold; // QFont::DemiBold == Weight of 63
+ case FontWeight700:
+ case FontWeight800:
+ return QFont::Bold; // QFont::Bold == Weight of 75
+ case FontWeight900:
+ return QFont::Black; // QFont::Black == Weight of 87
+ case FontWeight300:
+ case FontWeight400:
+ case FontWeight500:
+ default:
+ return QFont::Normal; // QFont::Normal == Weight of 50
+ }
+ }
+
+ QFont font() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->font;
+ return QFont();
+ }
+ float size() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->size;
+ return 0.0f;
+ }
+ QString family() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->font.family();
+ return QString();
+ }
+ bool bold() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->bold;
+ return false;
+ }
+ bool italic() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->font.italic();
+ return false;
+ }
+ bool smallCaps() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->font.capitalization() == QFont::SmallCaps;
+ return false;
+ }
+ int pixelSize() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data) {
+ // WebKit allows font size zero but QFont does not.
+ if (!m_data->size)
+ return m_data->size;
+ return m_data->font.pixelSize();
+ }
+ return 0;
+ }
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+ unsigned hash() const;
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+private:
+ FontPlatformDataPrivate* m_data;
+};
+
+} // namespace WebCore
+
+#endif // FontPlatformData_h
diff --git a/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
new file mode 100644
index 0000000..4c9eb32
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
@@ -0,0 +1,132 @@
+/*
+ Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+static inline bool isEmptyValue(const float size, const bool bold, const bool oblique)
+{
+ // this is the empty value by definition of the trait FontDataCacheKeyTraits
+ return !bold && !oblique && size == 0.f;
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+{
+ if (isEmptyValue(size, bold, oblique))
+ m_data = 0;
+ else
+ m_data = new FontPlatformDataPrivate(size, bold, oblique);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData &other) : m_data(other.m_data)
+{
+ if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ ++m_data->refCount;
+}
+
+FontPlatformData::FontPlatformData(const FontDescription& description, const AtomicString& familyName, int wordSpacing, int letterSpacing)
+ : m_data(new FontPlatformDataPrivate())
+{
+ QFont& font = m_data->font;
+ int requestedSize = qRound(description.computedPixelSize());
+ font.setFamily(familyName);
+ font.setPixelSize(qRound(requestedSize));
+ font.setItalic(description.italic());
+ font.setWeight(toQFontWeight(description.weight()));
+ font.setWordSpacing(wordSpacing);
+ font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing);
+ const bool smallCaps = description.smallCaps();
+ font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase);
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ font.setStyleStrategy(QFont::ForceIntegerMetrics);
+#endif
+
+ m_data->bold = font.bold();
+ // WebKit allows font size zero but QFont does not. We will return
+ // m_data->size if a font size of zero is requested and pixelSize()
+ // otherwise.
+ m_data->size = (!requestedSize) ? requestedSize : font.pixelSize();
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ if (!m_data || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ return;
+ --m_data->refCount;
+ if (!m_data->refCount)
+ delete m_data;
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ if (m_data == other.m_data)
+ return *this;
+ if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) {
+ --m_data->refCount;
+ if (!m_data->refCount)
+ delete m_data;
+ }
+ m_data = other.m_data;
+ if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ ++m_data->refCount;
+ return *this;
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& other) const
+{
+ if (m_data == other.m_data)
+ return true;
+
+ if (!m_data || !other.m_data
+ || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1) || other.m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ return false;
+
+ const bool equals = (m_data->size == other.m_data->size
+ && m_data->bold == other.m_data->bold
+ && m_data->oblique == other.m_data->oblique
+ && m_data->font == other.m_data->font);
+ return equals;
+}
+
+unsigned FontPlatformData::hash() const
+{
+ if (!m_data)
+ return 0;
+ if (m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ return 1;
+ return qHash(m_data->font.toString())
+ ^ qHash(*reinterpret_cast<quint32*>(&m_data->size))
+ ^ qHash(m_data->bold)
+ ^ qHash(m_data->oblique);
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/FontQt.cpp b/Source/WebCore/platform/graphics/qt/FontQt.cpp
new file mode 100644
index 0000000..f1ced2b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontQt.cpp
@@ -0,0 +1,432 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008, 2010 Holger Hans Peter Freyther
+ Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "Font.h"
+
+#include "AffineTransform.h"
+#include "ContextShadow.h"
+#include "FontDescription.h"
+#include "FontFallbackList.h"
+#include "FontSelector.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "Pattern.h"
+
+#include <QBrush>
+#include <QFontInfo>
+#include <QFontMetrics>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPen>
+#include <QTextLayout>
+#include <qalgorithms.h>
+#include <qdebug.h>
+
+#include <limits.h>
+
+namespace WebCore {
+
+static const QString fromRawDataWithoutRef(const String& string, int start = 0, int len = -1)
+{
+ if (len < 0)
+ len = string.length() - start;
+ Q_ASSERT(start + len <= string.length());
+
+ // We don't detach. This assumes the WebCore string data will stay valid for the
+ // lifetime of the QString we pass back, since we don't ref the WebCore string.
+ return QString::fromRawData(reinterpret_cast<const QChar*>(string.characters() + start), len);
+}
+
+static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
+{
+ int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
+ if (style.padding())
+ flags |= Qt::TextJustificationForced;
+ layout->setFlags(flags);
+ layout->beginLayout();
+ QTextLine line = layout->createLine();
+ line.setLineWidth(INT_MAX/256);
+ if (style.padding())
+ line.setLineWidth(line.naturalTextWidth() + style.padding());
+ layout->endLayout();
+ return line;
+}
+
+static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to, const QFont& font, bool isComplexText)
+{
+ if (to < 0)
+ to = run.length();
+
+ QPainter *p = ctx->platformContext();
+
+ QPen textFillPen;
+ if (ctx->textDrawingMode() & TextModeFill) {
+ if (ctx->fillGradient()) {
+ QBrush brush(*ctx->fillGradient()->platformGradient());
+ brush.setTransform(ctx->fillGradient()->gradientSpaceTransform());
+ textFillPen = QPen(brush, 0);
+ } else if (ctx->fillPattern()) {
+ AffineTransform affine;
+ textFillPen = QPen(QBrush(ctx->fillPattern()->createPlatformPattern(affine)), 0);
+ } else
+ textFillPen = QPen(QColor(ctx->fillColor()));
+ }
+
+ QPen textStrokePen;
+ if (ctx->textDrawingMode() & TextModeStroke) {
+ if (ctx->strokeGradient()) {
+ QBrush brush(*ctx->strokeGradient()->platformGradient());
+ brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform());
+ textStrokePen = QPen(brush, ctx->strokeThickness());
+ } else if (ctx->strokePattern()) {
+ AffineTransform affine;
+ QBrush brush(ctx->strokePattern()->createPlatformPattern(affine));
+ textStrokePen = QPen(brush, ctx->strokeThickness());
+ } else
+ textStrokePen = QPen(QColor(ctx->strokeColor()), ctx->strokeThickness());
+ }
+
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+ QPointF pt(point.x(), point.y());
+
+ if (from > 0 || to < run.length()) {
+ if (isComplexText) {
+ QTextLayout layout(string, font);
+ QTextLine line = setupLayout(&layout, run);
+ float x1 = line.cursorToX(from);
+ float x2 = line.cursorToX(to);
+ if (x2 < x1)
+ qSwap(x1, x2);
+
+ QFontMetrics fm(font);
+ int ascent = fm.ascent();
+ QRectF boundingRect(point.x() + x1, point.y() - ascent, x2 - x1, fm.height());
+ QRectF clip = boundingRect;
+
+ ContextShadow* ctxShadow = ctx->contextShadow();
+
+ if (ctxShadow->m_type != ContextShadow::NoShadow) {
+ qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0;
+ if (ctxShadow->offset().x() > 0)
+ dx2 = ctxShadow->offset().x();
+ else
+ dx1 = -ctxShadow->offset().x();
+ if (ctxShadow->offset().y() > 0)
+ dy2 = ctxShadow->offset().y();
+ else
+ dy1 = -ctxShadow->offset().y();
+ // expand the clip rect to include the text shadow as well
+ clip.adjust(dx1, dx2, dy1, dy2);
+ clip.adjust(-ctxShadow->m_blurDistance, -ctxShadow->m_blurDistance, ctxShadow->m_blurDistance, ctxShadow->m_blurDistance);
+ }
+ p->save();
+ p->setClipRect(clip.toRect(), Qt::IntersectClip);
+ pt.setY(pt.y() - ascent);
+
+ if (ctxShadow->m_type != ContextShadow::NoShadow) {
+ ContextShadow* ctxShadow = ctx->contextShadow();
+ if (!ctxShadow->mustUseContextShadow(ctx)) {
+ p->save();
+ p->setPen(ctxShadow->m_color);
+ p->translate(ctxShadow->offset());
+ line.draw(p, pt);
+ p->restore();
+ } else {
+ QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect);
+ if (shadowPainter) {
+ // Since it will be blurred anyway, we don't care about render hints.
+ shadowPainter->setFont(p->font());
+ shadowPainter->setPen(ctxShadow->m_color);
+ line.draw(shadowPainter, pt);
+ ctxShadow->endShadowLayer(ctx);
+ }
+ }
+ }
+ p->setPen(textFillPen);
+ line.draw(p, pt);
+ p->restore();
+ return;
+ }
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ int skipWidth = QFontMetrics(font).width(string, from, Qt::TextBypassShaping);
+ pt.setX(pt.x() + skipWidth);
+ string = fromRawDataWithoutRef(sanitized, from, to - from);
+#endif
+ }
+
+ p->setFont(font);
+
+ int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ // See QWebPagePrivate::QWebPagePrivate() where the default path is set to Complex for Qt 4.6 and earlier.
+ if (!isComplexText && !(ctx->textDrawingMode() & TextModeStroke))
+ flags |= Qt::TextBypassShaping;
+#endif
+
+ QPainterPath textStrokePath;
+ if (ctx->textDrawingMode() & TextModeStroke)
+ textStrokePath.addText(pt, font, string);
+
+ ContextShadow* ctxShadow = ctx->contextShadow();
+ if (ctxShadow->m_type != ContextShadow::NoShadow) {
+ if (ctx->textDrawingMode() & TextModeFill) {
+ if (ctxShadow->m_type != ContextShadow::BlurShadow) {
+ p->save();
+ p->setPen(ctxShadow->m_color);
+ p->translate(ctxShadow->offset());
+ p->drawText(pt, string, flags, run.padding());
+ p->restore();
+ } else {
+ QFontMetrics fm(font);
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height());
+#else
+ QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string), fm.height());
+#endif
+ QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect);
+ if (shadowPainter) {
+ // Since it will be blurred anyway, we don't care about render hints.
+ shadowPainter->setFont(p->font());
+ shadowPainter->setPen(ctxShadow->m_color);
+ shadowPainter->drawText(pt, string, flags, run.padding());
+ ctxShadow->endShadowLayer(ctx);
+ }
+ }
+ } else if (ctx->textDrawingMode() & TextModeStroke) {
+ if (ctxShadow->m_type != ContextShadow::BlurShadow) {
+ p->translate(ctxShadow->offset());
+ p->strokePath(textStrokePath, QPen(ctxShadow->m_color));
+ p->translate(-ctxShadow->offset());
+ } else {
+ QFontMetrics fm(font);
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height());
+#else
+ QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string), fm.height());
+#endif
+ QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect);
+ if (shadowPainter) {
+ // Since it will be blurred anyway, we don't care about render hints.
+ shadowPainter->setFont(p->font());
+ shadowPainter->strokePath(textStrokePath, QPen(ctxShadow->m_color));
+ ctxShadow->endShadowLayer(ctx);
+ }
+ }
+ }
+ }
+
+ if (ctx->textDrawingMode() & TextModeStroke)
+ p->strokePath(textStrokePath, textStrokePen);
+
+ if (ctx->textDrawingMode() & TextModeFill) {
+ QPen previousPen = p->pen();
+ p->setPen(textFillPen);
+ p->drawText(pt, string, flags, run.padding());
+ p->setPen(previousPen);
+ }
+}
+
+void Font::drawSimpleText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ drawTextCommon(ctx, run, point, from, to, font(), /* isComplexText = */false);
+#else
+ Q_ASSERT(false);
+#endif
+}
+
+void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+ drawTextCommon(ctx, run, point, from, to, font(), /* isComplexText = */true);
+}
+
+int Font::emphasisMarkAscent(const AtomicString&) const
+{
+ notImplemented();
+ return 0;
+}
+
+int Font::emphasisMarkDescent(const AtomicString&) const
+{
+ notImplemented();
+ return 0;
+}
+
+int Font::emphasisMarkHeight(const AtomicString&) const
+{
+ notImplemented();
+ return 0;
+}
+
+void Font::drawEmphasisMarksForSimpleText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+ if (!primaryFont()->platformData().size())
+ return 0;
+
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ if (!run.length())
+ return 0;
+
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ int w = QFontMetrics(font()).width(string, -1, Qt::TextBypassShaping);
+
+ // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does)
+ if (treatAsSpace(run[0]))
+ w -= m_wordSpacing;
+
+ return w + run.padding();
+#else
+ Q_ASSERT(false);
+ return 0;
+#endif
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const
+{
+ if (!primaryFont()->platformData().size())
+ return 0;
+
+ if (!run.length())
+ return 0;
+
+ if (run.length() == 1 && treatAsSpace(run[0]))
+ return QFontMetrics(font()).width(space) + run.padding();
+
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ int w = QFontMetrics(font()).width(string);
+ // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does)
+ if (treatAsSpace(run[0]))
+ w -= m_wordSpacing;
+
+ return w + run.padding();
+}
+
+int Font::offsetForPositionForSimpleText(const TextRun& run, float position, bool includePartialGlyphs) const
+{
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ QFontMetrics fm(font());
+ float delta = position;
+ int curPos = 0;
+ do {
+ float charWidth = fm.width(string[curPos]);
+ delta -= charWidth;
+ if (includePartialGlyphs) {
+ if (delta + charWidth / 2 <= 0)
+ break;
+ } else {
+ if (delta + charWidth <= 0)
+ break;
+ }
+ } while (++curPos < string.size());
+
+ return curPos;
+#else
+ Q_ASSERT(false);
+ return 0;
+#endif
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float position, bool) const
+{
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ QTextLayout layout(string, font());
+ QTextLine line = setupLayout(&layout, run);
+ return line.xToCursor(position);
+}
+
+FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& pt, int h, int from, int to) const
+{
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString wholeText = fromRawDataWithoutRef(sanitized);
+ QString selectedText = fromRawDataWithoutRef(sanitized, from, qMin(to - from, wholeText.length() - from));
+
+ int startX = QFontMetrics(font()).width(wholeText, from, Qt::TextBypassShaping);
+ int width = QFontMetrics(font()).width(selectedText, -1, Qt::TextBypassShaping);
+
+ return FloatRect(pt.x() + startX, pt.y(), width, h);
+#else
+ Q_ASSERT(false);
+ return FloatRect();
+#endif
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt, int h, int from, int to) const
+{
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ QTextLayout layout(string, font());
+ QTextLine line = setupLayout(&layout, run);
+
+ float x1 = line.cursorToX(from);
+ float x2 = line.cursorToX(to);
+ if (x2 < x1)
+ qSwap(x1, x2);
+
+ return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
+}
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+bool Font::primaryFontHasGlyphForCharacter(UChar32) const
+{
+ notImplemented();
+ return true;
+}
+
+QFont Font::font() const
+{
+ QFont f = primaryFont()->getQtFont();
+ if (m_letterSpacing != 0)
+ f.setLetterSpacing(QFont::AbsoluteSpacing, m_letterSpacing);
+ if (m_wordSpacing != 0)
+ f.setWordSpacing(m_wordSpacing);
+ return f;
+}
+
+}
+
diff --git a/Source/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp b/Source/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
new file mode 100644
index 0000000..2121206
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+namespace WebCore {
+
+void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData*)
+{
+}
+
+void GlyphPageTreeNode::pruneTreeFontData(const WebCore::SimpleFontData*)
+{
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/GradientQt.cpp b/Source/WebCore/platform/graphics/qt/GradientQt.cpp
new file mode 100644
index 0000000..72bb009
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GradientQt.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+
+#include <QGradient>
+#include <QPainter>
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ delete m_gradient;
+ m_gradient = 0;
+}
+
+QGradient* Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ bool reversed = m_r0 > m_r1;
+
+ qreal innerRadius = reversed ? m_r1 : m_r0;
+ qreal outerRadius = reversed ? m_r0 : m_r1;
+ QPointF center = reversed ? m_p0 : m_p1;
+ QPointF focalPoint = reversed ? m_p1 : m_p0;
+
+ if (m_radial)
+ m_gradient = new QRadialGradient(center, outerRadius, focalPoint);
+ else
+ m_gradient = new QLinearGradient(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y());
+
+ m_gradient->setInterpolationMode(QGradient::ComponentInterpolation);
+
+ sortStopsIfNecessary();
+
+ QColor stopColor;
+ Vector<ColorStop>::iterator stopIterator = m_stops.begin();
+ qreal lastStop(0.0);
+ const qreal lastStopDiff = 0.0000001;
+ while (stopIterator != m_stops.end()) {
+ stopColor.setRgbF(stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha);
+ if (qFuzzyCompare(lastStop, qreal(stopIterator->stop)))
+ lastStop = stopIterator->stop + lastStopDiff;
+ else
+ lastStop = stopIterator->stop;
+
+ if (m_radial && !qFuzzyCompare(1 + outerRadius, qreal(1))) {
+ lastStop = lastStop * (1.0f - innerRadius / outerRadius);
+ if (!reversed)
+ lastStop += innerRadius / outerRadius;
+ }
+
+ qreal stopPosition = qMin(lastStop, qreal(1.0f));
+
+ if (m_radial && reversed)
+ stopPosition = 1 - stopPosition;
+
+ m_gradient->setColorAt(stopPosition, stopColor);
+ // Keep the lastStop as orginal value, since the following stopColor depend it
+ lastStop = stopIterator->stop;
+ ++stopIterator;
+ }
+
+ if (m_stops.isEmpty()) {
+ // The behavior of QGradient with no stops is defined differently from HTML5 spec,
+ // where the latter requires the gradient to be transparent black.
+ m_gradient->setColorAt(0.0, QColor(0, 0, 0, 0));
+ }
+
+ switch (m_spreadMethod) {
+ case SpreadMethodPad:
+ m_gradient->setSpread(QGradient::PadSpread);
+ break;
+ case SpreadMethodReflect:
+ m_gradient->setSpread(QGradient::ReflectSpread);
+ break;
+ case SpreadMethodRepeat:
+ m_gradient->setSpread(QGradient::RepeatSpread);
+ break;
+ }
+
+ return m_gradient;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ context->platformContext()->fillRect(rect, *platformGradient());
+}
+
+} //namespace
diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
new file mode 100644
index 0000000..295212c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
@@ -0,0 +1,1674 @@
+/*
+ Copyright (C) 2010 Tieto Corporation.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include "GraphicsContext3D.h"
+
+#include "WebGLObject.h"
+#include "CanvasRenderingContext.h"
+#include "Extensions3DQt.h"
+#include "GraphicsContext.h"
+#include "HTMLCanvasElement.h"
+#include "HostWindow.h"
+#include "ImageBuffer.h"
+#include "NotImplemented.h"
+#include "QWebPageClient.h"
+#include <QAbstractScrollArea>
+#include <QGLContext>
+#include <wtf/UnusedParam.h>
+#include <wtf/text/CString.h>
+
+#if ENABLE(3D_CANVAS)
+
+namespace WebCore {
+
+#if !defined(GLchar)
+typedef char GLchar;
+#endif
+
+#if !defined(APIENTRY)
+#define APIENTRY
+#endif
+
+#ifdef QT_OPENGL_ES_2
+typedef GLsizeiptr GLsizeiptrType;
+typedef GLintptr GLintptrType;
+#else
+typedef ptrdiff_t GLsizeiptrType;
+typedef ptrdiff_t GLintptrType;
+#endif
+
+typedef void (APIENTRY* glActiveTextureType) (GLenum);
+typedef void (APIENTRY* glAttachShaderType) (GLuint, GLuint);
+typedef void (APIENTRY* glBindAttribLocationType) (GLuint, GLuint, const char*);
+typedef void (APIENTRY* glBindBufferType) (GLenum, GLuint);
+typedef void (APIENTRY* glBindFramebufferType) (GLenum, GLuint);
+typedef void (APIENTRY* glBindRenderbufferType) (GLenum, GLuint);
+typedef void (APIENTRY* glBlendColorType) (GLclampf, GLclampf, GLclampf, GLclampf);
+typedef void (APIENTRY* glBlendEquationType) (GLenum);
+typedef void (APIENTRY* glBlendEquationSeparateType)(GLenum, GLenum);
+typedef void (APIENTRY* glBlendFuncSeparateType)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (APIENTRY* glBufferDataType) (GLenum, GLsizeiptrType, const GLvoid*, GLenum);
+typedef void (APIENTRY* glBufferSubDataType) (GLenum, GLintptrType, GLsizeiptrType, const GLvoid*);
+typedef GLenum (APIENTRY* glCheckFramebufferStatusType) (GLenum);
+typedef void (APIENTRY* glCompileShaderType) (GLuint);
+typedef GLuint (APIENTRY* glCreateProgramType) ();
+typedef GLuint (APIENTRY* glCreateShaderType) (GLenum);
+typedef void (APIENTRY* glDeleteBuffersType) (GLsizei, const GLuint*);
+typedef void (APIENTRY* glDeleteFramebuffersType) (GLsizei n, const GLuint*);
+typedef void (APIENTRY* glDeleteProgramType) (GLuint);
+typedef void (APIENTRY* glDeleteRenderbuffersType) (GLsizei n, const GLuint*);
+typedef void (APIENTRY* glDeleteShaderType) (GLuint);
+typedef void (APIENTRY* glDetachShaderType) (GLuint, GLuint);
+typedef void (APIENTRY* glDisableVertexAttribArrayType) (GLuint);
+typedef void (APIENTRY* glEnableVertexAttribArrayType) (GLuint);
+typedef void (APIENTRY* glFramebufferRenderbufferType) (GLenum, GLenum, GLenum, GLuint);
+typedef void (APIENTRY* glFramebufferTexture2DType) (GLenum, GLenum, GLenum, GLuint, GLint);
+typedef void (APIENTRY* glGenBuffersType) (GLsizei, GLuint*);
+typedef void (APIENTRY* glGenerateMipmapType) (GLenum target);
+typedef void (APIENTRY* glGenFramebuffersType) (GLsizei, GLuint*);
+typedef void (APIENTRY* glGenRenderbuffersType) (GLsizei, GLuint*);
+typedef void (APIENTRY* glGetActiveAttribType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*);
+typedef void (APIENTRY* glGetActiveUniformType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*);
+typedef void (APIENTRY* glGetAttachedShadersType) (GLuint, GLsizei, GLsizei*, GLuint*);
+typedef GLint (APIENTRY* glGetAttribLocationType) (GLuint, const char*);
+typedef void (APIENTRY* glGetBufferParameterivType) (GLenum, GLenum, GLint*);
+typedef void (APIENTRY* glGetFramebufferAttachmentParameterivType) (GLenum, GLenum, GLenum, GLint* params);
+typedef void (APIENTRY* glGetProgramInfoLogType) (GLuint, GLsizei, GLsizei*, char*);
+typedef void (APIENTRY* glGetProgramivType) (GLuint, GLenum, GLint*);
+typedef void (APIENTRY* glGetRenderbufferParameterivType) (GLenum, GLenum, GLint*);
+typedef void (APIENTRY* glGetShaderInfoLogType) (GLuint, GLsizei, GLsizei*, char*);
+typedef void (APIENTRY* glGetShaderivType) (GLuint, GLenum, GLint*);
+typedef void (APIENTRY* glGetShaderSourceType) (GLuint, GLsizei, GLsizei*, char*);
+typedef GLint (APIENTRY* glGetUniformLocationType) (GLuint, const char*);
+typedef void (APIENTRY* glGetUniformfvType) (GLuint, GLint, GLfloat*);
+typedef void (APIENTRY* glGetUniformivType) (GLuint, GLint, GLint*);
+typedef void (APIENTRY* glGetVertexAttribfvType) (GLuint, GLenum, GLfloat*);
+typedef void (APIENTRY* glGetVertexAttribivType) (GLuint, GLenum, GLint*);
+typedef void (APIENTRY* glGetVertexAttribPointervType) (GLuint, GLenum, GLvoid**);
+typedef GLboolean (APIENTRY* glIsBufferType) (GLuint);
+typedef GLboolean (APIENTRY* glIsFramebufferType) (GLuint);
+typedef GLboolean (APIENTRY* glIsProgramType) (GLuint);
+typedef GLboolean (APIENTRY* glIsRenderbufferType) (GLuint);
+typedef GLboolean (APIENTRY* glIsShaderType) (GLuint);
+typedef void (APIENTRY* glLinkProgramType) (GLuint);
+typedef void (APIENTRY* glRenderbufferStorageType) (GLenum, GLenum, GLsizei, GLsizei);
+typedef void (APIENTRY* glSampleCoverageType) (GLclampf, GLboolean);
+typedef void (APIENTRY* glShaderSourceType) (GLuint, GLsizei, const char**, const GLint*);
+typedef void (APIENTRY* glStencilFuncSeparateType) (GLenum, GLenum, GLint, GLuint);
+typedef void (APIENTRY* glStencilMaskSeparateType) (GLenum, GLuint);
+typedef void (APIENTRY* glStencilOpSeparateType) (GLenum, GLenum, GLenum, GLenum);
+typedef void (APIENTRY* glUniform1fType) (GLint, GLfloat);
+typedef void (APIENTRY* glUniform1fvType) (GLint, GLsizei, const GLfloat*);
+typedef void (APIENTRY* glUniform1iType) (GLint, GLint);
+typedef void (APIENTRY* glUniform1ivType) (GLint, GLsizei, const GLint*);
+typedef void (APIENTRY* glUniform2fType) (GLint, GLfloat, GLfloat);
+typedef void (APIENTRY* glUniform2fvType) (GLint, GLsizei, const GLfloat*);
+typedef void (APIENTRY* glUniform2iType) (GLint, GLint, GLint);
+typedef void (APIENTRY* glUniform2ivType) (GLint, GLsizei, const GLint*);
+typedef void (APIENTRY* glUniform3fType) (GLint, GLfloat, GLfloat, GLfloat);
+typedef void (APIENTRY* glUniform3fvType) (GLint, GLsizei, const GLfloat*);
+typedef void (APIENTRY* glUniform3iType) (GLint, GLint, GLint, GLint);
+typedef void (APIENTRY* glUniform3ivType) (GLint, GLsizei, const GLint*);
+typedef void (APIENTRY* glUniform4fType) (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+typedef void (APIENTRY* glUniform4fvType) (GLint, GLsizei, const GLfloat*);
+typedef void (APIENTRY* glUniform4iType) (GLint, GLint, GLint, GLint, GLint);
+typedef void (APIENTRY* glUniform4ivType) (GLint, GLsizei, const GLint*);
+typedef void (APIENTRY* glUniformMatrix2fvType) (GLint, GLsizei, GLboolean, const GLfloat*);
+typedef void (APIENTRY* glUniformMatrix3fvType) (GLint, GLsizei, GLboolean, const GLfloat*);
+typedef void (APIENTRY* glUniformMatrix4fvType) (GLint, GLsizei, GLboolean, const GLfloat*);
+typedef void (APIENTRY* glUseProgramType) (GLuint);
+typedef void (APIENTRY* glValidateProgramType) (GLuint);
+typedef void (APIENTRY* glVertexAttrib1fType) (GLuint, const GLfloat);
+typedef void (APIENTRY* glVertexAttrib1fvType) (GLuint, const GLfloat*);
+typedef void (APIENTRY* glVertexAttrib2fType) (GLuint, const GLfloat, const GLfloat);
+typedef void (APIENTRY* glVertexAttrib2fvType) (GLuint, const GLfloat*);
+typedef void (APIENTRY* glVertexAttrib3fType) (GLuint, const GLfloat, const GLfloat, const GLfloat);
+typedef void (APIENTRY* glVertexAttrib3fvType) (GLuint, const GLfloat*);
+typedef void (APIENTRY* glVertexAttrib4fType) (GLuint, const GLfloat, const GLfloat, const GLfloat, const GLfloat);
+typedef void (APIENTRY* glVertexAttrib4fvType) (GLuint, const GLfloat*);
+typedef void (APIENTRY* glVertexAttribPointerType) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);
+
+class GraphicsContext3DInternal {
+public:
+ GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow);
+ ~GraphicsContext3DInternal();
+
+ bool isContextValid() { return m_contextValid; }
+ QGLWidget* getOwnerGLWidget(QWebPageClient* webPageClient);
+
+ glActiveTextureType activeTexture;
+ glAttachShaderType attachShader;
+ glBindAttribLocationType bindAttribLocation;
+ glBindBufferType bindBuffer;
+ glBindFramebufferType bindFramebuffer;
+ glBindRenderbufferType bindRenderbuffer;
+ glBlendColorType blendColor;
+ glBlendEquationType blendEquation;
+ glBlendEquationSeparateType blendEquationSeparate;
+ glBlendFuncSeparateType blendFuncSeparate;
+ glBufferDataType bufferData;
+ glBufferSubDataType bufferSubData;
+ glCheckFramebufferStatusType checkFramebufferStatus;
+ glCompileShaderType compileShader;
+ glCreateProgramType createProgram;
+ glCreateShaderType createShader;
+ glDeleteBuffersType deleteBuffers;
+ glDeleteFramebuffersType deleteFramebuffers;
+ glDeleteProgramType deleteProgram;
+ glDeleteRenderbuffersType deleteRenderbuffers;
+ glDeleteShaderType deleteShader;
+ glDetachShaderType detachShader;
+ glDisableVertexAttribArrayType disableVertexAttribArray;
+ glEnableVertexAttribArrayType enableVertexAttribArray;
+ glFramebufferRenderbufferType framebufferRenderbuffer;
+ glFramebufferTexture2DType framebufferTexture2D;
+ glGenBuffersType genBuffers;
+ glGenerateMipmapType generateMipmap;
+ glGenFramebuffersType genFramebuffers;
+ glGenRenderbuffersType genRenderbuffers;
+ glGetActiveAttribType getActiveAttrib;
+ glGetActiveUniformType getActiveUniform;
+ glGetAttachedShadersType getAttachedShaders;
+ glGetAttribLocationType getAttribLocation;
+ glGetBufferParameterivType getBufferParameteriv;
+ glGetFramebufferAttachmentParameterivType getFramebufferAttachmentParameteriv;
+ glGetProgramInfoLogType getProgramInfoLog;
+ glGetProgramivType getProgramiv;
+ glGetRenderbufferParameterivType getRenderbufferParameteriv;
+ glGetShaderInfoLogType getShaderInfoLog;
+ glGetShaderivType getShaderiv;
+ glGetShaderSourceType getShaderSource;
+ glGetUniformfvType getUniformfv;
+ glGetUniformivType getUniformiv;
+ glGetUniformLocationType getUniformLocation;
+ glGetVertexAttribfvType getVertexAttribfv;
+ glGetVertexAttribivType getVertexAttribiv;
+ glGetVertexAttribPointervType getVertexAttribPointerv;
+ glIsBufferType isBuffer;
+ glIsFramebufferType isFramebuffer;
+ glIsProgramType isProgram;
+ glIsRenderbufferType isRenderbuffer;
+ glIsShaderType isShader;
+ glLinkProgramType linkProgram;
+ glRenderbufferStorageType renderbufferStorage;
+ glSampleCoverageType sampleCoverage;
+ glShaderSourceType shaderSource;
+ glStencilFuncSeparateType stencilFuncSeparate;
+ glStencilMaskSeparateType stencilMaskSeparate;
+ glStencilOpSeparateType stencilOpSeparate;
+ glUniform1fType uniform1f;
+ glUniform1fvType uniform1fv;
+ glUniform1iType uniform1i;
+ glUniform1ivType uniform1iv;
+ glUniform2fType uniform2f;
+ glUniform2fvType uniform2fv;
+ glUniform2iType uniform2i;
+ glUniform2ivType uniform2iv;
+ glUniform3fType uniform3f;
+ glUniform3fvType uniform3fv;
+ glUniform3iType uniform3i;
+ glUniform3ivType uniform3iv;
+ glUniform4fType uniform4f;
+ glUniform4fvType uniform4fv;
+ glUniform4iType uniform4i;
+ glUniform4ivType uniform4iv;
+ glUniformMatrix2fvType uniformMatrix2fv;
+ glUniformMatrix3fvType uniformMatrix3fv;
+ glUniformMatrix4fvType uniformMatrix4fv;
+ glUseProgramType useProgram;
+ glValidateProgramType validateProgram;
+ glVertexAttrib1fType vertexAttrib1f;
+ glVertexAttrib1fvType vertexAttrib1fv;
+ glVertexAttrib2fType vertexAttrib2f;
+ glVertexAttrib2fvType vertexAttrib2fv;
+ glVertexAttrib3fType vertexAttrib3f;
+ glVertexAttrib3fvType vertexAttrib3fv;
+ glVertexAttrib4fType vertexAttrib4f;
+ glVertexAttrib4fvType vertexAttrib4fv;
+ glVertexAttribPointerType vertexAttribPointer;
+
+ GraphicsContext3D::Attributes m_attrs;
+ HostWindow* m_hostWindow;
+ QGLWidget* m_glWidget;
+ GLuint m_texture;
+ GLuint m_mainFbo;
+ GLuint m_currentFbo;
+ GLuint m_depthBuffer;
+ QImage m_pixels;
+ ListHashSet<unsigned long> m_syntheticErrors;
+
+ OwnPtr<Extensions3DQt> m_extensions;
+
+private:
+
+ void* getProcAddress(const String& proc);
+ bool m_contextValid;
+};
+
+#if defined (QT_OPENGL_ES_2)
+#define GET_PROC_ADDRESS(Proc) Proc
+#else
+#define GET_PROC_ADDRESS(Proc) reinterpret_cast<Proc##Type>(getProcAddress(#Proc));
+#endif
+
+bool GraphicsContext3D::isGLES2Compliant() const
+{
+#if defined (QT_OPENGL_ES_2)
+ return true;
+#else
+ return false;
+#endif
+}
+
+// Even with underlying GLES2 driver, the below flags should still be set to
+// false if extentions exist (and they almost always do).
+bool GraphicsContext3D::isGLES2NPOTStrict() const
+{
+ return false;
+}
+
+bool GraphicsContext3D::isErrorGeneratedOnOutOfBoundsAccesses() const
+{
+ return false;
+}
+
+int GraphicsContext3D::getGraphicsResetStatusARB()
+{
+ return NO_ERROR;
+}
+
+
+GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow)
+ : m_attrs(attrs)
+ , m_hostWindow(hostWindow)
+ , m_glWidget(0)
+ , m_texture(0)
+ , m_mainFbo(0)
+ , m_currentFbo(0)
+ , m_depthBuffer(0)
+ , m_contextValid(true)
+{
+ QWebPageClient* webPageClient = hostWindow->platformPageClient();
+ QGLWidget* ownerGLWidget = getOwnerGLWidget(webPageClient);
+
+ if (ownerGLWidget)
+ m_glWidget = new QGLWidget(0, ownerGLWidget);
+ else {
+ QGLFormat format;
+ format.setDepth(true);
+ format.setSampleBuffers(true);
+ format.setStencil(false);
+
+ m_glWidget = new QGLWidget(format);
+ }
+
+ if (!m_glWidget->isValid()) {
+ LOG_ERROR("GraphicsContext3D: QGLWidget does not have a valid context");
+ m_contextValid = false;
+ return;
+ }
+
+ QGLFormat format = m_glWidget->format();
+
+ m_attrs.alpha = format.alpha();
+ m_attrs.depth = format.depth();
+ m_attrs.stencil = format.stencil();
+ m_attrs.antialias = false;
+ m_attrs.premultipliedAlpha = true;
+
+ m_glWidget->makeCurrent();
+
+ activeTexture = GET_PROC_ADDRESS(glActiveTexture);
+ attachShader = GET_PROC_ADDRESS(glAttachShader);
+ bindAttribLocation = GET_PROC_ADDRESS(glBindAttribLocation);
+ bindBuffer = GET_PROC_ADDRESS(glBindBuffer);
+ bindFramebuffer = GET_PROC_ADDRESS(glBindFramebuffer);
+ bindRenderbuffer = GET_PROC_ADDRESS(glBindRenderbuffer);
+ blendColor = GET_PROC_ADDRESS(glBlendColor);
+ blendEquation = GET_PROC_ADDRESS(glBlendEquation);
+ blendEquationSeparate = GET_PROC_ADDRESS(glBlendEquationSeparate);
+ blendFuncSeparate = GET_PROC_ADDRESS(glBlendFuncSeparate);
+ bufferData = GET_PROC_ADDRESS(glBufferData);
+ bufferSubData = GET_PROC_ADDRESS(glBufferSubData);
+ checkFramebufferStatus = GET_PROC_ADDRESS(glCheckFramebufferStatus);
+ compileShader = GET_PROC_ADDRESS(glCompileShader);
+ createProgram = GET_PROC_ADDRESS(glCreateProgram);
+ createShader = GET_PROC_ADDRESS(glCreateShader);
+ deleteBuffers = GET_PROC_ADDRESS(glDeleteBuffers);
+ deleteFramebuffers = GET_PROC_ADDRESS(glDeleteFramebuffers);
+ deleteProgram = GET_PROC_ADDRESS(glDeleteProgram);
+ deleteRenderbuffers = GET_PROC_ADDRESS(glDeleteRenderbuffers);
+ deleteShader = GET_PROC_ADDRESS(glDeleteShader);
+ detachShader = GET_PROC_ADDRESS(glDetachShader);
+ disableVertexAttribArray = GET_PROC_ADDRESS(glDisableVertexAttribArray);
+ enableVertexAttribArray = GET_PROC_ADDRESS(glEnableVertexAttribArray);
+ framebufferRenderbuffer = GET_PROC_ADDRESS(glFramebufferRenderbuffer);
+ framebufferTexture2D = GET_PROC_ADDRESS(glFramebufferTexture2D);
+ genBuffers = GET_PROC_ADDRESS(glGenBuffers);
+ generateMipmap = GET_PROC_ADDRESS(glGenerateMipmap);
+ genFramebuffers = GET_PROC_ADDRESS(glGenFramebuffers);
+ genRenderbuffers = GET_PROC_ADDRESS(glGenRenderbuffers);
+ getActiveAttrib = GET_PROC_ADDRESS(glGetActiveAttrib);
+ getActiveUniform = GET_PROC_ADDRESS(glGetActiveUniform);
+ getAttachedShaders = GET_PROC_ADDRESS(glGetAttachedShaders);
+ getAttribLocation = GET_PROC_ADDRESS(glGetAttribLocation);
+ getBufferParameteriv = GET_PROC_ADDRESS(glGetBufferParameteriv);
+ getFramebufferAttachmentParameteriv = GET_PROC_ADDRESS(glGetFramebufferAttachmentParameteriv);
+ getProgramInfoLog = GET_PROC_ADDRESS(glGetProgramInfoLog);
+ getProgramiv = GET_PROC_ADDRESS(glGetProgramiv);
+ getRenderbufferParameteriv = GET_PROC_ADDRESS(glGetRenderbufferParameteriv);
+ getShaderInfoLog = GET_PROC_ADDRESS(glGetShaderInfoLog);
+ getShaderiv = GET_PROC_ADDRESS(glGetShaderiv);
+ getShaderSource = GET_PROC_ADDRESS(glGetShaderSource);
+ getUniformfv = GET_PROC_ADDRESS(glGetUniformfv);
+ getUniformiv = GET_PROC_ADDRESS(glGetUniformiv);
+ getUniformLocation = GET_PROC_ADDRESS(glGetUniformLocation);
+ getVertexAttribfv = GET_PROC_ADDRESS(glGetVertexAttribfv);
+ getVertexAttribiv = GET_PROC_ADDRESS(glGetVertexAttribiv);
+ getVertexAttribPointerv = GET_PROC_ADDRESS(glGetVertexAttribPointerv);
+ isBuffer = GET_PROC_ADDRESS(glIsBuffer);
+ isFramebuffer = GET_PROC_ADDRESS(glIsFramebuffer);
+ isProgram = GET_PROC_ADDRESS(glIsProgram);
+ isRenderbuffer = GET_PROC_ADDRESS(glIsRenderbuffer);
+ isShader = GET_PROC_ADDRESS(glIsShader);
+ linkProgram = GET_PROC_ADDRESS(glLinkProgram);
+ renderbufferStorage = GET_PROC_ADDRESS(glRenderbufferStorage);
+ sampleCoverage = GET_PROC_ADDRESS(glSampleCoverage);
+ shaderSource = GET_PROC_ADDRESS(glShaderSource);
+ stencilFuncSeparate = GET_PROC_ADDRESS(glStencilFuncSeparate);
+ stencilMaskSeparate = GET_PROC_ADDRESS(glStencilMaskSeparate);
+ stencilOpSeparate = GET_PROC_ADDRESS(glStencilOpSeparate);
+ uniform1f = GET_PROC_ADDRESS(glUniform1f);
+ uniform1fv = GET_PROC_ADDRESS(glUniform1fv);
+ uniform1i = GET_PROC_ADDRESS(glUniform1i);
+ uniform1iv = GET_PROC_ADDRESS(glUniform1iv);
+ uniform2f = GET_PROC_ADDRESS(glUniform2f);
+ uniform2fv = GET_PROC_ADDRESS(glUniform2fv);
+ uniform2i = GET_PROC_ADDRESS(glUniform2i);
+ uniform2iv = GET_PROC_ADDRESS(glUniform2iv);
+ uniform3f = GET_PROC_ADDRESS(glUniform3f);
+ uniform3fv = GET_PROC_ADDRESS(glUniform3fv);
+ uniform3i = GET_PROC_ADDRESS(glUniform3i);
+ uniform3iv = GET_PROC_ADDRESS(glUniform3iv);
+ uniform4f = GET_PROC_ADDRESS(glUniform4f);
+ uniform4fv = GET_PROC_ADDRESS(glUniform4fv);
+ uniform4i = GET_PROC_ADDRESS(glUniform4i);
+ uniform4iv = GET_PROC_ADDRESS(glUniform4iv);
+ uniformMatrix2fv = GET_PROC_ADDRESS(glUniformMatrix2fv);
+ uniformMatrix3fv = GET_PROC_ADDRESS(glUniformMatrix3fv);
+ uniformMatrix4fv = GET_PROC_ADDRESS(glUniformMatrix4fv);
+ useProgram = GET_PROC_ADDRESS(glUseProgram);
+ validateProgram = GET_PROC_ADDRESS(glValidateProgram);
+ vertexAttrib1f = GET_PROC_ADDRESS(glVertexAttrib1f);
+ vertexAttrib1fv = GET_PROC_ADDRESS(glVertexAttrib1fv);
+ vertexAttrib2f = GET_PROC_ADDRESS(glVertexAttrib2f);
+ vertexAttrib2fv = GET_PROC_ADDRESS(glVertexAttrib2fv);
+ vertexAttrib3f = GET_PROC_ADDRESS(glVertexAttrib3f);
+ vertexAttrib3fv = GET_PROC_ADDRESS(glVertexAttrib3fv);
+ vertexAttrib4f = GET_PROC_ADDRESS(glVertexAttrib4f);
+ vertexAttrib4fv = GET_PROC_ADDRESS(glVertexAttrib4fv);
+ vertexAttribPointer = GET_PROC_ADDRESS(glVertexAttribPointer);
+
+ if (!m_contextValid) {
+ LOG_ERROR("GraphicsContext3D: All needed OpenGL extensions are not available");
+ m_contextValid = false;
+ return;
+ }
+
+ glGenTextures(1, &m_texture);
+ glBindTexture(GraphicsContext3D::TEXTURE_2D, m_texture);
+ glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
+ glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
+ glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
+ glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
+ glTexImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0);
+ glBindTexture(GraphicsContext3D::TEXTURE_2D, 0);
+
+ genFramebuffers(/* count */ 1, &m_mainFbo);
+ m_currentFbo = m_mainFbo;
+
+ bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_mainFbo);
+
+ genRenderbuffers(/* count */ 1, &m_depthBuffer);
+ bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
+#if defined(QT_OPENGL_ES_2)
+ renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, /* width */ 1, /* height */ 1);
+#else
+ renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT, /* width */ 1, /* height */ 1);
+#endif
+
+ bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
+
+ framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_texture, 0);
+ framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
+ glClearColor(/* red */ 0, /* green */ 0, /* blue */ 0, /* alpha */ 0);
+
+ if (checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+ LOG_ERROR("GraphicsContext3D: Wasn't able to create the main framebuffer");
+ m_contextValid = false;
+ }
+}
+
+GraphicsContext3DInternal::~GraphicsContext3DInternal()
+{
+ delete m_glWidget;
+ m_glWidget = 0;
+}
+
+QGLWidget* GraphicsContext3DInternal::getOwnerGLWidget(QWebPageClient* webPageClient)
+{
+ QAbstractScrollArea* scrollArea = qobject_cast<QAbstractScrollArea*>(webPageClient->ownerWidget());
+
+ if (scrollArea)
+ return qobject_cast<QGLWidget*>(scrollArea->viewport());
+
+ return 0;
+}
+
+void* GraphicsContext3DInternal::getProcAddress(const String& proc)
+{
+ String ext[3] = { "", "ARB", "EXT" };
+
+ for (int i = 0; i < 3; i++) {
+ String nameWithExt = proc + ext[i];
+
+ void* addr = m_glWidget->context()->getProcAddress(nameWithExt.utf8().data());
+ if (addr)
+ return addr;
+ }
+
+ LOG_ERROR("GraphicsContext3D: Did not find GL function %s", proc.utf8().data());
+ m_contextValid = false;
+ return 0;
+}
+
+PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
+{
+ // This implementation doesn't currently support rendering directly to the HostWindow.
+ if (renderStyle == RenderDirectlyToHostWindow)
+ return 0;
+ OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs, hostWindow, false));
+ return context->m_internal ? context.release() : 0;
+}
+
+GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, bool)
+ : m_internal(new GraphicsContext3DInternal(attrs, hostWindow))
+{
+ if (!m_internal->isContextValid())
+ m_internal = 0;
+}
+
+GraphicsContext3D::~GraphicsContext3D()
+{
+}
+
+PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D()
+{
+ return m_internal->m_glWidget;
+}
+
+Platform3DObject GraphicsContext3D::platformTexture() const
+{
+ return m_internal->m_texture;
+}
+
+void GraphicsContext3D::makeContextCurrent()
+{
+ m_internal->m_glWidget->makeCurrent();
+}
+
+void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* context)
+{
+ m_internal->m_glWidget->makeCurrent();
+ HTMLCanvasElement* canvas = context->canvas();
+ ImageBuffer* imageBuffer = canvas->buffer();
+ QPainter* painter = imageBuffer->context()->platformContext();
+ paint(painter, QRect(QPoint(0, 0), QSize(m_currentWidth, m_currentHeight)));
+}
+
+void GraphicsContext3D::paint(QPainter* painter, const QRect& rect) const
+{
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ QWebPageClient* webPageClient = m_internal->m_hostWindow->platformPageClient();
+ QGLWidget* ownerGLWidget = m_internal->getOwnerGLWidget(webPageClient);
+ if (ownerGLWidget) {
+ ownerGLWidget->drawTexture(rect, m_internal->m_texture);
+ return;
+ }
+#endif
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_mainFbo);
+ glReadPixels(/* x */ 0, /* y */ 0, m_currentWidth, m_currentHeight, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, m_internal->m_pixels.bits());
+ painter->drawImage(/* x */ 0, /* y */ 0, m_internal->m_pixels.rgbSwapped().transformed(QMatrix().rotate(180)));
+ m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_currentFbo);
+}
+
+void GraphicsContext3D::reshape(int width, int height)
+{
+ if (((width == m_currentWidth) && (height == m_currentHeight)) || (!m_internal))
+ return;
+
+ m_currentWidth = width;
+ m_currentHeight = height;
+
+ m_internal->m_pixels = QImage(m_currentWidth, m_currentHeight, QImage::Format_ARGB32);
+
+ m_internal->m_glWidget->makeCurrent();
+
+ glBindTexture(GraphicsContext3D::TEXTURE_2D, m_internal->m_texture);
+ glTexImage2D(GraphicsContext3D::TEXTURE_2D, /* level */ 0, GraphicsContext3D::RGBA, width, height, /* border */ 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, /* data */ 0);
+ glBindTexture(GraphicsContext3D::TEXTURE_2D, 0);
+
+ m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_mainFbo);
+ m_internal->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_internal->m_depthBuffer);
+#if defined(QT_OPENGL_ES_2)
+ renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, width, height);
+#else
+ renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT, width, height);
+#endif
+ m_internal->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
+
+ m_internal->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_internal->m_texture, 0);
+ m_internal->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_internal->m_depthBuffer);
+
+ GLenum status = m_internal->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER);
+ if (status != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+ LOG_ERROR("GraphicsContext3D: Wasn't able to reshape the main framebuffer");
+ notImplemented();
+ }
+
+ glClear(GraphicsContext3D::COLOR_BUFFER_BIT);
+ glFlush();
+}
+
+IntSize GraphicsContext3D::getInternalFramebufferSize()
+{
+ return IntSize(m_currentWidth, m_currentHeight);
+}
+
+void GraphicsContext3D::activeTexture(GC3Denum texture)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->activeTexture(texture);
+}
+
+void GraphicsContext3D::attachShader(Platform3DObject program, Platform3DObject shader)
+{
+ ASSERT(program);
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->attachShader(program, shader);
+}
+
+void GraphicsContext3D::getAttachedShaders(Platform3DObject program, GC3Dsizei maxCount, GC3Dsizei* count, Platform3DObject* shaders)
+{
+ if (!program) {
+ synthesizeGLError(INVALID_VALUE);
+ return;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+ getAttachedShaders(program, maxCount, count, shaders);
+}
+
+void GraphicsContext3D::bindAttribLocation(Platform3DObject program, GC3Duint index, const String& name)
+{
+ ASSERT(program);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindAttribLocation(program, index, name.utf8().data());
+}
+
+void GraphicsContext3D::bindBuffer(GC3Denum target, Platform3DObject buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindBuffer(target, buffer);
+}
+
+void GraphicsContext3D::bindFramebuffer(GC3Denum target, Platform3DObject buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->m_currentFbo = buffer ? buffer : m_internal->m_mainFbo;
+ m_internal->bindFramebuffer(target, m_internal->m_currentFbo);
+}
+
+void GraphicsContext3D::bindRenderbuffer(GC3Denum target, Platform3DObject renderbuffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindRenderbuffer(target, renderbuffer);
+}
+
+void GraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glBindTexture(target, texture);
+}
+
+void GraphicsContext3D::blendColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendColor(red, green, blue, alpha);
+}
+
+void GraphicsContext3D::blendEquation(GC3Denum mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendEquation(mode);
+}
+
+void GraphicsContext3D::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendEquationSeparate(modeRGB, modeAlpha);
+}
+
+void GraphicsContext3D::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glBlendFunc(sfactor, dfactor);
+}
+
+void GraphicsContext3D::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bufferData(target, size, /* data */ 0, usage);
+}
+
+void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bufferData(target, size, data, usage);
+}
+
+void GraphicsContext3D::bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bufferSubData(target, offset, size, data);
+}
+
+GC3Denum GraphicsContext3D::checkFramebufferStatus(GC3Denum target)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->checkFramebufferStatus(target);
+}
+
+void GraphicsContext3D::clearColor(GC3Dclampf r, GC3Dclampf g, GC3Dclampf b, GC3Dclampf a)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glClearColor(r, g, b, a);
+}
+
+void GraphicsContext3D::clear(GC3Dbitfield mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glClear(mask);
+}
+
+void GraphicsContext3D::clearDepth(GC3Dclampf depth)
+{
+ m_internal->m_glWidget->makeCurrent();
+#if defined(QT_OPENGL_ES_2)
+ glClearDepthf(depth);
+#else
+ glClearDepth(depth);
+#endif
+}
+
+void GraphicsContext3D::clearStencil(GC3Dint s)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glClearStencil(s);
+}
+
+void GraphicsContext3D::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glColorMask(red, green, blue, alpha);
+}
+
+void GraphicsContext3D::compileShader(Platform3DObject shader)
+{
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->compileShader(shader);
+}
+
+void GraphicsContext3D::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+}
+
+void GraphicsContext3D::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+}
+
+void GraphicsContext3D::cullFace(GC3Denum mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glCullFace(mode);
+}
+
+void GraphicsContext3D::depthFunc(GC3Denum func)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDepthFunc(func);
+}
+
+void GraphicsContext3D::depthMask(GC3Dboolean flag)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDepthMask(flag);
+}
+
+void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar)
+{
+ m_internal->m_glWidget->makeCurrent();
+#if defined(QT_OPENGL_ES_2)
+ glDepthRangef(zNear, zFar);
+#else
+ glDepthRange(zNear, zFar);
+#endif
+}
+
+void GraphicsContext3D::detachShader(Platform3DObject program, Platform3DObject shader)
+{
+ ASSERT(program);
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->detachShader(program, shader);
+}
+
+void GraphicsContext3D::disable(GC3Denum cap)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDisable(cap);
+}
+
+void GraphicsContext3D::disableVertexAttribArray(GC3Duint index)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->disableVertexAttribArray(index);
+}
+
+void GraphicsContext3D::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDrawArrays(mode, first, count);
+}
+
+void GraphicsContext3D::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)));
+}
+
+void GraphicsContext3D::enable(GC3Denum cap)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glEnable(cap);
+}
+
+void GraphicsContext3D::enableVertexAttribArray(GC3Duint index)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->enableVertexAttribArray(index);
+}
+
+void GraphicsContext3D::finish()
+{
+ m_internal->m_glWidget->makeCurrent();
+ glFinish();
+}
+
+void GraphicsContext3D::flush()
+{
+ m_internal->m_glWidget->makeCurrent();
+ glFlush();
+}
+
+void GraphicsContext3D::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, Platform3DObject buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->framebufferRenderbuffer(target, attachment, renderbuffertarget, buffer);
+}
+
+void GraphicsContext3D::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject texture, GC3Dint level)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->framebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+void GraphicsContext3D::frontFace(GC3Denum mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glFrontFace(mode);
+}
+
+void GraphicsContext3D::generateMipmap(GC3Denum target)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->generateMipmap(target);
+}
+
+bool GraphicsContext3D::getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo& info)
+{
+ if (!program) {
+ synthesizeGLError(INVALID_VALUE);
+ return false;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint maxLength = 0;
+ m_internal->getProgramiv(program, GraphicsContext3D::ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
+
+ GLchar* name = (GLchar*) fastMalloc(maxLength);
+ GLsizei nameLength = 0;
+ GLint size = 0;
+ GLenum type = 0;
+
+ m_internal->getActiveAttrib(program, index, maxLength, &nameLength, &size, &type, name);
+
+ if (!nameLength) {
+ fastFree(name);
+ return false;
+ }
+
+ info.name = String(name, nameLength);
+ info.type = type;
+ info.size = size;
+
+ fastFree(name);
+ return true;
+}
+
+bool GraphicsContext3D::getActiveUniform(Platform3DObject program, GC3Duint index, ActiveInfo& info)
+{
+ if (!program) {
+ synthesizeGLError(INVALID_VALUE);
+ return false;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint maxLength = 0;
+ m_internal->getProgramiv(static_cast<GLuint>(program), GraphicsContext3D::ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+
+ GLchar* name = (GLchar*) fastMalloc(maxLength);
+ GLsizei nameLength = 0;
+ GLint size = 0;
+ GLenum type = 0;
+
+ m_internal->getActiveUniform(static_cast<GLuint>(program), index, maxLength, &nameLength, &size, &type, name);
+
+ if (!nameLength) {
+ fastFree(name);
+ return false;
+ }
+
+ info.name = String(name, nameLength);
+ info.type = type;
+ info.size = size;
+
+ fastFree(name);
+ return true;
+}
+
+int GraphicsContext3D::getAttribLocation(Platform3DObject program, const String& name)
+{
+ if (!program)
+ return -1;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->getAttribLocation(program, name.utf8().data());
+}
+
+GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes()
+{
+ return m_internal->m_attrs;
+}
+
+GC3Denum GraphicsContext3D::getError()
+{
+ if (m_internal->m_syntheticErrors.size() > 0) {
+ ListHashSet<GC3Denum>::iterator iter = m_internal->m_syntheticErrors.begin();
+ GC3Denum err = *iter;
+ m_internal->m_syntheticErrors.remove(iter);
+ return err;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+ return glGetError();
+}
+
+String GraphicsContext3D::getString(GC3Denum name)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return String((const char*) glGetString(name));
+}
+
+void GraphicsContext3D::hint(GC3Denum target, GC3Denum mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glHint(target, mode);
+}
+
+GC3Dboolean GraphicsContext3D::isBuffer(Platform3DObject buffer)
+{
+ if (!buffer)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isBuffer(buffer);
+}
+
+GC3Dboolean GraphicsContext3D::isEnabled(GC3Denum cap)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return glIsEnabled(cap);
+}
+
+GC3Dboolean GraphicsContext3D::isFramebuffer(Platform3DObject framebuffer)
+{
+ if (!framebuffer)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isFramebuffer(framebuffer);
+}
+
+GC3Dboolean GraphicsContext3D::isProgram(Platform3DObject program)
+{
+ if (!program)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isProgram(program);
+}
+
+GC3Dboolean GraphicsContext3D::isRenderbuffer(Platform3DObject renderbuffer)
+{
+ if (!renderbuffer)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isRenderbuffer(renderbuffer);
+}
+
+GC3Dboolean GraphicsContext3D::isShader(Platform3DObject shader)
+{
+ if (!shader)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isShader(shader);
+}
+
+GC3Dboolean GraphicsContext3D::isTexture(Platform3DObject texture)
+{
+ if (!texture)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return glIsTexture(texture);
+}
+
+void GraphicsContext3D::lineWidth(double width)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glLineWidth(static_cast<float>(width));
+}
+
+void GraphicsContext3D::linkProgram(Platform3DObject program)
+{
+ ASSERT(program);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->linkProgram(program);
+}
+
+void GraphicsContext3D::pixelStorei(GC3Denum paramName, GC3Dint param)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glPixelStorei(paramName, param);
+}
+
+void GraphicsContext3D::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glPolygonOffset(factor, units);
+}
+
+void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ if (type != GraphicsContext3D::UNSIGNED_BYTE || format != GraphicsContext3D::RGBA)
+ return;
+
+ glReadPixels(x, y, width, height, format, type, data);
+}
+
+void GraphicsContext3D::releaseShaderCompiler()
+{
+ m_internal->m_glWidget->makeCurrent();
+ notImplemented();
+}
+
+void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->renderbufferStorage(target, internalformat, width, height);
+}
+
+void GraphicsContext3D::sampleCoverage(GC3Dclampf value, GC3Dboolean invert)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->sampleCoverage(value, invert);
+}
+
+void GraphicsContext3D::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glScissor(x, y, width, height);
+}
+
+void GraphicsContext3D::shaderSource(Platform3DObject shader, const String& source)
+{
+ ASSERT(shader);
+
+ m_internal->m_glWidget->makeCurrent();
+
+ String prefixedSource;
+
+#if defined (QT_OPENGL_ES_2)
+ prefixedSource.append("precision mediump float;\n");
+#endif
+
+ prefixedSource.append(source);
+
+ CString sourceCS = prefixedSource.utf8();
+ const char* data = sourceCS.data();
+ int length = prefixedSource.length();
+ m_internal->shaderSource((GLuint) shader, /* count */ 1, &data, &length);
+}
+
+void GraphicsContext3D::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glStencilFunc(func, ref, mask);
+}
+
+void GraphicsContext3D::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->stencilFuncSeparate(face, func, ref, mask);
+}
+
+void GraphicsContext3D::stencilMask(GC3Duint mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glStencilMask(mask);
+}
+
+void GraphicsContext3D::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->stencilMaskSeparate(face, mask);
+}
+
+void GraphicsContext3D::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glStencilOp(fail, zfail, zpass);
+}
+
+void GraphicsContext3D::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->stencilOpSeparate(face, fail, zfail, zpass);
+}
+
+void GraphicsContext3D::texParameterf(GC3Denum target, GC3Denum paramName, GC3Dfloat value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexParameterf(target, paramName, value);
+}
+
+void GraphicsContext3D::texParameteri(GC3Denum target, GC3Denum paramName, GC3Dint value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexParameteri(target, paramName, value);
+}
+
+void GraphicsContext3D::uniform1f(GC3Dint location, GC3Dfloat v0)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1f(location, v0);
+}
+
+void GraphicsContext3D::uniform1fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform2f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2f(location, v0, v1);
+}
+
+void GraphicsContext3D::uniform2fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform3f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3f(location, v0, v1, v2);
+}
+
+void GraphicsContext3D::uniform3fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform4f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4f(location, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::uniform4fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform1i(GC3Dint location, GC3Dint v0)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1i(location, v0);
+}
+
+void GraphicsContext3D::uniform1iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform2i(GC3Dint location, GC3Dint v0, GC3Dint v1)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2i(location, v0, v1);
+}
+
+void GraphicsContext3D::uniform2iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform3i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3i(location, v0, v1, v2);
+}
+
+void GraphicsContext3D::uniform3iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform4i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2, GC3Dint v3)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4i(location, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::uniform4iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4iv(location, size, array);
+}
+
+void GraphicsContext3D::uniformMatrix2fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniformMatrix2fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::uniformMatrix3fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniformMatrix3fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::uniformMatrix4fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniformMatrix4fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::useProgram(Platform3DObject program)
+{
+ ASSERT(program);
+
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->useProgram(program);
+}
+
+void GraphicsContext3D::validateProgram(Platform3DObject program)
+{
+ ASSERT(program);
+
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->validateProgram(program);
+}
+
+void GraphicsContext3D::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib1f(index, v0);
+}
+
+void GraphicsContext3D::vertexAttrib1fv(GC3Duint index, GC3Dfloat* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib1fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib2f(index, v0, v1);
+}
+
+void GraphicsContext3D::vertexAttrib2fv(GC3Duint index, GC3Dfloat* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib2fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib3f(index, v0, v1, v2);
+}
+
+void GraphicsContext3D::vertexAttrib3fv(GC3Duint index, GC3Dfloat* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib3fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib4f(index, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::vertexAttrib4fv(GC3Duint index, GC3Dfloat* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib4fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)));
+}
+
+void GraphicsContext3D::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glViewport(x, y, width, height);
+}
+
+void GraphicsContext3D::getBooleanv(GC3Denum paramName, GC3Dboolean* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetBooleanv(paramName, value);
+}
+
+void GraphicsContext3D::getBufferParameteriv(GC3Denum target, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getBufferParameteriv(target, paramName, value);
+}
+
+void GraphicsContext3D::getFloatv(GC3Denum paramName, GC3Dfloat* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetFloatv(paramName, value);
+}
+
+void GraphicsContext3D::getFramebufferAttachmentParameteriv(GC3Denum target, GC3Denum attachment, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getFramebufferAttachmentParameteriv(target, attachment, paramName, value);
+}
+
+void GraphicsContext3D::getIntegerv(GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetIntegerv(paramName, value);
+}
+
+void GraphicsContext3D::getProgramiv(Platform3DObject program, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getProgramiv(program, paramName, value);
+}
+
+String GraphicsContext3D::getProgramInfoLog(Platform3DObject program)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint length = 0;
+ m_internal->getProgramiv(program, GraphicsContext3D::INFO_LOG_LENGTH, &length);
+
+ GLsizei size = 0;
+
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
+ m_internal->getProgramInfoLog(program, length, &size, info);
+
+ String result(info);
+ fastFree(info);
+
+ return result;
+}
+
+void GraphicsContext3D::getRenderbufferParameteriv(GC3Denum target, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getRenderbufferParameteriv(target, paramName, value);
+}
+
+void GraphicsContext3D::getShaderiv(Platform3DObject shader, GC3Denum paramName, GC3Dint* value)
+{
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getShaderiv(shader, paramName, value);
+}
+
+String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint length = 0;
+ m_internal->getShaderiv(shader, GraphicsContext3D::INFO_LOG_LENGTH, &length);
+
+ GLsizei size = 0;
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
+ m_internal->getShaderInfoLog(shader, length, &size, info);
+
+ String result(info);
+ fastFree(info);
+
+ return result;
+}
+
+String GraphicsContext3D::getShaderSource(Platform3DObject shader)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint length = 0;
+ m_internal->getShaderiv(shader, GraphicsContext3D::SHADER_SOURCE_LENGTH, &length);
+
+ GLsizei size = 0;
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
+ m_internal->getShaderSource(shader, length, &size, info);
+
+ String result(info);
+ fastFree(info);
+
+ return result;
+}
+
+void GraphicsContext3D::getTexParameterfv(GC3Denum target, GC3Denum paramName, GC3Dfloat* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetTexParameterfv(target, paramName, value);
+}
+
+void GraphicsContext3D::getTexParameteriv(GC3Denum target, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetTexParameteriv(target, paramName, value);
+}
+
+void GraphicsContext3D::getUniformfv(Platform3DObject program, GC3Dint location, GC3Dfloat* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getUniformfv(program, location, value);
+}
+
+void GraphicsContext3D::getUniformiv(Platform3DObject program, GC3Dint location, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getUniformiv(program, location, value);
+}
+
+long GraphicsContext3D::getUniformLocation(Platform3DObject program, const String& name)
+{
+ ASSERT(program);
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->getUniformLocation(program, name.utf8().data());
+}
+
+void GraphicsContext3D::getVertexAttribfv(GC3Duint index, GC3Denum paramName, GC3Dfloat* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getVertexAttribfv(index, paramName, value);
+}
+
+void GraphicsContext3D::getVertexAttribiv(GC3Duint index, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getVertexAttribiv(index, paramName, value);
+}
+
+GC3Dsizeiptr GraphicsContext3D::getVertexAttribOffset(GC3Duint index, GC3Denum paramName)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLvoid* pointer = 0;
+ m_internal->getVertexAttribPointerv(index, paramName, &pointer);
+ return static_cast<GC3Dsizeiptr>(reinterpret_cast<intptr_t>(pointer));
+}
+
+bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+ return true;
+}
+
+void GraphicsContext3D::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoff, GC3Dint yoff, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels);
+}
+
+Platform3DObject GraphicsContext3D::createBuffer()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle = 0;
+ m_internal->genBuffers(/* count */ 1, &handle);
+ return handle;
+}
+
+Platform3DObject GraphicsContext3D::createFramebuffer()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle = 0;
+ m_internal->genFramebuffers(/* count */ 1, &handle);
+ return handle;
+}
+
+Platform3DObject GraphicsContext3D::createProgram()
+{
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->createProgram();
+}
+
+Platform3DObject GraphicsContext3D::createRenderbuffer()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle = 0;
+ m_internal->genRenderbuffers(/* count */ 1, &handle);
+ return handle;
+}
+
+Platform3DObject GraphicsContext3D::createShader(GC3Denum type)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->createShader(type);
+}
+
+Platform3DObject GraphicsContext3D::createTexture()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle = 0;
+ glGenTextures(1, &handle);
+ return handle;
+}
+
+void GraphicsContext3D::deleteBuffer(Platform3DObject buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteBuffers(1, &buffer);
+}
+
+void GraphicsContext3D::deleteFramebuffer(Platform3DObject framebuffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteFramebuffers(1, &framebuffer);
+}
+
+void GraphicsContext3D::deleteProgram(Platform3DObject program)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteProgram(program);
+}
+
+void GraphicsContext3D::deleteRenderbuffer(Platform3DObject renderbuffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteRenderbuffers(1, &renderbuffer);
+}
+
+void GraphicsContext3D::deleteShader(Platform3DObject shader)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteShader(shader);
+}
+
+void GraphicsContext3D::deleteTexture(Platform3DObject texture)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDeleteTextures(1, &texture);
+}
+
+unsigned int GraphicsContext3D::sizeInBytes(GC3Denum type)
+{
+ switch (type) {
+ case GraphicsContext3D::BYTE:
+ return sizeof(GLbyte);
+ case GraphicsContext3D::UNSIGNED_BYTE:
+ return sizeof(GLubyte);
+ case GraphicsContext3D::SHORT:
+ return sizeof(GLshort);
+ case GraphicsContext3D::UNSIGNED_SHORT:
+ return sizeof(GLushort);
+ case GraphicsContext3D::INT:
+ return sizeof(GLint);
+ case GraphicsContext3D::UNSIGNED_INT:
+ return sizeof(GLuint);
+ case GraphicsContext3D::FLOAT:
+ return sizeof(GLfloat);
+ default:
+ return 0;
+ }
+}
+
+void GraphicsContext3D::synthesizeGLError(GC3Denum error)
+{
+ m_internal->m_syntheticErrors.add(error);
+}
+
+Extensions3D* GraphicsContext3D::getExtensions()
+{
+ if (!m_internal->m_extensions)
+ m_internal->m_extensions = adoptPtr(new Extensions3DQt);
+ return m_internal->m_extensions;
+}
+
+bool GraphicsContext3D::getImageData(Image* image,
+ GC3Denum format,
+ GC3Denum type,
+ bool premultiplyAlpha,
+ bool ignoreGammaAndColorProfile,
+ Vector<uint8_t>& outputVector)
+{
+ UNUSED_PARAM(ignoreGammaAndColorProfile);
+ if (!image)
+ return false;
+ QPixmap* nativePixmap = image->nativeImageForCurrentFrame();
+ if (!nativePixmap)
+ return false;
+
+ AlphaOp neededAlphaOp = kAlphaDoNothing;
+ if (!premultiplyAlpha)
+ // FIXME: must fetch the image data before the premultiplication step
+ neededAlphaOp = kAlphaDoUnmultiply;
+ QImage nativeImage = nativePixmap->toImage().convertToFormat(QImage::Format_ARGB32);
+ outputVector.resize(nativeImage.byteCount());
+ return packPixels(nativeImage.rgbSwapped().bits(), kSourceFormatRGBA8, image->width(), image->height(), 0,
+ format, type, neededAlphaOp, outputVector.data());
+}
+
+}
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
new file mode 100644
index 0000000..e237fc0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -0,0 +1,1370 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org>
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ * Copyright (C) 2010 Sencha, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#ifdef Q_WS_WIN
+#include <windows.h>
+#endif
+
+#include "AffineTransform.h"
+#include "Color.h"
+#include "ContextShadow.h"
+#include "FloatConversion.h"
+#include "Font.h"
+#include "ImageBuffer.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "Pattern.h"
+#include "TransparencyLayer.h"
+
+#include <QBrush>
+#include <QGradient>
+#include <QPaintDevice>
+#include <QPaintEngine>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPixmap>
+#include <QPolygonF>
+#include <QStack>
+#include <QVector>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+namespace WebCore {
+
+QPainter::CompositionMode GraphicsContext::toQtCompositionMode(CompositeOperator op)
+{
+ switch (op) {
+ case CompositeClear:
+ return QPainter::CompositionMode_Clear;
+ case CompositeCopy:
+ return QPainter::CompositionMode_Source;
+ case CompositeSourceOver:
+ return QPainter::CompositionMode_SourceOver;
+ case CompositeSourceIn:
+ return QPainter::CompositionMode_SourceIn;
+ case CompositeSourceOut:
+ return QPainter::CompositionMode_SourceOut;
+ case CompositeSourceAtop:
+ return QPainter::CompositionMode_SourceAtop;
+ case CompositeDestinationOver:
+ return QPainter::CompositionMode_DestinationOver;
+ case CompositeDestinationIn:
+ return QPainter::CompositionMode_DestinationIn;
+ case CompositeDestinationOut:
+ return QPainter::CompositionMode_DestinationOut;
+ case CompositeDestinationAtop:
+ return QPainter::CompositionMode_DestinationAtop;
+ case CompositeXOR:
+ return QPainter::CompositionMode_Xor;
+ case CompositePlusDarker:
+ // there is no exact match, but this is the closest
+ return QPainter::CompositionMode_Darken;
+ case CompositeHighlight:
+ return QPainter::CompositionMode_SourceOver;
+ case CompositePlusLighter:
+ return QPainter::CompositionMode_Plus;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return QPainter::CompositionMode_SourceOver;
+}
+
+static inline Qt::PenCapStyle toQtLineCap(LineCap lc)
+{
+ switch (lc) {
+ case ButtCap:
+ return Qt::FlatCap;
+ case RoundCap:
+ return Qt::RoundCap;
+ case SquareCap:
+ return Qt::SquareCap;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return Qt::FlatCap;
+}
+
+static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj)
+{
+ switch (lj) {
+ case MiterJoin:
+ return Qt::SvgMiterJoin;
+ case RoundJoin:
+ return Qt::RoundJoin;
+ case BevelJoin:
+ return Qt::BevelJoin;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return Qt::SvgMiterJoin;
+}
+
+static Qt::PenStyle toQPenStyle(StrokeStyle style)
+{
+ switch (style) {
+ case NoStroke:
+ return Qt::NoPen;
+ break;
+ case SolidStroke:
+ return Qt::SolidLine;
+ break;
+ case DottedStroke:
+ return Qt::DotLine;
+ break;
+ case DashedStroke:
+ return Qt::DashLine;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return Qt::NoPen;
+}
+
+static inline Qt::FillRule toQtFillRule(WindRule rule)
+{
+ switch (rule) {
+ case RULE_EVENODD:
+ return Qt::OddEvenFill;
+ case RULE_NONZERO:
+ return Qt::WindingFill;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return Qt::OddEvenFill;
+}
+
+class GraphicsContextPlatformPrivate : public Noncopyable {
+public:
+ GraphicsContextPlatformPrivate(QPainter*, const QColor& initialSolidColor);
+ ~GraphicsContextPlatformPrivate();
+
+ inline QPainter* p() const
+ {
+ if (layers.isEmpty())
+ return painter;
+ return &layers.top()->painter;
+ }
+
+ bool antiAliasingForRectsAndLines;
+
+ QStack<TransparencyLayer*> layers;
+ // Counting real layers. Required by inTransparencyLayer() calls
+ // For example, layers with valid alphaMask are not real layers
+ int layerCount;
+
+ // reuse this brush for solid color (to prevent expensive QBrush construction)
+ QBrush solidColor;
+
+ InterpolationQuality imageInterpolationQuality;
+ bool initialSmoothPixmapTransformHint;
+
+ ContextShadow shadow;
+ QStack<ContextShadow> shadowStack;
+
+ QRectF clipBoundingRect() const
+ {
+#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
+ return p()->clipBoundingRect();
+#else
+ return p()->clipRegion().boundingRect();
+#endif
+ }
+
+ void takeOwnershipOfPlatformContext() { platformContextIsOwned = true; }
+
+private:
+ QPainter* painter;
+ bool platformContextIsOwned;
+};
+
+GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p, const QColor& initialSolidColor)
+ : antiAliasingForRectsAndLines(false)
+ , layerCount(0)
+ , solidColor(initialSolidColor)
+ , imageInterpolationQuality(InterpolationDefault)
+ , initialSmoothPixmapTransformHint(false)
+ , painter(p)
+ , platformContextIsOwned(false)
+{
+ if (!painter)
+ return;
+
+ // Use the default the QPainter was constructed with.
+ antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing);
+
+ // Used for default image interpolation quality.
+ initialSmoothPixmapTransformHint = painter->testRenderHint(QPainter::SmoothPixmapTransform);
+
+ painter->setRenderHint(QPainter::Antialiasing, true);
+}
+
+GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
+{
+ if (!platformContextIsOwned)
+ return;
+
+ QPaintDevice* device = painter->device();
+ painter->end();
+ delete painter;
+ delete device;
+}
+
+void GraphicsContext::platformInit(PlatformGraphicsContext* painter)
+{
+ m_data = new GraphicsContextPlatformPrivate(painter, fillColor());
+
+ setPaintingDisabled(!painter);
+
+ if (!painter)
+ return;
+
+ // solidColor is initialized with the fillColor().
+ painter->setBrush(m_data->solidColor);
+
+ QPen pen(painter->pen());
+ pen.setColor(strokeColor());
+ pen.setJoinStyle(toQtLineJoin(MiterJoin));
+ painter->setPen(pen);
+}
+
+void GraphicsContext::platformDestroy()
+{
+ while (!m_data->layers.isEmpty())
+ endTransparencyLayer();
+
+ delete m_data;
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ return m_data->p();
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ const QTransform& matrix = platformContext()->combinedTransform();
+ return AffineTransform(matrix.m11(), matrix.m12(), matrix.m21(),
+ matrix.m22(), matrix.dx(), matrix.dy());
+}
+
+void GraphicsContext::savePlatformState()
+{
+ if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull())
+ ++m_data->layers.top()->saveCounter;
+ m_data->p()->save();
+ m_data->shadowStack.push(m_data->shadow);
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull())
+ if (!--m_data->layers.top()->saveCounter)
+ endTransparencyLayer();
+
+ m_data->p()->restore();
+
+ if (m_data->shadowStack.isEmpty())
+ m_data->shadow = ContextShadow();
+ else
+ m_data->shadow = m_data->shadowStack.pop();
+}
+
+// Draws a filled rectangle with a stroked border.
+// This is only used to draw borders (real fill is done via fillRect), and
+// thus it must not cast any shadow.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
+
+ p->drawRect(rect);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+// This is only used to draw borders.
+// Must not cast any shadow.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle style = strokeStyle();
+ Color color = strokeColor();
+ if (style == NoStroke)
+ return;
+
+ float width = strokeThickness();
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
+
+ QPainter* p = m_data->p();
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
+ adjustLineToPixelBoundaries(p1, p2, width, style);
+
+ int patWidth = 0;
+ switch (style) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DottedStroke:
+ patWidth = static_cast<int>(width);
+ break;
+ case DashedStroke:
+ patWidth = 3 * static_cast<int>(width);
+ break;
+ }
+
+ if (patWidth) {
+ p->save();
+
+ // Do a rect fill of our endpoints. This ensures we always have the
+ // appearance of being a border. We then draw the actual dotted/dashed line.
+ if (isVerticalLine) {
+ p->fillRect(FloatRect(p1.x() - width / 2, p1.y() - width, width, width), QColor(color));
+ p->fillRect(FloatRect(p2.x() - width / 2, p2.y(), width, width), QColor(color));
+ } else {
+ p->fillRect(FloatRect(p1.x() - width, p1.y() - width / 2, width, width), QColor(color));
+ p->fillRect(FloatRect(p2.x(), p2.y() - width / 2, width, width), QColor(color));
+ }
+
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width;
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0f;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0f;
+ else {
+ bool evenNumberOfSegments = !(numSegments % 2);
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2;
+ } else
+ patternOffset = patWidth / 2;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder) / 2;
+ }
+ }
+
+ QVector<qreal> dashes;
+ dashes << qreal(patWidth) / width << qreal(patWidth) / width;
+
+ QPen pen = p->pen();
+ pen.setWidthF(width);
+ pen.setCapStyle(Qt::FlatCap);
+ pen.setDashPattern(dashes);
+ pen.setDashOffset(patternOffset / width);
+ p->setPen(pen);
+ }
+
+ p->drawLine(p1, p2);
+
+ if (patWidth)
+ p->restore();
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->drawEllipse(rect);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (npoints <= 1)
+ return;
+
+ QPolygonF polygon(npoints);
+
+ for (size_t i = 0; i < npoints; i++)
+ polygon[i] = points[i];
+
+ QPainter* p = m_data->p();
+
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, shouldAntialias);
+
+ p->drawConvexPolygon(polygon);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ QPainterPath path(points[0]);
+ for (size_t i = 1; i < numPoints; ++i)
+ path.lineTo(points[i]);
+ path.setFillRule(Qt::WindingFill);
+
+ QPainter* p = m_data->p();
+
+ bool painterWasAntialiased = p->testRenderHint(QPainter::Antialiasing);
+
+ if (painterWasAntialiased != antialiased)
+ p->setRenderHint(QPainter::Antialiasing, antialiased);
+
+ p->setClipPath(path, Qt::IntersectClip);
+
+ if (painterWasAntialiased != antialiased)
+ p->setRenderHint(QPainter::Antialiasing, painterWasAntialiased);
+}
+
+void GraphicsContext::fillPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainterPath platformPath = path.platformPath();
+ platformPath.setFillRule(toQtFillRule(fillRule()));
+
+ if (hasShadow()) {
+ ContextShadow* shadow = contextShadow();
+ if (shadow->mustUseContextShadow(this) || m_state.fillPattern || m_state.fillGradient)
+ {
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, platformPath.controlPointRect());
+ if (shadowPainter) {
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
+ shadowPainter->fillPath(platformPath, QColor(m_data->shadow.m_color));
+ shadow->endShadowLayer(this);
+ }
+ } else {
+ QPointF offset = shadow->offset();
+ p->translate(offset);
+ p->fillPath(platformPath, QColor(shadow->m_color));
+ p->translate(-offset);
+ }
+ }
+ if (m_state.fillPattern) {
+ AffineTransform affine;
+ p->fillPath(platformPath, QBrush(m_state.fillPattern->createPlatformPattern(affine)));
+ } else if (m_state.fillGradient) {
+ QBrush brush(*m_state.fillGradient->platformGradient());
+ brush.setTransform(m_state.fillGradient->gradientSpaceTransform());
+ p->fillPath(platformPath, brush);
+ } else
+ p->fillPath(platformPath, p->brush());
+}
+
+void GraphicsContext::strokePath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen pen(p->pen());
+ QPainterPath platformPath = path.platformPath();
+ platformPath.setFillRule(toQtFillRule(fillRule()));
+
+ if (hasShadow()) {
+ ContextShadow* shadow = contextShadow();
+ if (shadow->mustUseContextShadow(this) || m_state.strokePattern || m_state.strokeGradient)
+ {
+ FloatRect boundingRect = platformPath.controlPointRect();
+ boundingRect.inflate(pen.miterLimit() + pen.widthF());
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, boundingRect);
+ if (shadowPainter) {
+ shadowPainter->setOpacity(static_cast<qreal>(m_data->shadow.m_color.alpha()) / 255);
+ shadowPainter->strokePath(platformPath, pen);
+ shadow->endShadowLayer(this);
+ }
+ } else {
+ QPen shadowPen(pen);
+ shadowPen.setColor(m_data->shadow.m_color);
+ QPointF offset = shadow->offset();
+ p->translate(offset);
+ p->strokePath(platformPath, shadowPen);
+ p->translate(-offset);
+ }
+ }
+
+ if (m_state.strokePattern) {
+ AffineTransform affine;
+ pen.setBrush(QBrush(m_state.strokePattern->createPlatformPattern(affine)));
+ p->setPen(pen);
+ p->strokePath(platformPath, pen);
+ } else if (m_state.strokeGradient) {
+ QBrush brush(*m_state.strokeGradient->platformGradient());
+ brush.setTransform(m_state.strokeGradient->gradientSpaceTransform());
+ pen.setBrush(brush);
+ p->setPen(pen);
+ p->strokePath(platformPath, pen);
+ } else
+ p->strokePath(platformPath, pen);
+}
+
+static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY)
+{
+ // Patterns must be painted so that the top left of the first image is anchored at
+ // the origin of the coordinate space
+ if (image) {
+ int w = image->width();
+ int h = image->height();
+ int startX, startY;
+ QRect r(static_cast<int>(rect.x()), static_cast<int>(rect.y()), static_cast<int>(rect.width()), static_cast<int>(rect.height()));
+
+ // startX, startY is the coordinate of the first image we need to put on the left-top of the rect
+ if (repeatX && repeatY) {
+ // repeat
+ // startX, startY is at the left top side of the left-top of the rect
+ startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
+ startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
+ } else {
+ if (!repeatX && !repeatY) {
+ // no-repeat
+ // only draw the image once at orgin once, check if need to draw
+ QRect imageRect(0, 0, w, h);
+ if (imageRect.intersects(r)) {
+ startX = 0;
+ startY = 0;
+ } else
+ return;
+ } else if (repeatX && !repeatY) {
+ // repeat-x
+ // startY is fixed, but startX change based on the left-top of the rect
+ QRect imageRect(r.x(), 0, r.width(), h);
+ if (imageRect.intersects(r)) {
+ startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
+ startY = 0;
+ } else
+ return;
+ } else {
+ // repeat-y
+ // startX is fixed, but startY change based on the left-top of the rect
+ QRect imageRect(0, r.y(), w, r.height());
+ if (imageRect.intersects(r)) {
+ startX = 0;
+ startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
+ } else
+ return;
+ }
+ }
+
+ int x = startX;
+ int y = startY;
+ do {
+ // repeat Y
+ do {
+ // repeat X
+ QRect imageRect(x, y, w, h);
+ QRect intersectRect = imageRect.intersected(r);
+ QPoint destStart(intersectRect.x(), intersectRect.y());
+ QRect sourceRect(intersectRect.x() - imageRect.x(), intersectRect.y() - imageRect.y(), intersectRect.width(), intersectRect.height());
+
+ p->drawPixmap(destStart, *image, sourceRect);
+ x += w;
+ } while (repeatX && x < r.x() + r.width());
+ x = startX;
+ y += h;
+ } while (repeatY && y < r.y() + r.height());
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QRectF normalizedRect = rect.normalized();
+ ContextShadow* shadow = contextShadow();
+
+ if (m_state.fillPattern) {
+ AffineTransform affine;
+ QBrush brush(m_state.fillPattern->createPlatformPattern(affine));
+ QPixmap* image = m_state.fillPattern->tileImage()->nativeImageForCurrentFrame();
+ QPainter* shadowPainter = hasShadow() ? shadow->beginShadowLayer(this, normalizedRect) : 0;
+ if (shadowPainter) {
+ drawRepeatPattern(shadowPainter, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY());
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn);
+ shadowPainter->fillRect(normalizedRect, shadow->m_color);
+ shadow->endShadowLayer(this);
+ }
+ drawRepeatPattern(p, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY());
+ } else if (m_state.fillGradient) {
+ QBrush brush(*m_state.fillGradient->platformGradient());
+ brush.setTransform(m_state.fillGradient->gradientSpaceTransform());
+ QPainter* shadowPainter = hasShadow() ? shadow->beginShadowLayer(this, normalizedRect) : 0;
+ if (shadowPainter) {
+ shadowPainter->fillRect(normalizedRect, brush);
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn);
+ shadowPainter->fillRect(normalizedRect, shadow->m_color);
+ shadow->endShadowLayer(this);
+ }
+ p->fillRect(normalizedRect, brush);
+ } else {
+ if (hasShadow()) {
+ if (shadow->mustUseContextShadow(this)) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, normalizedRect);
+ if (shadowPainter) {
+ shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255);
+ shadowPainter->fillRect(normalizedRect, p->brush());
+ shadow->endShadowLayer(this);
+ }
+ } else {
+ // Solid rectangle fill with no blur shadow or transformations applied can be done
+ // faster without using the shadow layer at all.
+ QColor shadowColor = shadow->m_color;
+ shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF());
+ p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor);
+ }
+ }
+
+ p->fillRect(normalizedRect, p->brush());
+ }
+}
+
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ m_data->solidColor.setColor(color);
+ QPainter* p = m_data->p();
+ QRectF normalizedRect = rect.normalized();
+
+ if (hasShadow()) {
+ ContextShadow* shadow = contextShadow();
+ if (shadow->mustUseContextShadow(this)) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, normalizedRect);
+ if (shadowPainter) {
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
+ shadowPainter->fillRect(normalizedRect, shadow->m_color);
+ shadow->endShadowLayer(this);
+ }
+ } else
+ p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color);
+ }
+
+ p->fillRect(normalizedRect, m_data->solidColor);
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ Path path;
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ QPainter* p = m_data->p();
+ if (hasShadow()) {
+ ContextShadow* shadow = contextShadow();
+ if (shadow->mustUseContextShadow(this)) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, rect);
+ if (shadowPainter) {
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
+ shadowPainter->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
+ shadow->endShadowLayer(this);
+ }
+ } else {
+ p->translate(m_data->shadow.offset());
+ p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
+ p->translate(-m_data->shadow.offset());
+ }
+ }
+ p->fillPath(path.platformPath(), QColor(color));
+}
+
+bool GraphicsContext::inTransparencyLayer() const
+{
+ return m_data->layerCount;
+}
+
+ContextShadow* GraphicsContext::contextShadow()
+{
+ return &m_data->shadow;
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->setClipRect(rect, Qt::IntersectClip);
+}
+
+void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainterPath platformPath = path.platformPath();
+ platformPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
+ p->setClipPath(platformPath, Qt::IntersectClip);
+}
+
+void drawFocusRingForPath(QPainter* p, const QPainterPath& path, int width, const Color& color, bool antiAliasing)
+{
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, antiAliasing);
+
+ const QPen oldPen = p->pen();
+ const QBrush oldBrush = p->brush();
+
+ QPen nPen = p->pen();
+ nPen.setColor(color);
+ nPen.setWidth(width);
+ p->setBrush(Qt::NoBrush);
+ nPen.setStyle(Qt::SolidLine);
+
+ p->strokePath(path, nPen);
+ p->setBrush(oldBrush);
+ p->setPen(oldPen);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
+{
+ // FIXME: Use 'offset' for something? http://webkit.org/b/49909
+
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ drawFocusRingForPath(m_data->p(), path.platformPath(), width, color, m_data->antiAliasingForRectsAndLines);
+}
+
+/**
+ * Focus ring handling for form controls is not handled here. Qt style in
+ * RenderTheme handles drawing focus on widgets which
+ * need it. It is still handled here for links.
+ */
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ unsigned rectCount = rects.size();
+
+ if (!rects.size())
+ return;
+
+ int radius = (width - 1) / 2;
+ QPainterPath path;
+ for (unsigned i = 0; i < rectCount; ++i) {
+ QRect rect = QRect((rects[i])).adjusted(-offset - radius, -offset - radius, offset + radius, offset + radius);
+ // This is not the most efficient way to add a rect to a path, but if we don't create the tmpPath,
+ // we will end up with ugly lines in between rows of text on anchors with multiple lines.
+ QPainterPath tmpPath;
+ tmpPath.addRoundedRect(rect, radius, radius);
+ path = path.united(tmpPath);
+ }
+
+ drawFocusRingForPath(m_data->p(), path, width, color, m_data->antiAliasingForRectsAndLines);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool)
+{
+ if (paintingDisabled())
+ return;
+
+ IntPoint startPoint = origin;
+ IntPoint endPoint = origin + IntSize(width, 0);
+
+ // If paintengine type is X11 to avoid artifacts
+ // like bug https://bugs.webkit.org/show_bug.cgi?id=42248
+#if defined(Q_WS_X11)
+ QPainter* p = m_data->p();
+ if (p->paintEngine()->type() == QPaintEngine::X11) {
+ // If stroke thickness is odd we need decrease Y coordinate by 1 pixel,
+ // because inside method adjustLineToPixelBoundaries(...), which
+ // called from drawLine(...), Y coordinate will be increased by 0.5f
+ // and then inside Qt painting engine will be rounded to next greater
+ // integer value.
+ float strokeWidth = strokeThickness();
+ if (static_cast<int>(strokeWidth) % 2) {
+ startPoint.setY(startPoint.y() - 1);
+ endPoint.setY(endPoint.y() - 1);
+ }
+ }
+#endif // defined(Q_WS_X11)
+
+ drawLine(startPoint, endPoint);
+}
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint&, int, TextCheckingLineStyle)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ // It is not enough just to round to pixels in device space. The rotation part of the
+ // affine transform matrix to device space can mess with this conversion if we have a
+ // rotating image like the hands of the world clock widget. We just need the scale, so
+ // we get the affine transform matrix and extract the scale.
+ QPainter* painter = platformContext();
+ QTransform deviceTransform = painter->deviceTransform();
+ if (deviceTransform.isIdentity())
+ return frect;
+
+ qreal deviceScaleX = sqrtf(deviceTransform.m11() * deviceTransform.m11() + deviceTransform.m12() * deviceTransform.m12());
+ qreal deviceScaleY = sqrtf(deviceTransform.m21() * deviceTransform.m21() + deviceTransform.m22() * deviceTransform.m22());
+
+ QPoint deviceOrigin(frect.x() * deviceScaleX, frect.y() * deviceScaleY);
+ QPoint deviceLowerRight(frect.right() * deviceScaleX, frect.bottom() * deviceScaleY);
+
+ // Don't let the height or width round to 0 unless either was originally 0
+ if (deviceOrigin.y() == deviceLowerRight.y() && frect.height())
+ deviceLowerRight.setY(deviceLowerRight.y() + 1);
+ if (deviceOrigin.x() == deviceLowerRight.x() && frect.width())
+ deviceLowerRight.setX(deviceLowerRight.x() + 1);
+
+ FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x() / deviceScaleX, deviceOrigin.y() / deviceScaleY);
+ FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x() / deviceScaleX, deviceLowerRight.y() / deviceScaleY);
+ return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
+}
+
+void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace)
+{
+ // Qt doesn't support shadows natively, they are drawn manually in the draw*
+ // functions
+
+ if (m_state.shadowsIgnoreTransforms) {
+ // Meaning that this graphics context is associated with a CanvasRenderingContext
+ // We flip the height since CG and HTML5 Canvas have opposite Y axis
+ m_state.shadowOffset = FloatSize(size.width(), -size.height());
+ m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
+ } else
+ m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
+
+ m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ m_data->shadow.clear();
+}
+
+void GraphicsContext::pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask)
+{
+ QPainter* p = m_data->p();
+ m_data->layers.push(new TransparencyLayer(p, p->transform().mapRect(rect), 1.0, alphaMask));
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ int x, y, w, h;
+ x = y = 0;
+ QPainter* p = m_data->p();
+ const QPaintDevice* device = p->device();
+ w = device->width();
+ h = device->height();
+
+ QRectF clip = m_data->clipBoundingRect();
+ QRectF deviceClip = p->transform().mapRect(clip);
+ x = int(qBound(qreal(0), deviceClip.x(), (qreal)w));
+ y = int(qBound(qreal(0), deviceClip.y(), (qreal)h));
+ w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2);
+ h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2);
+
+ QPixmap emptyAlphaMask;
+ m_data->layers.push(new TransparencyLayer(p, QRect(x, y, w, h), opacity, emptyAlphaMask));
+ ++m_data->layerCount;
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ TransparencyLayer* layer = m_data->layers.pop();
+ if (!layer->alphaMask.isNull()) {
+ layer->painter.resetTransform();
+ layer->painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ layer->painter.drawPixmap(QPoint(), layer->alphaMask);
+ } else
+ --m_data->layerCount; // see the comment for layerCount
+ layer->painter.end();
+
+ QPainter* p = m_data->p();
+ p->save();
+ p->resetTransform();
+ p->setOpacity(layer->opacity);
+ p->drawPixmap(layer->offset, layer->pixmap);
+ p->restore();
+
+ delete layer;
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainter::CompositionMode currentCompositionMode = p->compositionMode();
+ if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ p->setCompositionMode(QPainter::CompositionMode_Source);
+ p->fillRect(rect, Qt::transparent);
+ if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ p->setCompositionMode(currentCompositionMode);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ Path path;
+ path.addRect(rect);
+
+ float previousStrokeThickness = strokeThickness();
+
+ if (lineWidth != previousStrokeThickness)
+ setStrokeThickness(lineWidth);
+
+ strokePath(path);
+
+ if (lineWidth != previousStrokeThickness)
+ setStrokeThickness(previousStrokeThickness);
+}
+
+void GraphicsContext::setLineCap(LineCap lc)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen nPen = p->pen();
+ nPen.setCapStyle(toQtLineCap(lc));
+ p->setPen(nPen);
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ QPainter* p = m_data->p();
+ QPen pen = p->pen();
+ unsigned dashLength = dashes.size();
+ if (dashLength) {
+ QVector<qreal> pattern;
+ unsigned count = dashLength;
+ if (dashLength % 2)
+ count *= 2;
+
+ float penWidth = narrowPrecisionToFloat(double(pen.widthF()));
+ for (unsigned i = 0; i < count; i++)
+ pattern.append(dashes[i % dashLength] / penWidth);
+
+ pen.setDashPattern(pattern);
+ pen.setDashOffset(dashOffset / penWidth);
+ } else
+ pen.setStyle(Qt::SolidLine);
+ p->setPen(pen);
+}
+
+void GraphicsContext::setLineJoin(LineJoin lj)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen nPen = p->pen();
+ nPen.setJoinStyle(toQtLineJoin(lj));
+ p->setPen(nPen);
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen nPen = p->pen();
+ nPen.setMiterLimit(limit);
+ p->setPen(nPen);
+}
+
+void GraphicsContext::setAlpha(float opacity)
+{
+ if (paintingDisabled())
+ return;
+ QPainter* p = m_data->p();
+ p->setOpacity(opacity);
+}
+
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* painter = m_data->p();
+
+ if (!painter->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ return;
+
+ painter->setCompositionMode(toQtCompositionMode(op));
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainterPath clipPath = path.platformPath();
+ clipPath.setFillRule(Qt::WindingFill);
+ m_data->p()->setClipPath(clipPath, Qt::IntersectClip);
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainterPath clippedOut = path.platformPath();
+ QPainterPath newClip;
+ newClip.setFillRule(Qt::OddEvenFill);
+ if (p->hasClipping()) {
+ newClip.addRect(m_data->clipBoundingRect());
+ newClip.addPath(clippedOut);
+ p->setClipPath(newClip, Qt::IntersectClip);
+ } else {
+ QRect windowRect = p->transform().inverted().mapRect(p->window());
+ newClip.addRect(windowRect);
+ newClip.addPath(clippedOut.intersected(newClip));
+ p->setClipPath(newClip);
+ }
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->translate(x, y);
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->rotate(180 / M_PI*radians);
+}
+
+void GraphicsContext::scale(const FloatSize& s)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->scale(s.width(), s.height());
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainterPath newClip;
+ newClip.setFillRule(Qt::OddEvenFill);
+ if (p->hasClipping()) {
+ newClip.addRect(m_data->clipBoundingRect());
+ newClip.addRect(QRect(rect));
+ p->setClipPath(newClip, Qt::IntersectClip);
+ } else {
+ QRect clipOutRect(rect);
+ QRect window = p->transform().inverted().mapRect(p->window());
+ clipOutRect &= window;
+ newClip.addRect(window);
+ newClip.addRect(clipOutRect);
+ p->setClipPath(newClip);
+ }
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
+ int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ clip(rect);
+ QPainterPath path;
+
+ // Add outer ellipse
+ path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height()));
+
+ // Add inner ellipse.
+ path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness,
+ rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
+
+ path.setFillRule(Qt::OddEvenFill);
+
+ QPainter* p = m_data->p();
+
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, true);
+ p->setClipPath(path, Qt::IntersectClip);
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->setWorldTransform(transform, true);
+}
+
+void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen newPen(p->pen());
+ m_data->solidColor.setColor(color);
+ newPen.setBrush(m_data->solidColor);
+ p->setPen(newPen);
+}
+
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle)
+{
+ if (paintingDisabled())
+ return;
+ QPainter* p = m_data->p();
+ QPen newPen(p->pen());
+ newPen.setStyle(toQPenStyle(strokeStyle));
+ p->setPen(newPen);
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+ QPainter* p = m_data->p();
+ QPen newPen(p->pen());
+ newPen.setWidthF(thickness);
+ p->setPen(newPen);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ m_data->solidColor.setColor(color);
+ m_data->p()->setBrush(m_data->solidColor);
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+ m_data->p()->setRenderHint(QPainter::Antialiasing, enable);
+}
+
+#ifdef Q_WS_WIN
+
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true
+ Q_ASSERT(mayCreateBitmap);
+
+ if (dstRect.isEmpty())
+ return 0;
+
+ // Create a bitmap DC in which to draw.
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.bmiHeader.biWidth = dstRect.width();
+ bitmapInfo.bmiHeader.biHeight = dstRect.height();
+ bitmapInfo.bmiHeader.biPlanes = 1;
+ bitmapInfo.bmiHeader.biBitCount = 32;
+ bitmapInfo.bmiHeader.biCompression = BI_RGB;
+ bitmapInfo.bmiHeader.biSizeImage = 0;
+ bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biClrUsed = 0;
+ bitmapInfo.bmiHeader.biClrImportant = 0;
+
+ void* pixels = 0;
+ HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ if (!bitmap)
+ return 0;
+
+ HDC displayDC = ::GetDC(0);
+ HDC bitmapDC = ::CreateCompatibleDC(displayDC);
+ ::ReleaseDC(0, displayDC);
+
+ ::SelectObject(bitmapDC, bitmap);
+
+ // Fill our buffer with clear if we're going to alpha blend.
+ if (supportAlphaBlend) {
+ BITMAP bmpInfo;
+ GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 0, bufferSize);
+ }
+
+#if !OS(WINCE)
+ // Make sure we can do world transforms.
+ SetGraphicsMode(bitmapDC, GM_ADVANCED);
+
+ // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -dstRect.x();
+ xform.eDy = -dstRect.y();
+ ::SetWorldTransform(bitmapDC, &xform);
+#endif
+
+ return bitmapDC;
+}
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true
+ Q_ASSERT(mayCreateBitmap);
+
+ if (hdc) {
+
+ if (!dstRect.isEmpty()) {
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap, supportAlphaBlend ? QPixmap::PremultipliedAlpha : QPixmap::NoAlpha);
+ m_data->p()->drawPixmap(dstRect, pixmap);
+
+ ::DeleteObject(bitmap);
+ }
+
+ ::DeleteDC(hdc);
+ }
+}
+#endif
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality quality)
+{
+ m_data->imageInterpolationQuality = quality;
+
+ switch (quality) {
+ case InterpolationNone:
+ case InterpolationLow:
+ // use nearest-neigbor
+ m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, false);
+ break;
+
+ case InterpolationMedium:
+ case InterpolationHigh:
+ // use the filter
+ m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, true);
+ break;
+
+ case InterpolationDefault:
+ default:
+ m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, m_data->initialSmoothPixmapTransformHint);
+ break;
+ };
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ return m_data->imageInterpolationQuality;
+}
+
+void GraphicsContext::takeOwnershipOfPlatformContext()
+{
+ m_data->takeOwnershipOfPlatformContext();
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
new file mode 100644
index 0000000..f31844a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
@@ -0,0 +1,1779 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "GraphicsLayerQt.h"
+
+#include "CurrentTime.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "RefCounted.h"
+#include "TranslateTransformOperation.h"
+#include "UnitBezier.h"
+#include <QtCore/qabstractanimation.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qset.h>
+#include <QtCore/qtimer.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qgraphicseffect.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qgraphicsview.h>
+#include <QtGui/qgraphicswidget.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qpixmapcache.h>
+#include <QtGui/qstyleoption.h>
+
+#if ENABLE(TILED_BACKING_STORE)
+#include "TiledBackingStore.h"
+#include "TiledBackingStoreClient.h"
+
+// The minimum width/height for tiling. We use the same value as the Windows implementation.
+#define GRAPHICS_LAYER_TILING_THRESHOLD 2000
+#endif
+
+
+#define QT_DEBUG_RECACHE 0
+#define QT_DEBUG_CACHEDUMP 0
+
+#define QT_DEBUG_FPS 0
+
+namespace WebCore {
+
+#ifndef QT_NO_GRAPHICSEFFECT
+class MaskEffectQt : public QGraphicsEffect {
+public:
+ MaskEffectQt(QObject* parent, QGraphicsItem* maskLayer)
+ : QGraphicsEffect(parent)
+ , m_maskLayer(maskLayer)
+ {
+ }
+
+ void draw(QPainter* painter)
+ {
+ // This is a modified clone of QGraphicsOpacityEffect.
+ // It's more efficient to do it this way because:
+ // (a) We don't need the QBrush abstraction - we always end up using QGraphicsItem::paint
+ // from the mask layer.
+ // (b) QGraphicsOpacityEffect detaches the pixmap, which is inefficient on OpenGL.
+ const QSize maskSize = sourceBoundingRect().toAlignedRect().size();
+ if (!maskSize.isValid() || maskSize.isEmpty()) {
+ drawSource(painter);
+ return;
+ }
+ QPixmap maskPixmap(maskSize);
+
+ // We need to do this so the pixmap would have hasAlpha().
+ maskPixmap.fill(Qt::transparent);
+ QPainter maskPainter(&maskPixmap);
+ QStyleOptionGraphicsItem option;
+ option.exposedRect = option.rect = maskPixmap.rect();
+ maskPainter.setRenderHints(painter->renderHints(), true);
+ m_maskLayer->paint(&maskPainter, &option, 0);
+ maskPainter.end();
+
+ QPoint offset;
+ QPixmap srcPixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, QGraphicsEffect::NoPad);
+
+ // We have to use another intermediate pixmap, to make sure the mask applies only to this item
+ // and doesn't modify pixels already painted into this paint-device.
+ QPixmap pixmap(srcPixmap.size());
+ pixmap.fill(Qt::transparent);
+
+ if (pixmap.isNull())
+ return;
+
+ QPainter pixmapPainter(&pixmap);
+
+ pixmapPainter.setRenderHints(painter->renderHints());
+ pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
+
+ // We use drawPixmap rather than detaching, because it's more efficient on OpenGL.
+ pixmapPainter.drawPixmap(0, 0, srcPixmap);
+ pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ pixmapPainter.drawPixmap(0, 0, maskPixmap);
+
+ pixmapPainter.end();
+ painter->drawPixmap(offset, pixmap);
+ }
+
+ QGraphicsItem* m_maskLayer;
+};
+#endif // QT_NO_GRAPHICSEFFECT
+
+class GraphicsLayerQtImpl : public QGraphicsObject
+#if ENABLE(TILED_BACKING_STORE)
+, public virtual TiledBackingStoreClient
+#endif
+{
+ Q_OBJECT
+
+public:
+ // This set of flags help us defer which properties of the layer have been
+ // modified by the compositor, so we can know what to look for in the next flush.
+ enum ChangeMask {
+ NoChanges = 0,
+
+ ParentChange = (1L << 0),
+ ChildrenChange = (1L << 1),
+ MaskLayerChange = (1L << 2),
+ PositionChange = (1L << 3),
+
+ AnchorPointChange = (1L << 4),
+ SizeChange = (1L << 5),
+ TransformChange = (1L << 6),
+ ContentChange = (1L << 7),
+
+ ContentsOrientationChange = (1L << 8),
+ OpacityChange = (1L << 9),
+ ContentsRectChange = (1L << 10),
+
+ Preserves3DChange = (1L << 11),
+ MasksToBoundsChange = (1L << 12),
+ DrawsContentChange = (1L << 13),
+ ContentsOpaqueChange = (1L << 14),
+
+ BackfaceVisibilityChange = (1L << 15),
+ ChildrenTransformChange = (1L << 16),
+ DisplayChange = (1L << 17),
+ BackgroundColorChange = (1L << 18),
+
+ DistributesOpacityChange = (1L << 19)
+ };
+
+ // The compositor lets us special-case images and colors, so we try to do so.
+ enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType, MediaContentType, Canvas3DContentType};
+
+ const GraphicsLayerQtImpl* rootLayer() const;
+
+ GraphicsLayerQtImpl(GraphicsLayerQt* newLayer);
+ virtual ~GraphicsLayerQtImpl();
+
+ // reimps from QGraphicsItem
+ virtual QPainterPath opaqueArea() const;
+ virtual QRectF boundingRect() const;
+ virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);
+
+ // We manage transforms ourselves because transform-origin acts differently in webkit and in Qt,
+ // and we need it as a fallback in case we encounter an un-invertible matrix.
+ void setBaseTransform(const TransformationMatrix&);
+ void updateTransform();
+
+ // let the compositor-API tell us which properties were changed
+ void notifyChange(ChangeMask);
+
+ // Actual rendering of the web-content into a QPixmap:
+ // We prefer to use our own caching because it gives us a higher level of granularity than
+ // QGraphicsItem cache modes - Sometimes we need to cache the contents even though the item
+ // needs to be updated, e.g. when the background-color is changed.
+ // TODO: investigate if QGraphicsItem caching can be improved to support that out of the box.
+ QPixmap recache(const QRegion&);
+
+ // Called when the compositor is ready for us to show the changes on screen.
+ // This is called indirectly from ChromeClientQt::setNeedsOneShotDrawingSynchronization
+ // (meaning the sync would happen together with the next draw) or
+ // ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP)
+ void flushChanges(bool recursive = true, bool forceTransformUpdate = false);
+
+#if ENABLE(TILED_BACKING_STORE)
+ // reimplementations from TiledBackingStoreClient
+ virtual void tiledBackingStorePaintBegin();
+ virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&);
+ virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea);
+ virtual IntRect tiledBackingStoreContentsRect();
+ virtual IntRect tiledBackingStoreVisibleRect();
+ virtual Color tiledBackingStoreBackgroundColor() const;
+#endif
+
+public slots:
+ // We need to notify the client (ie. the layer compositor) when the animation actually starts.
+ void notifyAnimationStarted();
+
+ // We notify WebCore of a layer changed asynchronously; otherwise we end up calling flushChanges too often.
+ void notifySyncRequired();
+
+signals:
+ // Optimization: Avoid using QTimer::singleShot().
+ void notifyAnimationStartedAsync();
+
+public:
+ GraphicsLayerQt* m_layer;
+
+ TransformationMatrix m_baseTransform;
+ TransformationMatrix m_transformRelativeToRootLayer;
+ bool m_transformAnimationRunning;
+ bool m_opacityAnimationRunning;
+ bool m_blockNotifySyncRequired;
+#ifndef QT_NO_GRAPHICSEFFECT
+ QWeakPointer<MaskEffectQt> m_maskEffect;
+#endif
+
+ struct ContentData {
+ QPixmap pixmap;
+ QRegion regionToUpdate;
+ bool updateAll;
+
+ QColor contentsBackgroundColor;
+ QColor backgroundColor;
+
+ QWeakPointer<QGraphicsObject> mediaLayer;
+ StaticContentType contentType;
+
+ float opacity;
+
+ ContentData()
+ : updateAll(false)
+ , contentType(HTMLContentType)
+ , opacity(1.f)
+ {
+ }
+
+ };
+
+ ContentData m_pendingContent;
+ ContentData m_currentContent;
+
+ int m_changeMask;
+
+#if ENABLE(TILED_BACKING_STORE)
+ TiledBackingStore* m_tiledBackingStore;
+#endif
+
+ QSizeF m_size;
+ struct {
+ QPixmapCache::Key key;
+ QSizeF size;
+ } m_backingStore;
+#ifndef QT_NO_ANIMATION
+ QList<QWeakPointer<QAbstractAnimation> > m_animations;
+#endif
+ QTimer m_suspendTimer;
+
+ struct State {
+ GraphicsLayer* maskLayer;
+ FloatPoint pos;
+ FloatPoint3D anchorPoint;
+ FloatSize size;
+ TransformationMatrix transform;
+ TransformationMatrix childrenTransform;
+ Color backgroundColor;
+ Color currentColor;
+ GraphicsLayer::CompositingCoordinatesOrientation contentsOrientation;
+ float opacity;
+ QRect contentsRect;
+
+ bool preserves3D: 1;
+ bool masksToBounds: 1;
+ bool drawsContent: 1;
+ bool contentsOpaque: 1;
+ bool backfaceVisibility: 1;
+ bool distributeOpacity: 1;
+ bool align: 2;
+
+ State()
+ : maskLayer(0)
+ , opacity(1.f)
+ , preserves3D(false)
+ , masksToBounds(false)
+ , drawsContent(false)
+ , contentsOpaque(false)
+ , backfaceVisibility(false)
+ , distributeOpacity(false)
+ {
+ }
+ } m_state;
+
+#if ENABLE(3D_CANVAS)
+ const GraphicsContext3D* m_gc3D;
+#endif
+
+#ifndef QT_NO_ANIMATION
+ friend class AnimationQtBase;
+#endif
+};
+
+inline GraphicsLayerQtImpl* toGraphicsLayerQtImpl(QGraphicsItem* item)
+{
+ ASSERT(item);
+ return qobject_cast<GraphicsLayerQtImpl*>(item->toGraphicsObject());
+}
+
+inline GraphicsLayerQtImpl* toGraphicsLayerQtImpl(QGraphicsObject* item)
+{
+ return qobject_cast<GraphicsLayerQtImpl*>(item);
+}
+
+GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
+ : QGraphicsObject(0)
+ , m_layer(newLayer)
+ , m_transformAnimationRunning(false)
+ , m_opacityAnimationRunning(false)
+ , m_blockNotifySyncRequired(false)
+ , m_changeMask(NoChanges)
+#if ENABLE(TILED_BACKING_STORE)
+ , m_tiledBackingStore(0)
+#endif
+#if ENABLE(3D_CANVAS)
+ , m_gc3D(0)
+#endif
+{
+ // We use graphics-view for compositing-only, not for interactivity.
+ setAcceptedMouseButtons(Qt::NoButton);
+
+ // We need to have the item enabled, or else wheel events are not passed to the parent class
+ // implementation of wheelEvent, where they are ignored and passed to the item below.
+ setEnabled(true);
+
+ connect(this, SIGNAL(notifyAnimationStartedAsync()), this, SLOT(notifyAnimationStarted()), Qt::QueuedConnection);
+}
+
+GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
+{
+ // The compositor manages lifecycle of item, so we do not want the graphicsview system to delete
+ // our items automatically.
+ const QList<QGraphicsItem*> children = childItems();
+ QList<QGraphicsItem*>::const_iterator cit;
+ for (cit = children.constBegin(); cit != children.constEnd(); ++cit) {
+ if (QGraphicsItem* item = *cit) {
+ if (scene())
+ scene()->removeItem(item);
+ item->setParentItem(0);
+ }
+ }
+#if ENABLE(TILED_BACKING_STORE)
+ delete m_tiledBackingStore;
+#endif
+#ifndef QT_NO_ANIMATION
+ // We do, however, own the animations.
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_animations.begin(); it != m_animations.end(); ++it)
+ if (QAbstractAnimation* anim = it->data())
+ delete anim;
+#endif
+}
+
+const GraphicsLayerQtImpl* GraphicsLayerQtImpl::rootLayer() const
+{
+ if (const GraphicsLayerQtImpl* parent = toGraphicsLayerQtImpl(parentObject()))
+ return parent->rootLayer();
+ return this;
+}
+
+QPixmap GraphicsLayerQtImpl::recache(const QRegion& regionToUpdate)
+{
+ if (!m_layer->drawsContent() || m_size.isEmpty() || !m_size.isValid())
+ return QPixmap();
+
+#if ENABLE(TILED_BACKING_STORE)
+ const bool requiresTiling = (m_state.drawsContent && m_currentContent.contentType == HTMLContentType) && (m_size.width() > GRAPHICS_LAYER_TILING_THRESHOLD || m_size.height() > GRAPHICS_LAYER_TILING_THRESHOLD);
+ if (requiresTiling && !m_tiledBackingStore) {
+ m_tiledBackingStore = new TiledBackingStore(this);
+ m_tiledBackingStore->setTileCreationDelay(0);
+ setFlag(ItemUsesExtendedStyleOption, true);
+ } else if (!requiresTiling && m_tiledBackingStore) {
+ delete m_tiledBackingStore;
+ m_tiledBackingStore = 0;
+ setFlag(ItemUsesExtendedStyleOption, false);
+ }
+
+ if (m_tiledBackingStore) {
+ m_tiledBackingStore->adjustVisibleRect();
+ const QVector<QRect> rects = regionToUpdate.rects();
+ for (int i = 0; i < rects.size(); ++i)
+ m_tiledBackingStore->invalidate(rects[i]);
+ return QPixmap();
+ }
+#endif
+
+ QPixmap pixmap;
+ QRegion region = regionToUpdate;
+ if (QPixmapCache::find(m_backingStore.key, &pixmap)) {
+ if (region.isEmpty())
+ return pixmap;
+ QPixmapCache::remove(m_backingStore.key); // Remove the reference to the pixmap in the cache to avoid a detach.
+ }
+
+ {
+ bool erased = false;
+
+ // If the pixmap is not in the cache or the view has grown since last cached.
+ if (pixmap.isNull() || m_size != m_backingStore.size) {
+#if QT_DEBUG_RECACHE
+ if (pixmap.isNull())
+ qDebug() << "CacheMiss" << this << m_size;
+#endif
+ bool fill = true;
+ QRegion newRegion;
+ QPixmap oldPixmap = pixmap;
+
+ // If the pixmap is two small to hold the view contents we enlarge, otherwise just use the old (large) pixmap.
+ if (pixmap.width() < m_size.width() || pixmap.height() < m_size.height()) {
+#if QT_DEBUG_RECACHE
+ qDebug() << "CacheGrow" << this << m_size;
+#endif
+ pixmap = QPixmap(m_size.toSize());
+ pixmap.fill(Qt::transparent);
+ newRegion = QRegion(0, 0, m_size.width(), m_size.height());
+ }
+
+#if 1
+ // Blit the contents of oldPixmap back into the cached pixmap as we are just adding new pixels.
+ if (!oldPixmap.isNull()) {
+ const QRegion cleanRegion = (QRegion(0, 0, m_size.width(), m_size.height())
+ & QRegion(0, 0, m_backingStore.size.width(), m_backingStore.size.height())) - regionToUpdate;
+ if (!cleanRegion.isEmpty()) {
+#if QT_DEBUG_RECACHE
+ qDebug() << "CacheBlit" << this << cleanRegion;
+#endif
+ const QRect cleanBounds(cleanRegion.boundingRect());
+ QPainter painter(&pixmap);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.drawPixmap(cleanBounds.topLeft(), oldPixmap, cleanBounds);
+ newRegion -= cleanRegion;
+ fill = false; // We cannot just fill the pixmap.
+ }
+ oldPixmap = QPixmap();
+ }
+#endif
+ region += newRegion;
+ if (fill && !region.isEmpty()) { // Clear the entire pixmap with the background.
+#if QT_DEBUG_RECACHE
+ qDebug() << "CacheErase" << this << m_size << background;
+#endif
+ erased = true;
+ pixmap.fill(Qt::transparent);
+ }
+ }
+ region &= QRegion(0, 0, m_size.width(), m_size.height());
+
+ // If we have something to draw its time to erase it and render the contents.
+ if (!region.isEmpty()) {
+#if QT_DEBUG_CACHEDUMP
+ static int recacheCount = 0;
+ ++recacheCount;
+ qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size;
+ pixmap.save(QString().sprintf("/tmp/%05d_A.png", recacheCount), "PNG");
+#endif
+
+ QPainter painter(&pixmap);
+ GraphicsContext gc(&painter);
+
+ painter.setClipRegion(region);
+
+ if (!erased) { // Erase the area in cache that we're drawing into.
+ painter.setCompositionMode(QPainter::CompositionMode_Clear);
+ painter.fillRect(region.boundingRect(), Qt::transparent);
+
+#if QT_DEBUG_CACHEDUMP
+ qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size;
+ pixmap.save(QString().sprintf("/tmp/%05d_B.png", recacheCount), "PNG");
+#endif
+ }
+
+ // Render the actual contents into the cache.
+ painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ m_layer->paintGraphicsLayerContents(gc, region.boundingRect());
+ painter.end();
+
+#if QT_DEBUG_CACHEDUMP
+ qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size;
+ pixmap.save(QString().sprintf("/tmp/%05d_C.png", recacheCount), "PNG");
+#endif
+ }
+ m_backingStore.size = m_size; // Store the used size of the pixmap.
+ }
+
+ // Finally insert into the cache and allow a reference there.
+ m_backingStore.key = QPixmapCache::insert(pixmap);
+ return pixmap;
+}
+
+void GraphicsLayerQtImpl::updateTransform()
+{
+ if (!m_transformAnimationRunning)
+ m_baseTransform = m_layer->transform();
+
+ TransformationMatrix localTransform;
+
+ GraphicsLayerQtImpl* parent = toGraphicsLayerQtImpl(parentObject());
+
+ // WebCore has relative-to-size originPoint, where as the QGraphicsView has a pixel originPoint.
+ // Thus, we need to convert here as we have to manage this outselves due to the fact that the
+ // transformOrigin of the graphicsview is imcompatible.
+ const qreal originX = m_state.anchorPoint.x() * m_size.width();
+ const qreal originY = m_state.anchorPoint.y() * m_size.height();
+
+ // We ignore QGraphicsItem::pos completely, and use transforms only, due to the fact that we
+ // have to maintain that ourselves for 3D.
+ localTransform
+ .translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z())
+ .multLeft(m_baseTransform)
+ .translate3d(-originX, -originY, -m_state.anchorPoint.z());
+
+ // This is the actual 3D transform of this item, with the ancestors' transform baked in.
+ m_transformRelativeToRootLayer = TransformationMatrix(parent ? parent->m_transformRelativeToRootLayer : TransformationMatrix())
+ .multLeft(localTransform);
+
+ // Now we have enough information to determine if the layer is facing backwards.
+ if (!m_state.backfaceVisibility && m_transformRelativeToRootLayer.inverse().m33() < 0) {
+ setVisible(false);
+ // No point in making extra calculations for invisible elements.
+ return;
+ }
+
+ // The item is front-facing or backface-visibility is on.
+ setVisible(true);
+
+ // Flatten to 2D-space of this item if it doesn't preserve 3D.
+ if (!m_state.preserves3D) {
+ m_transformRelativeToRootLayer.setM13(0);
+ m_transformRelativeToRootLayer.setM23(0);
+ m_transformRelativeToRootLayer.setM31(0);
+ m_transformRelativeToRootLayer.setM32(0);
+ m_transformRelativeToRootLayer.setM33(1);
+ m_transformRelativeToRootLayer.setM34(0);
+ m_transformRelativeToRootLayer.setM43(0);
+ }
+
+ // Apply perspective for the use of this item's children. Perspective is always applied from the item's
+ // center.
+ if (!m_state.childrenTransform.isIdentity()) {
+ m_transformRelativeToRootLayer
+ .translate(m_size.width() / 2, m_size.height() /2)
+ .multLeft(m_state.childrenTransform)
+ .translate(-m_size.width() / 2, -m_size.height() /2);
+ }
+
+ bool inverseOk = true;
+ // Use QTransform::inverse to extrapolate the relative transform of this item, based on the parent's
+ // transform relative to the root layer and the desired transform for this item relative to the root layer.
+ const QTransform parentTransform = parent ? parent->itemTransform(rootLayer()) : QTransform();
+ const QTransform transform2D = QTransform(m_transformRelativeToRootLayer) * parentTransform.inverted(&inverseOk);
+
+ // In rare cases the transformation cannot be inversed - in that case we don't apply the transformation at
+ // all, otherwise we'd flicker. FIXME: This should be amended when Qt moves to a real 3D scene-graph.
+ if (!inverseOk)
+ return;
+
+ setTransform(transform2D);
+
+ const QList<QGraphicsItem*> children = childItems();
+ QList<QGraphicsItem*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it)
+ if (GraphicsLayerQtImpl* layer= toGraphicsLayerQtImpl(*it))
+ layer->updateTransform();
+}
+
+void GraphicsLayerQtImpl::setBaseTransform(const TransformationMatrix& baseTransform)
+{
+ m_baseTransform = baseTransform;
+ updateTransform();
+}
+
+QPainterPath GraphicsLayerQtImpl::opaqueArea() const
+{
+ QPainterPath painterPath;
+
+ // We try out best to return the opaque area, maybe it will help graphics-view render less items.
+ if (m_currentContent.backgroundColor.isValid() && m_currentContent.backgroundColor.alpha() == 0xff)
+ painterPath.addRect(boundingRect());
+ else {
+ if (m_state.contentsOpaque
+ || (m_currentContent.contentType == ColorContentType && m_currentContent.contentsBackgroundColor.alpha() == 0xff)
+ || (m_currentContent.contentType == MediaContentType)
+ || (m_currentContent.contentType == PixmapContentType && !m_currentContent.pixmap.hasAlpha())) {
+ painterPath.addRect(m_state.contentsRect);
+ }
+ }
+ return painterPath;
+}
+
+QRectF GraphicsLayerQtImpl::boundingRect() const
+{
+ return QRectF(QPointF(0, 0), QSizeF(m_size));
+}
+
+void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+{
+#if ENABLE(TILED_BACKING_STORE)
+ // FIXME: There's currently no Qt API to know if a new region of an item is exposed outside of the paint event.
+ // Suggested for Qt: http://bugreports.qt.nokia.com/browse/QTBUG-14877.
+ if (m_tiledBackingStore)
+ m_tiledBackingStore->adjustVisibleRect();
+#endif
+
+ if (m_currentContent.backgroundColor.isValid())
+ painter->fillRect(option->exposedRect, QColor(m_currentContent.backgroundColor));
+
+ switch (m_currentContent.contentType) {
+ case HTMLContentType:
+ if (m_state.drawsContent) {
+ QPixmap backingStore;
+ // We might need to recache, in case we try to paint and the cache was purged (e.g. if it was full).
+ if (!QPixmapCache::find(m_backingStore.key, &backingStore) || backingStore.size() != m_size.toSize())
+ backingStore = recache(QRegion(m_state.contentsRect));
+ const QRectF bounds(0, 0, m_backingStore.size.width(), m_backingStore.size.height());
+ painter->drawPixmap(0, 0, backingStore);
+ }
+ break;
+ case PixmapContentType:
+ painter->drawPixmap(m_state.contentsRect, m_currentContent.pixmap);
+ break;
+ case ColorContentType:
+ painter->fillRect(m_state.contentsRect, m_currentContent.contentsBackgroundColor);
+ break;
+ case MediaContentType:
+ // we don't need to paint anything: we have a QGraphicsItem from the media element
+ break;
+#if ENABLE(3D_CANVAS)
+ case Canvas3DContentType:
+ m_gc3D->paint(painter, option->rect);
+ break;
+#endif
+ }
+}
+
+void GraphicsLayerQtImpl::notifySyncRequired()
+{
+ m_blockNotifySyncRequired = false;
+
+ if (m_layer->client())
+ m_layer->client()->notifySyncRequired(m_layer);
+}
+
+void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
+{
+ m_changeMask |= changeMask;
+
+ if (m_blockNotifySyncRequired)
+ return;
+
+ static QMetaMethod syncMethod = staticMetaObject.method(staticMetaObject.indexOfMethod("notifySyncRequired()"));
+ syncMethod.invoke(this, Qt::QueuedConnection);
+
+ m_blockNotifySyncRequired = true;
+}
+
+void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform)
+{
+ // This is the bulk of the work. understanding what the compositor is trying to achieve, what
+ // graphicsview can do, and trying to find a sane common-ground.
+ if (!m_layer || m_changeMask == NoChanges)
+ goto afterLayerChanges;
+
+ if (m_changeMask & ParentChange) {
+ // The WebCore compositor manages item ownership. We have to make sure graphicsview doesn't
+ // try to snatch that ownership.
+ if (!m_layer->parent() && !parentItem())
+ setParentItem(0);
+ else if (m_layer && m_layer->parent() && m_layer->parent()->platformLayer() != parentItem())
+ setParentItem(m_layer->parent()->platformLayer());
+ }
+
+ if (m_changeMask & ChildrenChange) {
+ // We basically do an XOR operation on the list of current children and the list of wanted
+ // children, and remove/add.
+ QSet<QGraphicsItem*> newChildren;
+ const Vector<GraphicsLayer*> newChildrenVector = (m_layer->children());
+ newChildren.reserve(newChildrenVector.size());
+
+ for (size_t i = 0; i < newChildrenVector.size(); ++i)
+ newChildren.insert(newChildrenVector[i]->platformLayer());
+
+ const QSet<QGraphicsItem*> currentChildren = childItems().toSet();
+ const QSet<QGraphicsItem*> childrenToAdd = newChildren - currentChildren;
+ const QSet<QGraphicsItem*> childrenToRemove = currentChildren - newChildren;
+
+ QSet<QGraphicsItem*>::const_iterator it;
+ for (it = childrenToAdd.constBegin(); it != childrenToAdd.constEnd(); ++it) {
+ if (QGraphicsItem* w = *it)
+ w->setParentItem(this);
+ }
+
+ QSet<QGraphicsItem*>::const_iterator rit;
+ for (rit = childrenToRemove.constBegin(); rit != childrenToRemove.constEnd(); ++rit) {
+ if (GraphicsLayerQtImpl* w = toGraphicsLayerQtImpl(*rit))
+ w->setParentItem(0);
+ }
+
+ // Children are ordered by z-value, let graphicsview know.
+ for (size_t i = 0; i < newChildrenVector.size(); ++i) {
+ if (newChildrenVector[i]->platformLayer())
+ newChildrenVector[i]->platformLayer()->setZValue(i);
+ }
+ }
+
+ if (m_changeMask & MaskLayerChange) {
+ // We can't paint here, because we don't know if the mask layer itself is ready... we'll have
+ // to wait till this layer tries to paint.
+ setFlag(ItemClipsChildrenToShape, m_layer->maskLayer() || m_layer->masksToBounds());
+#ifndef QT_NO_GRAPHICSEFFECT
+ setGraphicsEffect(0);
+ if (m_layer->maskLayer()) {
+ if (GraphicsLayerQtImpl* mask = toGraphicsLayerQtImpl(m_layer->maskLayer()->platformLayer())) {
+ mask->m_maskEffect = new MaskEffectQt(this, mask);
+ setGraphicsEffect(mask->m_maskEffect.data());
+ }
+ }
+#endif
+ }
+
+ if (m_changeMask & SizeChange) {
+ if (m_layer->size() != m_state.size) {
+ prepareGeometryChange();
+ m_size = QSizeF(m_layer->size().width(), m_layer->size().height());
+ }
+ }
+
+ // FIXME: This is a hack, due to a probable QGraphicsScene bug when rapidly modifying the perspective
+ // but without this line we get graphic artifacts.
+ if ((m_changeMask & ChildrenTransformChange) && m_state.childrenTransform != m_layer->childrenTransform())
+ if (scene())
+ scene()->update();
+
+ if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | BackfaceVisibilityChange | PositionChange | ParentChange)) {
+ // Due to the differences between the way WebCore handles transforms and the way Qt handles transforms,
+ // all these elements affect the transforms of all the descendants.
+ forceUpdateTransform = true;
+ }
+
+ if (m_changeMask & (ContentChange | DrawsContentChange | MaskLayerChange)) {
+ switch (m_pendingContent.contentType) {
+ case PixmapContentType:
+ update();
+ setFlag(ItemHasNoContents, false);
+ break;
+
+ case MediaContentType:
+ setFlag(ItemHasNoContents, true);
+ m_pendingContent.mediaLayer.data()->setParentItem(this);
+ break;
+
+ case ColorContentType:
+ if (m_pendingContent.contentType != m_currentContent.contentType
+ || m_pendingContent.contentsBackgroundColor != m_currentContent.contentsBackgroundColor)
+ update();
+ m_state.drawsContent = false;
+ setFlag(ItemHasNoContents, false);
+
+ // Only use ItemUsesExtendedStyleOption for HTML content as colors don't gain much from that.
+ setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
+ break;
+
+ case HTMLContentType:
+ if (m_pendingContent.contentType != m_currentContent.contentType)
+ update();
+ if (!m_state.drawsContent && m_layer->drawsContent())
+ update();
+
+ setFlag(ItemHasNoContents, !m_layer->drawsContent());
+ break;
+
+#if ENABLE(3D_CANVAS)
+ case Canvas3DContentType:
+ if (m_pendingContent.contentType != m_currentContent.contentType)
+ update();
+
+ setCacheMode(NoCache);
+ setFlag(ItemHasNoContents, false);
+ break;
+#endif
+ }
+ }
+
+ if ((m_changeMask & OpacityChange) && m_state.opacity != m_layer->opacity() && !m_opacityAnimationRunning)
+ setOpacity(m_layer->opacity());
+
+ if (m_changeMask & ContentsRectChange) {
+ const QRect rect(m_layer->contentsRect());
+ if (m_state.contentsRect != rect) {
+ m_state.contentsRect = rect;
+ if (m_pendingContent.mediaLayer) {
+ QGraphicsWidget* widget = qobject_cast<QGraphicsWidget*>(m_pendingContent.mediaLayer.data());
+ if (widget)
+ widget->setGeometry(rect);
+ }
+ update();
+ }
+ }
+
+ if ((m_changeMask & MasksToBoundsChange) && m_state.masksToBounds != m_layer->masksToBounds()) {
+ setFlag(QGraphicsItem::ItemClipsToShape, m_layer->masksToBounds());
+ setFlag(QGraphicsItem::ItemClipsChildrenToShape, m_layer->masksToBounds());
+ }
+
+ if ((m_changeMask & ContentsOpaqueChange) && m_state.contentsOpaque != m_layer->contentsOpaque())
+ prepareGeometryChange();
+
+#ifndef QT_NO_GRAPHICSEFFECT
+ if (m_maskEffect)
+ m_maskEffect.data()->update();
+ else
+#endif
+ if (m_changeMask & DisplayChange) {
+#ifndef QT_GRAPHICS_LAYER_NO_RECACHE_ON_DISPLAY_CHANGE
+ // Recache now: all the content is ready and we don't want to wait until the paint event.
+ // We only need to do this for HTML content, there's no point in caching directly composited
+ // content like images or solid rectangles.
+ if (m_pendingContent.contentType == HTMLContentType)
+ recache(m_pendingContent.regionToUpdate);
+#endif
+ update(m_pendingContent.regionToUpdate.boundingRect());
+ m_pendingContent.regionToUpdate = QRegion();
+ }
+
+ if ((m_changeMask & BackgroundColorChange)
+ && (m_pendingContent.backgroundColor != m_currentContent.backgroundColor))
+ update();
+
+ m_state.maskLayer = m_layer->maskLayer();
+ m_state.pos = m_layer->position();
+ m_state.anchorPoint = m_layer->anchorPoint();
+ m_state.size = m_layer->size();
+ m_state.transform = m_layer->transform();
+ m_state.contentsOrientation =m_layer->contentsOrientation();
+ m_state.opacity = m_layer->opacity();
+ m_state.contentsRect = m_layer->contentsRect();
+ m_state.preserves3D = m_layer->preserves3D();
+ m_state.masksToBounds = m_layer->masksToBounds();
+ m_state.drawsContent = m_layer->drawsContent();
+ m_state.contentsOpaque = m_layer->contentsOpaque();
+ m_state.backfaceVisibility = m_layer->backfaceVisibility();
+ m_state.childrenTransform = m_layer->childrenTransform();
+ m_currentContent.pixmap = m_pendingContent.pixmap;
+ m_currentContent.contentType = m_pendingContent.contentType;
+ m_currentContent.mediaLayer = m_pendingContent.mediaLayer;
+ m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
+ m_currentContent.contentsBackgroundColor = m_pendingContent.contentsBackgroundColor;
+ m_pendingContent.regionToUpdate = QRegion();
+ m_changeMask = NoChanges;
+
+afterLayerChanges:
+ if (forceUpdateTransform)
+ updateTransform();
+
+ if (!recursive)
+ return;
+
+ QList<QGraphicsItem*> children = childItems();
+ if (m_state.maskLayer)
+ children.append(m_state.maskLayer->platformLayer());
+
+ QList<QGraphicsItem*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ if (QGraphicsItem* item = *it) {
+ if (GraphicsLayerQtImpl* layer = toGraphicsLayerQtImpl(item))
+ layer->flushChanges(true, forceUpdateTransform);
+ }
+ }
+}
+
+#if ENABLE(TILED_BACKING_STORE)
+/* \reimp (TiledBackingStoreClient.h)
+*/
+void GraphicsLayerQtImpl::tiledBackingStorePaintBegin()
+{
+}
+
+/* \reimp (TiledBackingStoreClient.h)
+*/
+void GraphicsLayerQtImpl::tiledBackingStorePaint(GraphicsContext* gc, const IntRect& rect)
+{
+ m_layer->paintGraphicsLayerContents(*gc, rect);
+}
+
+/* \reimp (TiledBackingStoreClient.h)
+*/
+void GraphicsLayerQtImpl::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
+{
+ for (int i = 0; i < paintedArea.size(); ++i)
+ update(QRectF(paintedArea[i]));
+}
+
+/* \reimp (TiledBackingStoreClient.h)
+*/
+IntRect GraphicsLayerQtImpl::tiledBackingStoreContentsRect()
+{
+ return m_layer->contentsRect();
+}
+
+/* \reimp (TiledBackingStoreClient.h)
+*/
+Color GraphicsLayerQtImpl::tiledBackingStoreBackgroundColor() const
+{
+ if (m_currentContent.contentType == PixmapContentType && !m_currentContent.pixmap.hasAlphaChannel())
+ return Color(0, 0, 0);
+ // We return a transparent color so that the tiles initialize with alpha.
+ return Color(0, 0, 0, 0);
+}
+
+IntRect GraphicsLayerQtImpl::tiledBackingStoreVisibleRect()
+{
+ const QGraphicsView* view = scene()->views().isEmpty() ? 0 : scene()->views().first();
+ if (!view)
+ return mapFromScene(scene()->sceneRect()).boundingRect().toAlignedRect();
+
+ // All we get is the viewport's visible region. We have to map it to the scene and then to item coordinates.
+ return mapFromScene(view->mapToScene(view->viewport()->visibleRegion().boundingRect()).boundingRect()).boundingRect().toAlignedRect();
+}
+#endif
+
+void GraphicsLayerQtImpl::notifyAnimationStarted()
+{
+ // WebCore notifies javascript when the animation starts. Here we're letting it know.
+ m_layer->client()->notifyAnimationStarted(m_layer, /* DOM time */ WTF::currentTime());
+}
+
+GraphicsLayerQt::GraphicsLayerQt(GraphicsLayerClient* client)
+ : GraphicsLayer(client)
+ , m_impl(PassOwnPtr<GraphicsLayerQtImpl>(new GraphicsLayerQtImpl(this)))
+{
+}
+
+GraphicsLayerQt::~GraphicsLayerQt()
+{
+}
+
+// This is the hook for WebCore compositor to know that Qt implements compositing with GraphicsLayerQt.
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerQt(client);
+}
+
+/* \reimp (GraphicsLayer.h): The current size might change, thus we need to update the whole display.
+*/
+void GraphicsLayerQt::setNeedsDisplay()
+{
+ m_impl->m_pendingContent.regionToUpdate = QRegion(QRect(QPoint(0, 0), QSize(size().width(), size().height())));
+ m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ m_impl->m_pendingContent.regionToUpdate |= QRectF(rect).toAlignedRect();
+ m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
+}
+
+void GraphicsLayerQt::setContentsNeedsDisplay()
+{
+ switch (m_impl->m_pendingContent.contentType) {
+ case GraphicsLayerQtImpl::MediaContentType:
+ if (!m_impl->m_pendingContent.mediaLayer)
+ return;
+ m_impl->m_pendingContent.mediaLayer.data()->update();
+ break;
+ default:
+ setNeedsDisplay();
+ break;
+ }
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setName(const String& name)
+{
+ m_impl->setObjectName(name);
+ GraphicsLayer::setName(name);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setParent(GraphicsLayer* layer)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
+ GraphicsLayer::setParent(layer);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+bool GraphicsLayerQt::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+ return GraphicsLayer::setChildren(children);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::addChild(GraphicsLayer* layer)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+ GraphicsLayer::addChild(layer);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::addChildAtIndex(GraphicsLayer* layer, int index)
+{
+ GraphicsLayer::addChildAtIndex(layer, index);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildAbove(layer, sibling);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+
+ GraphicsLayer::addChildBelow(layer, sibling);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+bool GraphicsLayerQt::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+ return true;
+ }
+
+ return false;
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::removeFromParent()
+{
+ if (parent())
+ m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
+ GraphicsLayer::removeFromParent();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setMaskLayer(GraphicsLayer* value)
+{
+ if (value == maskLayer())
+ return;
+ GraphicsLayer::setMaskLayer(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::MaskLayerChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setPosition(const FloatPoint& value)
+{
+ if (value == position())
+ return;
+ GraphicsLayer::setPosition(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::PositionChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setAnchorPoint(const FloatPoint3D& value)
+{
+ if (value == anchorPoint())
+ return;
+ GraphicsLayer::setAnchorPoint(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::AnchorPointChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setSize(const FloatSize& value)
+{
+ if (value == size())
+ return;
+ GraphicsLayer::setSize(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::SizeChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setTransform(const TransformationMatrix& value)
+{
+ if (value == transform())
+ return;
+ GraphicsLayer::setTransform(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::TransformChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setChildrenTransform(const TransformationMatrix& value)
+{
+ if (value == childrenTransform())
+ return;
+ GraphicsLayer::setChildrenTransform(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenTransformChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setPreserves3D(bool value)
+{
+ if (value == preserves3D())
+ return;
+ GraphicsLayer::setPreserves3D(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::Preserves3DChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setMasksToBounds(bool value)
+{
+ if (value == masksToBounds())
+ return;
+ GraphicsLayer::setMasksToBounds(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::MasksToBoundsChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setDrawsContent(bool value)
+{
+ if (value == drawsContent())
+ return;
+ m_impl->notifyChange(GraphicsLayerQtImpl::DrawsContentChange);
+ GraphicsLayer::setDrawsContent(value);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setBackgroundColor(const Color& value)
+{
+ if (value == m_impl->m_pendingContent.backgroundColor)
+ return;
+ m_impl->m_pendingContent.backgroundColor = value;
+ GraphicsLayer::setBackgroundColor(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::clearBackgroundColor()
+{
+ if (!m_impl->m_pendingContent.backgroundColor.isValid())
+ return;
+ m_impl->m_pendingContent.backgroundColor = QColor();
+ GraphicsLayer::clearBackgroundColor();
+ m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsOpaque(bool value)
+{
+ if (value == contentsOpaque())
+ return;
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOpaqueChange);
+ GraphicsLayer::setContentsOpaque(value);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setBackfaceVisibility(bool value)
+{
+ if (value == backfaceVisibility())
+ return;
+ GraphicsLayer::setBackfaceVisibility(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::BackfaceVisibilityChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setOpacity(float value)
+{
+ if (value == opacity())
+ return;
+ GraphicsLayer::setOpacity(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsRect(const IntRect& value)
+{
+ if (value == contentsRect())
+ return;
+ GraphicsLayer::setContentsRect(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentsRectChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsToImage(Image* image)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::HTMLContentType;
+ GraphicsLayer::setContentsToImage(image);
+ if (image) {
+ QPixmap* pxm = image->nativeImageForCurrentFrame();
+ if (pxm) {
+ m_impl->m_pendingContent.pixmap = *pxm;
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::PixmapContentType;
+ return;
+ }
+ }
+ m_impl->m_pendingContent.pixmap = QPixmap();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsBackgroundColor(const Color& color)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::ColorContentType;
+ m_impl->m_pendingContent.contentsBackgroundColor = QColor(color);
+ GraphicsLayer::setContentsBackgroundColor(color);
+}
+
+#if ENABLE(3D_CANVAS)
+void GraphicsLayerQt::setContentsToGraphicsContext3D(const GraphicsContext3D* ctx)
+{
+ if (ctx == m_impl->m_gc3D)
+ return;
+
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::Canvas3DContentType;
+ m_impl->m_gc3D = ctx;
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+}
+
+void GraphicsLayerQt::setGraphicsContext3DNeedsDisplay()
+{
+ setNeedsDisplay();
+}
+#endif
+
+void GraphicsLayerQt::setContentsToMedia(PlatformLayer* media)
+{
+ if (media) {
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::MediaContentType;
+ m_impl->m_pendingContent.mediaLayer = media->toGraphicsObject();
+ } else
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::HTMLContentType;
+
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+ GraphicsLayer::setContentsToMedia(media);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsOrientation(CompositingCoordinatesOrientation orientation)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOrientationChange);
+ GraphicsLayer::setContentsOrientation(orientation);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::distributeOpacity(float o)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
+ m_impl->m_state.distributeOpacity = true;
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+float GraphicsLayerQt::accumulatedOpacity() const
+{
+ return m_impl->effectiveOpacity();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::syncCompositingState()
+{
+ m_impl->flushChanges();
+ GraphicsLayer::syncCompositingState();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::syncCompositingStateForThisLayerOnly()
+{
+ // We can't call flushChanges recursively here
+ m_impl->flushChanges(false);
+ GraphicsLayer::syncCompositingStateForThisLayerOnly();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+PlatformLayer* GraphicsLayerQt::platformLayer() const
+{
+ return m_impl.get();
+}
+
+// Now we start dealing with WebCore animations translated to Qt animations
+
+template <typename T>
+struct KeyframeValueQt {
+ const TimingFunction* timingFunction;
+ T value;
+};
+
+/* Copied from AnimationBase.cpp
+*/
+static inline double solveEpsilon(double duration)
+{
+ return 1.0 / (200.0 * duration);
+}
+
+static inline double solveCubicBezierFunction(qreal p1x, qreal p1y, qreal p2x, qreal p2y, double t, double duration)
+{
+ UnitBezier bezier(p1x, p1y, p2x, p2y);
+ return bezier.solve(t, solveEpsilon(duration));
+}
+
+static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t)
+{
+ if (stepAtStart)
+ return qMin(1.0, (floor(numSteps * t) + 1) / numSteps);
+ return floor(numSteps * t) / numSteps;
+}
+
+static inline qreal applyTimingFunction(const TimingFunction* timingFunction, qreal progress, double duration)
+{
+ // We want the timing function to be as close as possible to what the web-developer intended, so
+ // we're using the same function used by WebCore when compositing is disabled. Using easing-curves
+ // would probably work for some of the cases, but wouldn't really buy us anything as we'd have to
+ // convert the bezier function back to an easing curve.
+
+ if (timingFunction->isCubicBezierTimingFunction()) {
+ const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction);
+ return solveCubicBezierFunction(ctf->x1(),
+ ctf->y1(),
+ ctf->x2(),
+ ctf->y2(),
+ double(progress), double(duration) / 1000);
+ } else if (timingFunction->isStepsTimingFunction()) {
+ const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(timingFunction);
+ return solveStepsFunction(stf->numberOfSteps(), stf->stepAtStart(), double(progress));
+ } else
+ return progress;
+}
+
+// Helper functions to safely get a value out of WebCore's AnimationValue*.
+
+static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, TransformOperations& transformOperations)
+{
+ transformOperations = TransformOperations();
+ if (!animationValue)
+ return;
+
+ if (const TransformOperations* ops = static_cast<const TransformAnimationValue*>(animationValue)->value())
+ transformOperations = *ops;
+}
+
+static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, qreal& realValue)
+{
+ realValue = animationValue ? static_cast<const FloatAnimationValue*>(animationValue)->value() : 0;
+}
+
+#ifndef QT_NO_ANIMATION
+// We put a bit of the functionality in a base class to allow casting and to save some code size.
+
+class AnimationQtBase : public QAbstractAnimation {
+public:
+ AnimationQtBase(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ : QAbstractAnimation(0)
+ , m_layer(layer)
+ , m_boxSize(boxSize)
+ , m_duration(anim->duration() * 1000)
+ , m_isAlternate(anim->direction() == Animation::AnimationDirectionAlternate)
+ , m_webkitPropertyID(values.property())
+ , m_webkitAnimation(anim)
+ , m_keyframesName(name)
+ , m_fillsForwards(false)
+ {
+ }
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+ QAbstractAnimation::updateState(newState, oldState);
+
+ // For some reason we have do this asynchronously - or the animation won't work.
+ if (newState == Running && oldState == Stopped && m_layer.data())
+ m_layer.data()->notifyAnimationStartedAsync();
+ }
+
+ virtual int duration() const { return m_duration; }
+
+ QWeakPointer<GraphicsLayerQtImpl> m_layer;
+ IntSize m_boxSize;
+ int m_duration;
+ bool m_isAlternate;
+ AnimatedPropertyID m_webkitPropertyID;
+
+ // We might need this in case the same animation is added again (i.e. resumed by WebCore).
+ const Animation* m_webkitAnimation;
+ QString m_keyframesName;
+ bool m_fillsForwards;
+};
+
+// We'd rather have a templatized QAbstractAnimation than QPropertyAnimation / QVariantAnimation;
+// Since we know the types that we're dealing with, the QObject/QProperty/QVariant abstraction
+// buys us very little in this case, for too much overhead.
+template <typename T>
+class AnimationQt : public AnimationQtBase {
+
+public:
+ AnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ : AnimationQtBase(layer, values, boxSize, anim, name)
+ {
+ // Copying those WebCore structures is not trivial, we have to do it like this.
+ for (size_t i = 0; i < values.size(); ++i) {
+ const AnimationValue* animationValue = values.at(i);
+ KeyframeValueQt<T> keyframeValue;
+ if (animationValue->timingFunction())
+ keyframeValue.timingFunction = animationValue->timingFunction();
+ else
+ keyframeValue.timingFunction = anim->timingFunction().get();
+ webkitAnimationToQtAnimationValue(animationValue, keyframeValue.value);
+ m_keyframeValues[animationValue->keyTime()] = keyframeValue;
+ }
+ }
+
+protected:
+
+ // This is the part that differs between animated properties.
+ virtual void applyFrame(const T& fromValue, const T& toValue, qreal progress) = 0;
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+#if QT_DEBUG_FPS
+ if (newState == Running && oldState == Stopped) {
+ qDebug("Animation Started!");
+ m_fps.frames = 0;
+ m_fps.duration.start();
+ } else if (newState == Stopped && oldState == Running) {
+ const int duration = m_fps.duration.elapsed();
+ qDebug("Animation Ended! %dms [%f FPS]", duration,
+ (1000 / (((float)duration) / m_fps.frames)));
+ }
+#endif
+ AnimationQtBase::updateState(newState, oldState);
+ }
+
+ virtual void updateCurrentTime(int currentTime)
+ {
+ if (!m_layer)
+ return;
+
+ qreal progress = qreal(currentLoopTime()) / duration();
+
+ if (m_isAlternate && currentLoop()%2)
+ progress = 1-progress;
+
+ if (m_keyframeValues.isEmpty())
+ return;
+
+ // Find the current from-to keyframes in our little map.
+ typename QMap<qreal, KeyframeValueQt<T> >::iterator it = m_keyframeValues.find(progress);
+
+ // We didn't find an exact match, we try the closest match (lower bound).
+ if (it == m_keyframeValues.end())
+ it = m_keyframeValues.lowerBound(progress)-1;
+
+ // We didn't find any match; use the first keyframe.
+ if (it == m_keyframeValues.end())
+ it = m_keyframeValues.begin();
+
+ typename QMap<qreal, KeyframeValueQt<T> >::iterator it2 = it + 1;
+ if (it2 == m_keyframeValues.end())
+ it2 = it;
+ const KeyframeValueQt<T>& fromKeyframe = it.value();
+ const KeyframeValueQt<T>& toKeyframe = it2.value();
+
+ const TimingFunction* timingFunc = fromKeyframe.timingFunction;
+ const T& fromValue = fromKeyframe.value;
+ const T& toValue = toKeyframe.value;
+
+ // Now we have a source keyframe, origin keyframe and a timing function.
+ // We can now process the progress and apply the frame.
+ progress = (!progress || progress == 1 || it.key() == it2.key()) ?
+ progress : applyTimingFunction(timingFunc, (progress - it.key()) / (it2.key() - it.key()), duration());
+ applyFrame(fromValue, toValue, progress);
+#if QT_DEBUG_FPS
+ ++m_fps.frames;
+#endif
+ }
+
+ QMap<qreal, KeyframeValueQt<T> > m_keyframeValues;
+#if QT_DEBUG_FPS
+ struct {
+ QTime duration;
+ int frames;
+ } m_fps;
+#endif
+};
+
+class TransformAnimationQt : public AnimationQt<TransformOperations> {
+public:
+ TransformAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ : AnimationQt<TransformOperations>(layer, values, boxSize, anim, name)
+ {
+ }
+
+ ~TransformAnimationQt()
+ {
+ if (m_fillsForwards)
+ setCurrentTime(1);
+ }
+
+ // The idea is that we let WebCore manage the transform operations and Qt just manage the
+ // animation heartbeat and the bottom-line QTransform. We gain performance, not by using
+ // Transform instead of TransformationMatrix, but by proper caching of items that are
+ // expensive for WebCore to render. We want the rest to be as close to WebCore's idea as possible.
+ virtual void applyFrame(const TransformOperations& sourceOperations, const TransformOperations& targetOperations, qreal progress)
+ {
+ TransformationMatrix transformMatrix;
+
+ bool validTransformLists = true;
+ const int sourceOperationCount = sourceOperations.size();
+ if (sourceOperationCount) {
+ if (targetOperations.size() != sourceOperationCount)
+ validTransformLists = false;
+ else {
+ for (size_t j = 0; j < sourceOperationCount && validTransformLists; ++j) {
+ if (!sourceOperations.operations()[j]->isSameType(*targetOperations.operations()[j]))
+ validTransformLists = false;
+ }
+ }
+ }
+
+ if (validTransformLists) {
+ for (size_t i = 0; i < targetOperations.size(); ++i)
+ targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize);
+ } else {
+ targetOperations.apply(m_boxSize, transformMatrix);
+ transformMatrix.blend(m_sourceMatrix, progress);
+ }
+
+ m_layer.data()->m_layer->setTransform(transformMatrix);
+ // We force the actual opacity change, otherwise it would be ignored because of the animation.
+ m_layer.data()->setBaseTransform(transformMatrix);
+ }
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+ AnimationQt<TransformOperations>::updateState(newState, oldState);
+ if (!m_layer)
+ return;
+
+ m_layer.data()->flushChanges(true);
+
+ // To increase FPS, we use a less accurate caching mechanism while animation is going on
+ // this is a UX choice that should probably be customizable.
+ if (newState == QAbstractAnimation::Running) {
+ m_sourceMatrix = m_layer.data()->m_layer->transform();
+ m_layer.data()->m_transformAnimationRunning = true;
+ } else if (newState == QAbstractAnimation::Stopped) {
+ // We update the transform back to the default. This already takes fill-modes into account.
+ m_layer.data()->m_transformAnimationRunning = false;
+ if (m_layer && m_layer.data()->m_layer)
+ m_layer.data()->setBaseTransform(m_layer.data()->m_layer->transform());
+ }
+ }
+
+ TransformationMatrix m_sourceMatrix;
+};
+
+class OpacityAnimationQt : public AnimationQt<qreal> {
+public:
+ OpacityAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString& name)
+ : AnimationQt<qreal>(layer, values, boxSize, anim, name)
+ {
+ }
+
+ ~OpacityAnimationQt()
+ {
+ if (m_fillsForwards)
+ setCurrentTime(1);
+ }
+
+ virtual void applyFrame(const qreal& fromValue, const qreal& toValue, qreal progress)
+ {
+ qreal opacity = qBound(qreal(0), fromValue + (toValue - fromValue) * progress, qreal(1));
+
+ // FIXME: This is a hack, due to a probable QGraphicsScene bug.
+ // Without this the opacity change doesn't always have immediate effect.
+ if (m_layer.data()->scene() && !m_layer.data()->opacity() && opacity)
+ m_layer.data()->scene()->update();
+
+ m_layer.data()->m_layer->setOpacity(opacity);
+ // We force the actual opacity change, otherwise it would be ignored because of the animation.
+ m_layer.data()->setOpacity(opacity);
+ }
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+ AnimationQt<qreal>::updateState(newState, oldState);
+
+ if (m_layer)
+ m_layer.data()->m_opacityAnimationRunning = (newState == QAbstractAnimation::Running);
+
+ // If stopped, we update the opacity back to the default. This already takes fill-modes into account.
+ if (newState == Stopped)
+ if (m_layer && m_layer.data()->m_layer)
+ m_layer.data()->setOpacity(m_layer.data()->m_layer->opacity());
+
+ }
+};
+
+bool GraphicsLayerQt::addAnimation(const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset)
+{
+ if (!anim->duration() || !anim->iterationCount())
+ return false;
+
+ AnimationQtBase* newAnim = 0;
+
+ // Fixed: we might already have the Qt animation object associated with this WebCore::Animation object.
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (*it) {
+ AnimationQtBase* curAnimation = static_cast<AnimationQtBase*>(it->data());
+ if (curAnimation && curAnimation->m_webkitAnimation == anim)
+ newAnim = curAnimation;
+ }
+ }
+
+ if (!newAnim) {
+ switch (values.property()) {
+ case AnimatedPropertyOpacity:
+ newAnim = new OpacityAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
+ break;
+ case AnimatedPropertyWebkitTransform:
+ newAnim = new TransformAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
+ break;
+ default:
+ return false;
+ }
+
+ // We make sure WebCore::Animation and QAnimation are on the same terms.
+ newAnim->setLoopCount(anim->iterationCount());
+ newAnim->m_fillsForwards = anim->fillsForwards();
+ m_impl->m_animations.append(QWeakPointer<QAbstractAnimation>(newAnim));
+ QObject::connect(&m_impl->m_suspendTimer, SIGNAL(timeout()), newAnim, SLOT(resume()));
+ }
+
+ // Flush now to avoid flicker.
+ m_impl->flushChanges(false);
+
+ // Qhen fill-mode is backwards/both, we set the value to 0 before the delay takes place.
+ if (anim->fillsBackwards())
+ newAnim->setCurrentTime(0);
+
+ newAnim->start();
+
+ // We synchronize the animation's clock to WebCore's timeOffset.
+ newAnim->setCurrentTime(timeOffset * 1000);
+
+ // We don't need to manage the animation object's lifecycle:
+ // WebCore would call removeAnimations when it's time to delete.
+
+ return true;
+}
+
+void GraphicsLayerQt::removeAnimationsForProperty(AnimatedPropertyID id)
+{
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (!(*it))
+ continue;
+
+ AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
+ if (anim && anim->m_webkitPropertyID == id) {
+ // We need to stop the animation right away, or it might flicker before it's deleted.
+ anim->stop();
+ anim->deleteLater();
+ it = m_impl->m_animations.erase(it);
+ --it;
+ }
+ }
+}
+
+void GraphicsLayerQt::removeAnimationsForKeyframes(const String& name)
+{
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (!(*it))
+ continue;
+
+ AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
+ if (anim && anim->m_keyframesName == QString(name)) {
+ // We need to stop the animation right away, or it might flicker before it's deleted.
+ anim->stop();
+ anim->deleteLater();
+ it = m_impl->m_animations.erase(it);
+ --it;
+ }
+ }
+}
+
+void GraphicsLayerQt::pauseAnimation(const String& name, double timeOffset)
+{
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (!(*it))
+ continue;
+
+ AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
+ if (anim && anim->m_keyframesName == QString(name)) {
+ // we synchronize the animation's clock to WebCore's timeOffset
+ anim->setCurrentTime(timeOffset * 1000);
+ anim->pause();
+ }
+ }
+}
+
+void GraphicsLayerQt::suspendAnimations(double time)
+{
+ if (m_impl->m_suspendTimer.isActive()) {
+ m_impl->m_suspendTimer.stop();
+ m_impl->m_suspendTimer.start(time * 1000);
+ } else {
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (QAbstractAnimation* anim = it->data())
+ anim->pause();
+ }
+ }
+}
+
+void GraphicsLayerQt::resumeAnimations()
+{
+ if (m_impl->m_suspendTimer.isActive()) {
+ m_impl->m_suspendTimer.stop();
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (QAbstractAnimation* anim = it->data())
+ anim->resume();
+ }
+ }
+}
+
+#endif // QT_NO_ANIMATION
+}
+
+#include <GraphicsLayerQt.moc>
diff --git a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h
new file mode 100644
index 0000000..b1692d2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef GraphicsLayerQt_h
+#define GraphicsLayerQt_h
+
+#if ENABLE(3D_CANVAS)
+#include "GraphicsContext3D.h"
+#endif
+#include "GraphicsLayer.h"
+#include "GraphicsLayerClient.h"
+
+namespace WebCore {
+
+class GraphicsLayerQtImpl;
+
+class GraphicsLayerQt : public GraphicsLayer {
+ friend class GraphicsLayerQtImpl;
+
+public:
+ GraphicsLayerQt(GraphicsLayerClient*);
+ virtual ~GraphicsLayerQt();
+
+ // reimps from GraphicsLayer.h
+ virtual PlatformLayer* platformLayer() const;
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+ virtual void setParent(GraphicsLayer* layer);
+ virtual void setName(const String& name);
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
+ virtual void addChild(GraphicsLayer*);
+ virtual void addChildAtIndex(GraphicsLayer*, int index);
+ virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+ virtual void removeFromParent();
+ virtual void setMaskLayer(GraphicsLayer* layer);
+ virtual void setPosition(const FloatPoint& p);
+ virtual void setAnchorPoint(const FloatPoint3D& p);
+ virtual void setSize(const FloatSize& size);
+ virtual void setTransform(const TransformationMatrix& t);
+ virtual void setChildrenTransform(const TransformationMatrix& t);
+ virtual void setPreserves3D(bool b);
+ virtual void setMasksToBounds(bool b);
+ virtual void setDrawsContent(bool b);
+ virtual void setBackgroundColor(const Color&);
+ virtual void clearBackgroundColor();
+ virtual void setContentsOpaque(bool b);
+ virtual void setBackfaceVisibility(bool b);
+ virtual void setOpacity(float opacity);
+ virtual void setContentsRect(const IntRect& r);
+#ifndef QT_NO_ANIMATION
+ virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double timeOffset);
+ virtual void removeAnimationsForProperty(AnimatedPropertyID);
+ virtual void removeAnimationsForKeyframes(const String& keyframesName);
+ virtual void pauseAnimation(const String& keyframesName, double timeOffset);
+ virtual void suspendAnimations(double time);
+ virtual void resumeAnimations();
+#endif // QT_NO_ANIMATION
+ virtual void setContentsToImage(Image*);
+ virtual void setContentsNeedsDisplay();
+ virtual void setContentsToMedia(PlatformLayer*);
+ virtual void setContentsBackgroundColor(const Color&);
+#if ENABLE(3D_CANVAS)
+ virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*);
+ virtual void setGraphicsContext3DNeedsDisplay();
+#endif
+ virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation);
+ virtual void distributeOpacity(float);
+ virtual float accumulatedOpacity() const;
+ virtual void syncCompositingState();
+ virtual void syncCompositingStateForThisLayerOnly();
+
+private:
+ OwnPtr<GraphicsLayerQtImpl> m_impl;
+};
+
+}
+#endif // GraphicsLayerQt_h
diff --git a/Source/WebCore/platform/graphics/qt/IconQt.cpp b/Source/WebCore/platform/graphics/qt/IconQt.cpp
new file mode 100644
index 0000000..eb09eda
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/IconQt.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include "IntRect.h"
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qrect.h>
+#include <qglobal.h>
+
+namespace WebCore {
+
+Icon::Icon()
+{
+}
+
+Icon::~Icon()
+{
+}
+
+// FIXME: Move the code to ChromeClient::iconForFiles().
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ if (filenames.isEmpty())
+ return 0;
+
+ if (filenames.size() == 1) {
+ RefPtr<Icon> i = adoptRef(new Icon);
+ i->m_icon = QIcon(filenames[0]);
+ return i.release();
+ }
+
+ //FIXME: Implement this
+ return 0;
+}
+
+void Icon::paint(GraphicsContext* ctx, const IntRect& rect)
+{
+ QPixmap px = m_icon.pixmap(rect.size());
+ QPainter *p = static_cast<QPainter*>(ctx->platformContext());
+ if (p && !px.isNull())
+ p->drawPixmap(rect.x(), rect.y(), px);
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferData.h b/Source/WebCore/platform/graphics/qt/ImageBufferData.h
new file mode 100644
index 0000000..aa32253
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageBufferData.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ImageBufferData_h
+#define ImageBufferData_h
+
+#include "Image.h"
+#include <wtf/RefPtr.h>
+
+#include <QPainter>
+#include <QPixmap>
+
+#include "OwnPtr.h"
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ QPixmap m_pixmap;
+ OwnPtr<QPainter> m_painter;
+ RefPtr<Image> m_image;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp
new file mode 100644
index 0000000..f56603d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "StillImageQt.h"
+#include "TransparencyLayer.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+
+#include <QBuffer>
+#include <QColor>
+#include <QImage>
+#include <QImageWriter>
+#include <QPainter>
+#include <QPixmap>
+#include <math.h>
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_pixmap(size)
+ , m_painter(0)
+{
+ if (m_pixmap.isNull())
+ return;
+
+ m_pixmap.fill(QColor(Qt::transparent));
+
+ QPainter* painter = new QPainter;
+ m_painter.set(painter);
+
+ if (!painter->begin(&m_pixmap))
+ return;
+
+ // Since ImageBuffer is used mainly for Canvas, explicitly initialize
+ // its painter's pen and brush with the corresponding canvas defaults
+ // NOTE: keep in sync with CanvasRenderingContext2D::State
+ QPen pen = painter->pen();
+ pen.setColor(Qt::black);
+ pen.setWidth(1);
+ pen.setCapStyle(Qt::FlatCap);
+ pen.setJoinStyle(Qt::SvgMiterJoin);
+ pen.setMiterLimit(10);
+ painter->setPen(pen);
+ QBrush brush = painter->brush();
+ brush.setColor(Qt::black);
+ painter->setBrush(brush);
+ painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
+
+ m_image = StillImage::createForRendering(&m_pixmap);
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ success = m_data.m_painter && m_data.m_painter->isActive();
+ if (!success)
+ return;
+
+ m_context.set(new GraphicsContext(m_data.m_painter.get()));
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ ASSERT(m_data.m_painter->isActive());
+
+ return m_context.get();
+}
+
+bool ImageBuffer::drawsUsingCopy() const
+{
+ return false;
+}
+
+PassRefPtr<Image> ImageBuffer::copyImage() const
+{
+ return StillImage::create(m_data.m_pixmap);
+}
+
+void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
+ CompositeOperator op, bool useLowQualityScale)
+{
+ if (destContext == context()) {
+ // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first.
+ RefPtr<Image> copy = copyImage();
+ destContext->drawImage(copy.get(), ColorSpaceDeviceRGB, destRect, srcRect, op, useLowQualityScale);
+ } else
+ destContext->drawImage(m_data.m_image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
+}
+
+void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ if (destContext == context()) {
+ // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first.
+ RefPtr<Image> copy = copyImage();
+ copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+ } else
+ m_data.m_image->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+}
+
+void ImageBuffer::clip(GraphicsContext* context, const FloatRect& floatRect) const
+{
+ QPixmap* nativeImage = m_data.m_image->nativeImageForCurrentFrame();
+ if (!nativeImage)
+ return;
+
+ IntRect rect = enclosingIntRect(floatRect);
+ QPixmap alphaMask = *nativeImage;
+ if (alphaMask.width() != rect.width() || alphaMask.height() != rect.height())
+ alphaMask = alphaMask.scaled(rect.width(), rect.height());
+
+ context->pushTransparencyLayerInternal(rect, 1.0, alphaMask);
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ bool isPainting = m_data.m_painter->isActive();
+ if (isPainting)
+ m_data.m_painter->end();
+
+ QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ ASSERT(!image.isNull());
+
+ uchar* bits = image.bits();
+ const int bytesPerLine = image.bytesPerLine();
+
+ for (int y = 0; y < m_size.height(); ++y) {
+ quint32* scanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine);
+ for (int x = 0; x < m_size.width(); ++x) {
+ QRgb& pixel = scanLine[x];
+ pixel = qRgba(lookUpTable[qRed(pixel)],
+ lookUpTable[qGreen(pixel)],
+ lookUpTable[qBlue(pixel)],
+ qAlpha(pixel));
+ }
+ }
+
+ m_data.m_pixmap = QPixmap::fromImage(image);
+
+ if (isPainting)
+ m_data.m_painter->begin(&m_data.m_pixmap);
+}
+
+template <Multiply multiplied>
+PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size)
+{
+ RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4);
+ unsigned char* data = result->data();
+
+ if (rect.x() < 0 || rect.y() < 0 || rect.right() > size.width() || rect.bottom() > size.height())
+ memset(data, 0, result->length());
+
+ int originx = rect.x();
+ int destx = 0;
+ if (originx < 0) {
+ destx = -originx;
+ originx = 0;
+ }
+ int endx = rect.right();
+ if (endx > size.width())
+ endx = size.width();
+ int numColumns = endx - originx;
+
+ int originy = rect.y();
+ int desty = 0;
+ if (originy < 0) {
+ desty = -originy;
+ originy = 0;
+ }
+ int endy = rect.bottom();
+ if (endy > size.height())
+ endy = size.height();
+ int numRows = endy - originy;
+
+ // NOTE: For unmultiplied data, we undo the premultiplication below.
+ QImage image = imageData.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
+
+ ASSERT(!image.isNull());
+
+ const int bytesPerLine = image.bytesPerLine();
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ const uchar* bits = image.constBits();
+#else
+ const uchar* bits = image.bits();
+#endif
+
+ quint32* destRows = reinterpret_cast_ptr<quint32*>(&data[desty * rect.width() * 4 + destx * 4]);
+
+ if (multiplied == Unmultiplied) {
+ for (int y = 0; y < numRows; ++y) {
+ const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(bits + (y + originy) * bytesPerLine);
+ for (int x = 0; x < numColumns; x++) {
+ QRgb pixel = scanLine[x + originx];
+ int alpha = qAlpha(pixel);
+ // Un-premultiply and convert RGB to BGR.
+ if (alpha == 255)
+ destRows[x] = (0xFF000000
+ | (qBlue(pixel) << 16)
+ | (qGreen(pixel) << 8)
+ | (qRed(pixel)));
+ else if (alpha > 0)
+ destRows[x] = ((alpha << 24)
+ | (((255 * qBlue(pixel)) / alpha)) << 16)
+ | (((255 * qGreen(pixel)) / alpha) << 8)
+ | ((255 * qRed(pixel)) / alpha);
+ else
+ destRows[x] = 0;
+ }
+ destRows += rect.width();
+ }
+ } else {
+ for (int y = 0; y < numRows; ++y) {
+ const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(bits + (y + originy) * bytesPerLine);
+ for (int x = 0; x < numColumns; x++) {
+ QRgb pixel = scanLine[x + originx];
+ // Convert RGB to BGR.
+ destRows[x] = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00);
+
+ }
+ destRows += rect.width();
+ }
+ }
+
+ return result.release();
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<Unmultiplied>(rect, m_data, m_size);
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<Premultiplied>(rect, m_data, m_size);
+}
+
+static inline unsigned int premultiplyABGRtoARGB(unsigned int x)
+{
+ unsigned int a = x >> 24;
+ if (a == 255)
+ return (x << 16) | ((x >> 16) & 0xff) | (x & 0xff00ff00);
+ unsigned int t = (x & 0xff00ff) * a;
+ t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
+ t = ((t << 16) | (t >> 16)) & 0xff00ff;
+
+ x = ((x >> 8) & 0xff) * a;
+ x = (x + ((x >> 8) & 0xff) + 0x80);
+ x &= 0xff00;
+ x |= t | (a << 24);
+ return x;
+}
+
+template <Multiply multiplied>
+void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size)
+{
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originx = sourceRect.x();
+ int destx = destPoint.x() + sourceRect.x();
+ ASSERT(destx >= 0);
+ ASSERT(destx < size.width());
+ ASSERT(originx >= 0);
+ ASSERT(originx <= sourceRect.right());
+
+ int endx = destPoint.x() + sourceRect.right();
+ ASSERT(endx <= size.width());
+
+ int numColumns = endx - destx;
+
+ int originy = sourceRect.y();
+ int desty = destPoint.y() + sourceRect.y();
+ ASSERT(desty >= 0);
+ ASSERT(desty < size.height());
+ ASSERT(originy >= 0);
+ ASSERT(originy <= sourceRect.bottom());
+
+ int endy = destPoint.y() + sourceRect.bottom();
+ ASSERT(endy <= size.height());
+ int numRows = endy - desty;
+
+ unsigned srcBytesPerRow = 4 * sourceSize.width();
+
+ // NOTE: For unmultiplied input data, we do the premultiplication below.
+ QImage image(numColumns, numRows, QImage::Format_ARGB32_Premultiplied);
+ uchar* bits = image.bits();
+ const int bytesPerLine = image.bytesPerLine();
+
+ const quint32* srcScanLine = reinterpret_cast_ptr<const quint32*>(source->data() + originy * srcBytesPerRow + originx * 4);
+
+ if (multiplied == Unmultiplied) {
+ for (int y = 0; y < numRows; ++y) {
+ quint32* destScanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine);
+ for (int x = 0; x < numColumns; x++) {
+ // Premultiply and convert BGR to RGB.
+ quint32 pixel = srcScanLine[x];
+ destScanLine[x] = premultiplyABGRtoARGB(pixel);
+ }
+ srcScanLine += sourceSize.width();
+ }
+ } else {
+ for (int y = 0; y < numRows; ++y) {
+ quint32* destScanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine);
+ for (int x = 0; x < numColumns; x++) {
+ // Convert BGR to RGB.
+ quint32 pixel = srcScanLine[x];
+ destScanLine[x] = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00);
+ }
+ srcScanLine += sourceSize.width();
+ }
+ }
+
+ bool isPainting = data.m_painter->isActive();
+ if (!isPainting)
+ data.m_painter->begin(&data.m_pixmap);
+ else {
+ data.m_painter->save();
+
+ // putImageData() should be unaffected by painter state
+ data.m_painter->resetTransform();
+ data.m_painter->setOpacity(1.0);
+ data.m_painter->setClipping(false);
+ }
+
+ data.m_painter->setCompositionMode(QPainter::CompositionMode_Source);
+ data.m_painter->drawImage(destx, desty, image);
+
+ if (!isPainting)
+ data.m_painter->end();
+ else
+ data.m_painter->restore();
+}
+
+void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
+}
+
+void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
+}
+
+// We get a mimeType here but QImageWriter does not support mimetypes but
+// only formats (png, gif, jpeg..., xpm). So assume we get image/ as image
+// mimetypes and then remove the image/ to get the Qt format.
+String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const
+{
+ ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+
+ if (!mimeType.startsWith("image/"))
+ return "data:,";
+
+ // prepare our target
+ QByteArray data;
+ QBuffer buffer(&data);
+ buffer.open(QBuffer::WriteOnly);
+
+ if (quality && *quality >= 0.0 && *quality <= 1.0) {
+ if (!m_data.m_pixmap.save(&buffer, mimeType.substring(sizeof "image").utf8().data(), *quality * 100 + 0.5)) {
+ buffer.close();
+ return "data:,";
+ }
+ } else {
+ if (!m_data.m_pixmap.save(&buffer, mimeType.substring(sizeof "image").utf8().data(), 100)) {
+ buffer.close();
+ return "data:,";
+ }
+ }
+
+ buffer.close();
+
+ return makeString("data:", mimeType, ";base64,", data.toBase64().data());
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
new file mode 100644
index 0000000..2bbb9ce
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ImageDecoderQt.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QBuffer>
+
+#include <QtGui/QImageReader>
+#include <qdebug.h>
+
+namespace WebCore {
+
+ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
+{
+ // We need at least 4 bytes to figure out what kind of image we're dealing with.
+ if (data.size() < 4)
+ return 0;
+
+ return new ImageDecoderQt(alphaOption, gammaAndColorProfileOption);
+}
+
+ImageDecoderQt::ImageDecoderQt(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
+ : ImageDecoder(alphaOption, gammaAndColorProfileOption)
+ , m_repetitionCount(cAnimationNone)
+{
+}
+
+ImageDecoderQt::~ImageDecoderQt()
+{
+}
+
+void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (failed())
+ return;
+
+ // No progressive loading possible
+ if (!allDataReceived)
+ return;
+
+ // Cache our own new data.
+ ImageDecoder::setData(data, allDataReceived);
+
+ // We expect to be only called once with allDataReceived
+ ASSERT(!m_buffer);
+ ASSERT(!m_reader);
+
+ // Attempt to load the data
+ QByteArray imageData = QByteArray::fromRawData(m_data->data(), m_data->size());
+ m_buffer.set(new QBuffer);
+ m_buffer->setData(imageData);
+ m_buffer->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ m_reader.set(new QImageReader(m_buffer.get(), m_format));
+
+ // This will force the JPEG decoder to use JDCT_IFAST
+ m_reader->setQuality(49);
+
+ // QImageReader only allows retrieving the format before reading the image
+ m_format = m_reader->format();
+}
+
+bool ImageDecoderQt::isSizeAvailable()
+{
+ if (!ImageDecoder::isSizeAvailable() && m_reader)
+ internalDecodeSize();
+
+ return ImageDecoder::isSizeAvailable();
+}
+
+size_t ImageDecoderQt::frameCount()
+{
+ if (m_frameBufferCache.isEmpty() && m_reader) {
+ if (m_reader->supportsAnimation()) {
+ int imageCount = m_reader->imageCount();
+
+ // Fixup for Qt decoders... imageCount() is wrong
+ // and jumpToNextImage does not work either... so
+ // we will have to parse everything...
+ if (!imageCount)
+ forceLoadEverything();
+ else {
+ m_frameBufferCache.resize(imageCount);
+ for (size_t i = 0; i < m_frameBufferCache.size(); ++i)
+ m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha);
+ }
+ } else {
+ m_frameBufferCache.resize(1);
+ m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha);
+ }
+ }
+
+ return m_frameBufferCache.size();
+}
+
+int ImageDecoderQt::repetitionCount() const
+{
+ if (m_reader && m_reader->supportsAnimation())
+ m_repetitionCount = m_reader->loopCount();
+ return m_repetitionCount;
+}
+
+String ImageDecoderQt::filenameExtension() const
+{
+ return String(m_format.constData(), m_format.length());
+};
+
+RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index)
+{
+ // In case the ImageDecoderQt got recreated we don't know
+ // yet how many images we are going to have and need to
+ // find that out now.
+ size_t count = m_frameBufferCache.size();
+ if (!failed() && !count) {
+ internalDecodeSize();
+ count = frameCount();
+ }
+
+ if (index >= count)
+ return 0;
+
+ RGBA32Buffer& frame = m_frameBufferCache[index];
+ if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
+ internalReadImage(index);
+ return &frame;
+}
+
+void ImageDecoderQt::clearFrameBufferCache(size_t /*index*/)
+{
+}
+
+void ImageDecoderQt::internalDecodeSize()
+{
+ ASSERT(m_reader);
+
+ // If we have a QSize() something failed
+ QSize size = m_reader->size();
+ if (size.isEmpty()) {
+ setFailed();
+ return clearPointers();
+ }
+
+ setSize(size.width(), size.height());
+}
+
+void ImageDecoderQt::internalReadImage(size_t frameIndex)
+{
+ ASSERT(m_reader);
+
+ if (m_reader->supportsAnimation())
+ m_reader->jumpToImage(frameIndex);
+ else if (frameIndex) {
+ setFailed();
+ return clearPointers();
+ }
+
+ if (!internalHandleCurrentImage(frameIndex))
+ setFailed();
+
+ // Attempt to return some memory
+ for (int i = 0; i < m_frameBufferCache.size(); ++i) {
+ if (m_frameBufferCache[i].status() != RGBA32Buffer::FrameComplete)
+ return;
+ }
+
+ clearPointers();
+}
+
+bool ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex)
+{
+ QPixmap pixmap;
+
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ pixmap = QPixmap::fromImageReader(m_reader.get());
+#else
+ QImage img;
+ if (m_reader->read(&img))
+ pixmap = QPixmap::fromImage(img);
+#endif
+
+ if (pixmap.isNull()) {
+ frameCount();
+ repetitionCount();
+ clearPointers();
+ return false;
+ }
+
+ // now into the RGBA32Buffer - even if the image is not
+ RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex];
+ buffer->setRect(m_reader->currentImageRect());
+ buffer->setStatus(RGBA32Buffer::FrameComplete);
+ buffer->setDuration(m_reader->nextImageDelay());
+ buffer->setPixmap(pixmap);
+ return true;
+}
+
+// The QImageIOHandler is not able to tell us how many frames
+// we have and we need to parse every image. We do this by
+// increasing the m_frameBufferCache by one and try to parse
+// the image. We stop when QImage::read fails and then need
+// to resize the m_frameBufferCache to the final size and update
+// the failed bit. If we failed to decode the first image
+// then we truly failed to decode, otherwise we're OK.
+
+// TODO: Do not increment the m_frameBufferCache.size() by one but more than one
+void ImageDecoderQt::forceLoadEverything()
+{
+ int imageCount = 0;
+
+ do {
+ m_frameBufferCache.resize(++imageCount);
+ } while (internalHandleCurrentImage(imageCount - 1));
+
+ // If we failed decoding the first image we actually
+ // have no images and need to set the failed bit.
+ // Otherwise, we want to forget about
+ // the last attempt to decode a image.
+ m_frameBufferCache.resize(imageCount - 1);
+ for (size_t i = 0; i < m_frameBufferCache.size(); ++i)
+ m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha);
+ if (imageCount == 1)
+ setFailed();
+}
+
+void ImageDecoderQt::clearPointers()
+{
+ m_reader.clear();
+ m_buffer.clear();
+}
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/ImageDecoderQt.h b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.h
new file mode 100644
index 0000000..23fb79a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ImageDecoderQt_h
+#define ImageDecoderQt_h
+
+#include "ImageDecoder.h"
+#include <QtGui/QImageReader>
+#include <QtGui/QPixmap>
+#include <QtCore/QList>
+#include <QtCore/QHash>
+#include <QtCore/QBuffer>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+
+class ImageDecoderQt : public ImageDecoder
+{
+public:
+ ImageDecoderQt(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption);
+ ~ImageDecoderQt();
+
+ virtual void setData(SharedBuffer* data, bool allDataReceived);
+ virtual bool isSizeAvailable();
+ virtual size_t frameCount();
+ virtual int repetitionCount() const;
+ virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
+
+ virtual String filenameExtension() const;
+
+ virtual void clearFrameBufferCache(size_t clearBeforeFrame);
+
+private:
+ ImageDecoderQt(const ImageDecoderQt&);
+ ImageDecoderQt &operator=(const ImageDecoderQt&);
+
+private:
+ void internalDecodeSize();
+ void internalReadImage(size_t);
+ bool internalHandleCurrentImage(size_t);
+ void forceLoadEverything();
+ void clearPointers();
+
+private:
+ QByteArray m_format;
+ OwnPtr<QBuffer> m_buffer;
+ OwnPtr<QImageReader> m_reader;
+ mutable int m_repetitionCount;
+};
+
+
+
+}
+
+#endif
+
diff --git a/Source/WebCore/platform/graphics/qt/ImageQt.cpp b/Source/WebCore/platform/graphics/qt/ImageQt.cpp
new file mode 100644
index 0000000..49afd29
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageQt.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ * Copyright (C) 2010 Sencha, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "ContextShadow.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageObserver.h"
+#include "PlatformString.h"
+#include "StillImageQt.h"
+#include "qwebsettings.h"
+
+#include <QPixmap>
+#include <QPainter>
+#include <QImage>
+#include <QImageReader>
+#include <QTransform>
+
+#include <QDebug>
+
+#include <math.h>
+
+// This function loads resources into WebKit
+static QPixmap loadResourcePixmap(const char *name)
+{
+ QPixmap pixmap;
+ if (qstrcmp(name, "missingImage") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::MissingImageGraphic);
+ else if (qstrcmp(name, "nullPlugin") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::MissingPluginGraphic);
+ else if (qstrcmp(name, "urlIcon") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic);
+ else if (qstrcmp(name, "textAreaResizeCorner") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic);
+ else if (qstrcmp(name, "deleteButton") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::DeleteButtonGraphic);
+ else if (!qstrcmp(name, "inputSpeech"))
+ pixmap = QWebSettings::webGraphic(QWebSettings::InputSpeechButtonGraphic);
+
+ return pixmap;
+}
+
+namespace WebCore {
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ delete m_frame;
+ m_frame = 0;
+ return true;
+ }
+ return false;
+}
+
+
+// ================================================
+// Image Class
+// ================================================
+
+PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+{
+ return StillImage::create(loadResourcePixmap(name));
+}
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ QPixmap* framePixmap = nativeImageForCurrentFrame();
+ if (!framePixmap) // If it's too early we won't have an image yet.
+ return;
+
+ // Qt interprets 0 width/height as full width/height so just short circuit.
+ QRectF dr = QRectF(destRect).normalized();
+ QRect tr = QRectF(tileRect).toRect().normalized();
+ if (!dr.width() || !dr.height() || !tr.width() || !tr.height())
+ return;
+
+ QPixmap pixmap = *framePixmap;
+ if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height())
+ pixmap = pixmap.copy(tr);
+
+ CompositeOperator previousOperator = ctxt->compositeOperation();
+
+ ctxt->setCompositeOperation(op);
+ QPainter* p = ctxt->platformContext();
+ if (!pixmap.hasAlpha() && p->compositionMode() == QPainter::CompositionMode_SourceOver)
+ p->setCompositionMode(QPainter::CompositionMode_Source);
+
+ /* Translate the coordinates as phase is not in world matrix coordinate space but the tile rect origin is. */
+ QTransform transform(patternTransform);
+ transform *= QTransform().translate(phase.x(), phase.y());
+ transform.translate(tr.x(), tr.y());
+
+ QBrush b(pixmap);
+ b.setTransform(transform);
+ p->fillRect(dr, b);
+
+ ctxt->setCompositeOperation(previousOperator);
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+BitmapImage::BitmapImage(QPixmap* pixmap, ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
+ , m_animationFinished(true)
+ , m_allDataReceived(true)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ int width = pixmap->width();
+ int height = pixmap->height();
+ m_decodedSize = width * height * 4;
+ m_size = IntSize(width, height);
+
+ m_frames.grow(1);
+ m_frames[0].m_frame = pixmap;
+ m_frames[0].m_hasAlpha = pixmap->hasAlpha();
+ m_frames[0].m_haveMetadata = true;
+ checkForSolidColor();
+}
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+// Drawing Routines
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
+ const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ QRectF normalizedDst = dst.normalized();
+ QRectF normalizedSrc = src.normalized();
+
+ startAnimation();
+
+ if (normalizedSrc.isEmpty() || normalizedDst.isEmpty())
+ return;
+
+ QPixmap* image = nativeImageForCurrentFrame();
+ if (!image)
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+ QPainter* painter(ctxt->platformContext());
+
+ QPainter::CompositionMode compositionMode = GraphicsContext::toQtCompositionMode(op);
+
+ if (!image->hasAlpha() && painter->compositionMode() == QPainter::CompositionMode_SourceOver)
+ compositionMode = QPainter::CompositionMode_Source;
+
+ QPainter::CompositionMode lastCompositionMode = painter->compositionMode();
+ painter->setCompositionMode(compositionMode);
+
+ ContextShadow* shadow = ctxt->contextShadow();
+ if (shadow->m_type != ContextShadow::NoShadow) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst);
+ if (shadowPainter) {
+ shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255);
+ shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc);
+ shadow->endShadowLayer(ctxt);
+ }
+ }
+
+ // Test using example site at
+ // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ painter->drawPixmap(normalizedDst, *image, normalizedSrc);
+
+ painter->setCompositionMode(lastCompositionMode);
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_isSolidColor = false;
+ m_checkedForSolidColor = true;
+
+ if (frameCount() > 1)
+ return;
+
+ QPixmap* framePixmap = frameAtIndex(0);
+ if (!framePixmap || framePixmap->width() != 1 || framePixmap->height() != 1)
+ return;
+
+ m_isSolidColor = true;
+ m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0));
+}
+
+#if OS(WINDOWS)
+PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap)
+{
+ return BitmapImage::create(new QPixmap(QPixmap::fromWinHBITMAP(hBitmap)));
+}
+#endif
+
+}
+
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/IntPointQt.cpp b/Source/WebCore/platform/graphics/qt/IntPointQt.cpp
new file mode 100644
index 0000000..f9d336a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/IntPointQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include <QPoint>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const QPoint& p)
+ : m_x(p.x())
+ , m_y(p.y())
+{
+}
+
+IntPoint::operator QPoint() const
+{
+ return QPoint(m_x, m_y);
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/IntRectQt.cpp b/Source/WebCore/platform/graphics/qt/IntRectQt.cpp
new file mode 100644
index 0000000..ccc153e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/IntRectQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include <QRect>
+
+namespace WebCore {
+
+IntRect::IntRect(const QRect& r)
+ : m_location(r.topLeft())
+ , m_size(r.width(), r.height())
+{
+}
+
+IntRect::operator QRect() const
+{
+ return QRect(x(), y(), width(), height());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/IntSizeQt.cpp b/Source/WebCore/platform/graphics/qt/IntSizeQt.cpp
new file mode 100644
index 0000000..4f2bf35
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/IntSizeQt.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#include <QSize>
+
+#include "IntSize.h"
+
+namespace WebCore {
+
+IntSize::IntSize(const QSize& r)
+ : m_width(r.width())
+ , m_height(r.height())
+{
+}
+
+IntSize::operator QSize() const
+{
+ return QSize(width(), height());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
new file mode 100644
index 0000000..b881036
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
@@ -0,0 +1,547 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Apple Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "MediaPlayerPrivatePhonon.h"
+
+#include <limits>
+
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "Logging.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "TimeRanges.h"
+#include "Widget.h"
+#include <wtf/HashSet.h>
+#include <wtf/text/CString.h>
+
+#include <QDebug>
+#include <QEvent>
+#include <QMetaEnum>
+#include <QPainter>
+#include <QWidget>
+#include <QUrl>
+
+#include <phonon/audiooutput.h>
+#include <phonon/backendcapabilities.h>
+#include <phonon/path.h>
+#include <phonon/mediaobject.h>
+#include <phonon/videowidget.h>
+
+using namespace Phonon;
+
+#define LOG_MEDIAOBJECT() (LOG(Media, "%s", debugMediaObject(this, *m_mediaObject).constData()))
+
+#if !LOG_DISABLED
+static QByteArray debugMediaObject(WebCore::MediaPlayerPrivatePhonon* mediaPlayer, const MediaObject& mediaObject)
+{
+ QByteArray byteArray;
+ QTextStream stream(&byteArray);
+
+ const QMetaObject* metaObj = mediaPlayer->metaObject();
+ QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState"));
+
+ stream << "debugMediaObject -> Phonon::MediaObject(";
+ stream << "State: " << phononStates.valueToKey(mediaObject.state());
+ stream << " | Current time: " << mediaObject.currentTime();
+ stream << " | Remaining time: " << mediaObject.remainingTime();
+ stream << " | Total time: " << mediaObject.totalTime();
+ stream << " | Meta-data: ";
+ QMultiMap<QString, QString> map = mediaObject.metaData();
+ for (QMap<QString, QString>::const_iterator it = map.constBegin();
+ it != map.constEnd(); ++it) {
+ stream << "(" << it.key() << ", " << it.value() << ")";
+ }
+ stream << " | Has video: " << mediaObject.hasVideo();
+ stream << " | Is seekable: " << mediaObject.isSeekable();
+ stream << ")";
+
+ stream.flush();
+
+ return byteArray;
+}
+#endif
+
+using namespace WTF;
+
+namespace WebCore {
+
+MediaPlayerPrivatePhonon::MediaPlayerPrivatePhonon(MediaPlayer* player)
+ : m_player(player)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_mediaObject(new MediaObject())
+ , m_videoWidget(new VideoWidget(0))
+ , m_audioOutput(new AudioOutput())
+ , m_isVisible(false)
+{
+ // Hint to Phonon to disable overlay painting
+ m_videoWidget->setAttribute(Qt::WA_DontShowOnScreen);
+ m_videoWidget->setAttribute(Qt::WA_QuitOnClose, false);
+
+ createPath(m_mediaObject, m_videoWidget);
+ createPath(m_mediaObject, m_audioOutput);
+
+ // Make sure we get updates for each frame
+ m_videoWidget->installEventFilter(this);
+ foreach (QWidget* widget, qFindChildren<QWidget*>(m_videoWidget))
+ widget->installEventFilter(this);
+
+ connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
+ this, SLOT(stateChanged(Phonon::State,Phonon::State)));
+ connect(m_mediaObject, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged()));
+ connect(m_mediaObject, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool)));
+ connect(m_mediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool)));
+ connect(m_mediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int)));
+ connect(m_mediaObject, SIGNAL(finished()), this, SLOT(finished()));
+ connect(m_mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),
+ this, SLOT(currentSourceChanged(Phonon::MediaSource)));
+ connect(m_mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
+ connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
+}
+
+MediaPlayerPrivateInterface* MediaPlayerPrivatePhonon::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivatePhonon(player);
+}
+
+void MediaPlayerPrivatePhonon::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+
+MediaPlayerPrivatePhonon::~MediaPlayerPrivatePhonon()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting videowidget");
+ m_videoWidget->close();
+ delete m_videoWidget;
+ m_videoWidget = 0;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting audiooutput");
+ delete m_audioOutput;
+ m_audioOutput = 0;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting mediaobject");
+ delete m_mediaObject;
+ m_mediaObject = 0;
+}
+
+HashSet<String>& MediaPlayerPrivatePhonon::supportedTypesCache()
+{
+ static HashSet<String> supportedTypes;
+ if (!supportedTypes.isEmpty())
+ return supportedTypes;
+
+ // FIXME: we should rebuild the MIME type cache every time the backend is changed,
+ // however, this would have no effect on MIMETypeRegistry anyway, because it
+ // pulls this data only once.
+
+ QStringList types = Phonon::BackendCapabilities::availableMimeTypes();
+ foreach (const QString& type, types) {
+ QString first = type.split(QLatin1Char('/')).at(0);
+
+ // We're only interested in types which are not supported by WebCore itself.
+ if (first != QLatin1String("video")
+ && first != QLatin1String("audio")
+ && first != QLatin1String("application"))
+ continue;
+ if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
+ continue;
+
+ supportedTypes.add(String(type));
+ }
+
+ // These formats are supported by GStreamer, but not correctly advertised.
+ if (supportedTypes.contains(String("video/x-h264"))
+ || supportedTypes.contains(String("audio/x-m4a"))) {
+ supportedTypes.add(String("video/mp4"));
+ supportedTypes.add(String("audio/aac"));
+ }
+
+ if (supportedTypes.contains(String("video/x-theora")))
+ supportedTypes.add(String("video/ogg"));
+
+ if (supportedTypes.contains(String("audio/x-vorbis")))
+ supportedTypes.add(String("audio/ogg"));
+
+ if (supportedTypes.contains(String("audio/x-wav")))
+ supportedTypes.add(String("audio/wav"));
+
+ return supportedTypes;
+}
+
+void MediaPlayerPrivatePhonon::getSupportedTypes(HashSet<String>& types)
+{
+ types = supportedTypesCache();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivatePhonon::supportsType(const String& type, const String& codecs)
+{
+ if (type.isEmpty())
+ return MediaPlayer::IsNotSupported;
+
+ if (supportedTypesCache().contains(type))
+ return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
+ return MediaPlayer::IsNotSupported;
+}
+
+bool MediaPlayerPrivatePhonon::hasVideo() const
+{
+ bool hasVideo = m_mediaObject->hasVideo();
+ LOG(Media, "MediaPlayerPrivatePhonon::hasVideo() -> %s", hasVideo ? "true" : "false");
+ return hasVideo;
+}
+
+bool MediaPlayerPrivatePhonon::hasAudio() const
+{
+ // FIXME: Phonon::MediaObject does not have such a hasAudio() function
+ bool hasAudio = true;
+ LOG(Media, "MediaPlayerPrivatePhonon::hasAudio() -> %s", hasAudio ? "true" : "false");
+ return hasAudio;
+}
+
+void MediaPlayerPrivatePhonon::load(const String& url)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data());
+
+ // We are now loading
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+
+ // And we don't have any data yet
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+ }
+
+ m_mediaObject->setCurrentSource(QUrl(url));
+ m_audioOutput->setVolume(m_player->volume());
+ setVisible(m_player->visible());
+}
+
+void MediaPlayerPrivatePhonon::cancelLoad()
+{
+ notImplemented();
+}
+
+
+void MediaPlayerPrivatePhonon::play()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::play()");
+ m_mediaObject->play();
+}
+
+void MediaPlayerPrivatePhonon::pause()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::pause()");
+ m_mediaObject->pause();
+}
+
+
+bool MediaPlayerPrivatePhonon::paused() const
+{
+ bool paused = m_mediaObject->state() == Phonon::PausedState;
+ LOG(Media, "MediaPlayerPrivatePhonon::paused() --> %s", paused ? "true" : "false");
+ return paused;
+}
+
+void MediaPlayerPrivatePhonon::seek(float position)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::seek(%f)", position);
+
+ if (!m_mediaObject->isSeekable())
+ return;
+
+ if (position > duration())
+ position = duration();
+
+ m_mediaObject->seek(position * 1000.0f);
+}
+
+bool MediaPlayerPrivatePhonon::seeking() const
+{
+ return false;
+}
+
+float MediaPlayerPrivatePhonon::duration() const
+{
+ if (m_readyState < MediaPlayer::HaveMetadata)
+ return 0.0f;
+
+ float duration = m_mediaObject->totalTime() / 1000.0f;
+
+ if (duration == 0.0f) // We are streaming
+ duration = std::numeric_limits<float>::infinity();
+
+ LOG(Media, "MediaPlayerPrivatePhonon::duration() --> %f", duration);
+ return duration;
+}
+
+float MediaPlayerPrivatePhonon::currentTime() const
+{
+ float currentTime = m_mediaObject->currentTime() / 1000.0f;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::currentTime() --> %f", currentTime);
+ return currentTime;
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivatePhonon::buffered() const
+{
+ notImplemented();
+ return TimeRanges::create();
+}
+
+float MediaPlayerPrivatePhonon::maxTimeSeekable() const
+{
+ notImplemented();
+ return 0.0f;
+}
+
+unsigned MediaPlayerPrivatePhonon::bytesLoaded() const
+{
+ notImplemented();
+ return 0;
+}
+
+unsigned MediaPlayerPrivatePhonon::totalBytes() const
+{
+ //notImplemented();
+ return 0;
+}
+
+void MediaPlayerPrivatePhonon::setRate(float)
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivatePhonon::setVolume(float volume)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::setVolume()");
+ m_audioOutput->setVolume(volume);
+}
+
+void MediaPlayerPrivatePhonon::setMuted(bool muted)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::setMuted()");
+ m_audioOutput->setMuted(muted);
+}
+
+MediaPlayer::NetworkState MediaPlayerPrivatePhonon::networkState() const
+{
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState"));
+ LOG(Media, "MediaPlayerPrivatePhonon::networkState() --> %s", networkStates.valueToKey(m_networkState));
+ return m_networkState;
+}
+
+MediaPlayer::ReadyState MediaPlayerPrivatePhonon::readyState() const
+{
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState"));
+ LOG(Media, "MediaPlayerPrivatePhonon::readyState() --> %s", readyStates.valueToKey(m_readyState));
+ return m_readyState;
+}
+
+void MediaPlayerPrivatePhonon::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ Phonon::State phononState = m_mediaObject->state();
+
+ if (phononState == Phonon::StoppedState) {
+ if (m_readyState < MediaPlayer::HaveMetadata) {
+ m_networkState = MediaPlayer::Loading; // FIXME: should this be MediaPlayer::Idle?
+ m_readyState = MediaPlayer::HaveMetadata;
+ m_mediaObject->pause();
+ }
+ } else if (phononState == Phonon::PausedState) {
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (phononState == Phonon::ErrorState) {
+ if (!m_mediaObject || m_mediaObject->errorType() == Phonon::FatalError) {
+ // FIXME: is it possile to differentiate between different types of errors
+ m_networkState = MediaPlayer::NetworkError;
+ m_readyState = MediaPlayer::HaveNothing;
+ cancelLoad();
+ } else
+ m_mediaObject->pause();
+ }
+
+ if (seeking())
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (m_networkState != oldNetworkState) {
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState"));
+ LOG(Media, "Network state changed from '%s' to '%s'",
+ networkStates.valueToKey(oldNetworkState),
+ networkStates.valueToKey(m_networkState));
+ m_player->networkStateChanged();
+ }
+
+ if (m_readyState != oldReadyState) {
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState"));
+ LOG(Media, "Ready state changed from '%s' to '%s'",
+ readyStates.valueToKey(oldReadyState),
+ readyStates.valueToKey(m_readyState));
+ m_player->readyStateChanged();
+ }
+}
+
+void MediaPlayerPrivatePhonon::setVisible(bool visible)
+{
+ m_isVisible = visible;
+ LOG(Media, "MediaPlayerPrivatePhonon::setVisible(%s)", visible ? "true" : "false");
+
+ m_videoWidget->setVisible(m_isVisible);
+}
+
+void MediaPlayerPrivatePhonon::setSize(const IntSize& newSize)
+{
+ if (!m_videoWidget)
+ return;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::setSize(%d,%d)",
+ newSize.width(), newSize.height());
+
+ QRect currentRect = m_videoWidget->rect();
+
+ if (newSize.width() != currentRect.width() || newSize.height() != currentRect.height())
+ m_videoWidget->resize(newSize.width(), newSize.height());
+}
+
+IntSize MediaPlayerPrivatePhonon::naturalSize() const
+{
+ if (!hasVideo()) {
+ LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
+ 0, 0);
+ return IntSize();
+ }
+
+ if (m_readyState < MediaPlayer::HaveMetadata) {
+ LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
+ 0, 0);
+ return IntSize();
+ }
+
+ QSize videoSize = m_videoWidget->sizeHint();
+ IntSize naturalSize(videoSize.width(), videoSize.height());
+ LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
+ naturalSize.width(), naturalSize.height());
+ return naturalSize;
+}
+
+bool MediaPlayerPrivatePhonon::eventFilter(QObject* obj, QEvent* event)
+{
+ if (event->type() == QEvent::UpdateRequest)
+ m_player->repaint();
+
+ return QObject::eventFilter(obj, event);
+}
+
+void MediaPlayerPrivatePhonon::paint(GraphicsContext* graphicsContect, const IntRect& rect)
+{
+ if (graphicsContect->paintingDisabled())
+ return;
+
+ if (!m_isVisible)
+ return;
+
+ QPainter* painter = graphicsContect->platformContext();
+
+ painter->fillRect(rect, Qt::black);
+
+ m_videoWidget->render(painter, QPoint(rect.x(), rect.y()),
+ QRegion(0, 0, rect.width(), rect.height()));
+}
+
+// ====================== Phonon::MediaObject signals ======================
+
+void MediaPlayerPrivatePhonon::stateChanged(Phonon::State newState, Phonon::State oldState)
+{
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState"));
+ LOG(Media, "MediaPlayerPrivatePhonon::stateChanged(newState=%s, oldState=%s)",
+ phononStates.valueToKey(newState), phononStates.valueToKey(oldState));
+
+ updateStates();
+}
+
+void MediaPlayerPrivatePhonon::metaDataChanged()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::metaDataChanged()");
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::seekableChanged(bool)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::hasVideoChanged(bool hasVideo)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::hasVideoChanged(%s)", hasVideo ? "true" : "false");
+}
+
+void MediaPlayerPrivatePhonon::bufferStatus(int)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::finished()
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::currentSourceChanged(const Phonon::MediaSource&)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::aboutToFinish()
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::totalTimeChanged(qint64 totalTime)
+{
+#if OS(WINDOWS)
+ LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%I64d)", totalTime);
+#else
+ LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%lld)", totalTime);
+#endif
+ LOG_MEDIAOBJECT();
+}
+
+} // namespace WebCore
+
+#include "moc_MediaPlayerPrivatePhonon.cpp"
diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
new file mode 100644
index 0000000..d793675
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
@@ -0,0 +1,153 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Apple Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MediaPlayerPrivatePhonon_h
+#define MediaPlayerPrivatePhonon_h
+
+#include "MediaPlayerPrivate.h"
+
+#include <QObject>
+#include <phononnamespace.h>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+class QUrl;
+
+namespace Phonon {
+ class MediaObject;
+ class VideoWidget;
+ class AudioOutput;
+ class MediaSource;
+}
+QT_END_NAMESPACE
+
+namespace WebCore {
+
+ class MediaPlayerPrivatePhonon : public QObject, public MediaPlayerPrivateInterface {
+
+ Q_OBJECT
+
+ public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+ ~MediaPlayerPrivatePhonon();
+
+ // These enums are used for debugging
+ Q_ENUMS(ReadyState NetworkState PhononState)
+
+ enum ReadyState {
+ HaveNothing,
+ HaveMetadata,
+ HaveCurrentData,
+ HaveFutureData,
+ HaveEnoughData
+ };
+
+ enum NetworkState {
+ Empty,
+ Idle,
+ Loading,
+ Loaded,
+ FormatError,
+ NetworkError,
+ DecodeError
+ };
+
+ enum PhononState {
+ LoadingState,
+ StoppedState,
+ PlayingState,
+ BufferingState,
+ PausedState,
+ ErrorState
+ };
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+ bool hasAudio() const;
+
+ void load(const String &url);
+ void cancelLoad();
+
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float);
+
+ void setRate(float);
+ void setVolume(float);
+ void setMuted(bool);
+
+ MediaPlayer::NetworkState networkState() const;
+ MediaPlayer::ReadyState readyState() const;
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setSize(const IntSize&);
+
+ void paint(GraphicsContext*, const IntRect&);
+
+ protected:
+ bool eventFilter(QObject*, QEvent*);
+
+ private slots:
+ void stateChanged(Phonon::State, Phonon::State);
+ void metaDataChanged();
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+ void bufferStatus(int);
+ void finished();
+ void currentSourceChanged(const Phonon::MediaSource&);
+ void aboutToFinish();
+ void totalTimeChanged(qint64);
+
+ private:
+ MediaPlayerPrivatePhonon(MediaPlayer*);
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static HashSet<String>& supportedTypesCache();
+ static bool isAvailable() { return true; }
+
+ void updateStates();
+
+ MediaPlayer* m_player;
+
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+
+ Phonon::MediaObject* m_mediaObject;
+ Phonon::VideoWidget* m_videoWidget;
+ Phonon::AudioOutput* m_audioOutput;
+
+ bool m_isVisible;
+ };
+}
+
+#endif // MediaPlayerPrivatePhonon_h
diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
new file mode 100644
index 0000000..dd4b6e6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
@@ -0,0 +1,674 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "MediaPlayerPrivateQt.h"
+
+#include "FrameLoaderClientQt.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLMediaElement.h"
+#include "HTMLVideoElement.h"
+#include "QtNAMThreadSafeProxy.h"
+#include "NetworkingContext.h"
+#include "NotImplemented.h"
+#include "RenderVideo.h"
+#include "TimeRanges.h"
+#include "Widget.h"
+#include "qwebframe.h"
+#include "qwebpage.h"
+
+#include <QGraphicsScene>
+#include <QGraphicsVideoItem>
+#include <QMediaPlayerControl>
+#include <QMediaService>
+#include <QNetworkAccessManager>
+#include <QNetworkCookieJar>
+#include <QNetworkRequest>
+#include <QPainter>
+#include <QPoint>
+#include <QRect>
+#include <QStyleOptionGraphicsItem>
+#include <QTime>
+#include <QTimer>
+#include <QUrl>
+#include <limits>
+#include <wtf/HashSet.h>
+#include <wtf/text/CString.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "texmap/TextureMapperPlatformLayer.h"
+#endif
+
+using namespace WTF;
+
+namespace WebCore {
+
+MediaPlayerPrivateInterface* MediaPlayerPrivateQt::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivateQt(player);
+}
+
+void MediaPlayerPrivateQt::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+void MediaPlayerPrivateQt::getSupportedTypes(HashSet<String> &supported)
+{
+ QStringList types = QMediaPlayer::supportedMimeTypes();
+
+ for (int i = 0; i < types.size(); i++) {
+ QString mime = types.at(i);
+ if (mime.startsWith("audio/") || mime.startsWith("video/"))
+ supported.add(mime);
+ }
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivateQt::supportsType(const String& mime, const String& codec)
+{
+ if (!mime.startsWith("audio/") && !mime.startsWith("video/"))
+ return MediaPlayer::IsNotSupported;
+
+ if (QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMultimediaKit::ProbablySupported)
+ return MediaPlayer::IsSupported;
+
+ return MediaPlayer::MayBeSupported;
+}
+
+MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player)
+ : m_webCorePlayer(player)
+ , m_mediaPlayer(new QMediaPlayer)
+ , m_mediaPlayerControl(0)
+ , m_videoItem(new QGraphicsVideoItem)
+ , m_videoScene(new QGraphicsScene)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_currentSize(0, 0)
+ , m_naturalSize(RenderVideo::defaultSize())
+ , m_isVisible(false)
+ , m_isSeeking(false)
+ , m_composited(false)
+ , m_queuedSeek(-1)
+ , m_preload(MediaPlayer::Auto)
+{
+ m_mediaPlayer->bind(m_videoItem);
+ m_videoScene->addItem(m_videoItem);
+
+ // Signal Handlers
+ connect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
+ this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus)));
+ connect(m_mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)),
+ this, SLOT(stateChanged(QMediaPlayer::State)));
+ connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)),
+ this, SLOT(handleError(QMediaPlayer::Error)));
+ connect(m_mediaPlayer, SIGNAL(bufferStatusChanged(int)),
+ this, SLOT(bufferStatusChanged(int)));
+ connect(m_mediaPlayer, SIGNAL(durationChanged(qint64)),
+ this, SLOT(durationChanged(qint64)));
+ connect(m_mediaPlayer, SIGNAL(positionChanged(qint64)),
+ this, SLOT(positionChanged(qint64)));
+ connect(m_mediaPlayer, SIGNAL(volumeChanged(int)),
+ this, SLOT(volumeChanged(int)));
+ connect(m_mediaPlayer, SIGNAL(mutedChanged(bool)),
+ this, SLOT(mutedChanged(bool)));
+ connect(m_videoScene, SIGNAL(changed(QList<QRectF>)),
+ this, SLOT(repaint()));
+ connect(m_videoItem, SIGNAL(nativeSizeChanged(QSizeF)),
+ this, SLOT(nativeSizeChanged(QSizeF)));
+
+ // Grab the player control
+ if (QMediaService* service = m_mediaPlayer->service()) {
+ m_mediaPlayerControl = qobject_cast<QMediaPlayerControl *>(
+ service->requestControl(QMediaPlayerControl_iid));
+ }
+}
+
+MediaPlayerPrivateQt::~MediaPlayerPrivateQt()
+{
+ m_mediaPlayer->disconnect(this);
+ m_mediaPlayer->stop();
+ m_mediaPlayer->setMedia(QMediaContent());
+
+ delete m_mediaPlayer;
+ delete m_videoScene;
+}
+
+bool MediaPlayerPrivateQt::hasVideo() const
+{
+ return m_mediaPlayer->isVideoAvailable();
+}
+
+bool MediaPlayerPrivateQt::hasAudio() const
+{
+ return true;
+}
+
+void MediaPlayerPrivateQt::load(const String& url)
+{
+ m_mediaUrl = url;
+
+ // QtMultimedia does not have an API to throttle loading
+ // so we handle this ourselves by delaying the load
+ if (m_preload == MediaPlayer::None) {
+ m_delayingLoad = true;
+ return;
+ }
+
+ commitLoad(url);
+}
+
+void MediaPlayerPrivateQt::commitLoad(const String& url)
+{
+ // We are now loading
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_webCorePlayer->networkStateChanged();
+ }
+
+ // And we don't have any data yet
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_webCorePlayer->readyStateChanged();
+ }
+
+ const QUrl rUrl = QUrl(QString(url));
+ const QString scheme = rUrl.scheme().toLower();
+
+ // Grab the client media element
+ HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient());
+
+ // Construct the media content with a network request if the resource is http[s]
+ if (scheme == "http" || scheme == "https") {
+ QNetworkRequest request = QNetworkRequest(rUrl);
+
+ // Grab the current document
+ Document* document = element->document();
+ if (!document)
+ document = element->ownerDocument();
+
+ // Grab the frame and network manager
+ Frame* frame = document ? document->frame() : 0;
+ QNetworkAccessManager* manager = frame ? frame->loader()->networkingContext()->networkAccessManager() : 0;
+ FrameLoaderClientQt* frameLoader = frame ? static_cast<FrameLoaderClientQt*>(frame->loader()->client()) : 0;
+
+ if (document && manager) {
+ // Set the cookies
+ QtNAMThreadSafeProxy managerProxy(manager);
+ QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(rUrl);
+
+ // Don't set the header if there are no cookies.
+ // This prevents a warning from being emitted.
+ if (!cookies.isEmpty())
+ request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
+
+ // Set the refferer, but not when requesting insecure content from a secure page
+ QUrl documentUrl = QUrl(QString(document->documentURI()));
+ if (documentUrl.scheme().toLower() == "http" || scheme == "https")
+ request.setRawHeader("Referer", documentUrl.toEncoded());
+
+ // Set the user agent
+ request.setRawHeader("User-Agent", frameLoader->userAgent(rUrl).utf8().data());
+ }
+
+ m_mediaPlayer->setMedia(QMediaContent(request));
+ } else {
+ // Otherwise, just use the URL
+ m_mediaPlayer->setMedia(QMediaContent(rUrl));
+ }
+
+ // Set the current volume and mute status
+ // We get these from the element, rather than the player, in case we have
+ // transitioned from a media engine which doesn't support muting, to a media
+ // engine which does.
+ m_mediaPlayer->setMuted(element->muted());
+ m_mediaPlayer->setVolume(static_cast<int>(element->volume() * 100.0));
+
+ // Setting a media source will start loading the media, but we need
+ // to pre-roll as well to get video size-hints and buffer-status
+ if (element->paused())
+ m_mediaPlayer->pause();
+ else
+ m_mediaPlayer->play();
+}
+
+void MediaPlayerPrivateQt::resumeLoad()
+{
+ m_delayingLoad = false;
+
+ if (!m_mediaUrl.isNull())
+ commitLoad(m_mediaUrl);
+}
+
+void MediaPlayerPrivateQt::cancelLoad()
+{
+ m_mediaPlayer->setMedia(QMediaContent());
+ updateStates();
+}
+
+void MediaPlayerPrivateQt::prepareToPlay()
+{
+ if (m_mediaPlayer->media().isNull() || m_delayingLoad)
+ resumeLoad();
+}
+
+void MediaPlayerPrivateQt::play()
+{
+ if (m_mediaPlayer->state() != QMediaPlayer::PlayingState)
+ m_mediaPlayer->play();
+}
+
+void MediaPlayerPrivateQt::pause()
+{
+ if (m_mediaPlayer->state() == QMediaPlayer::PlayingState)
+ m_mediaPlayer->pause();
+}
+
+bool MediaPlayerPrivateQt::paused() const
+{
+ return (m_mediaPlayer->state() != QMediaPlayer::PlayingState);
+}
+
+void MediaPlayerPrivateQt::seek(float position)
+{
+ if (!m_mediaPlayer->isSeekable())
+ return;
+
+ if (m_mediaPlayerControl && !m_mediaPlayerControl->availablePlaybackRanges().contains(position * 1000))
+ return;
+
+ if (m_isSeeking)
+ return;
+
+ if (position > duration())
+ position = duration();
+
+ // Seeking is most reliable when we're paused.
+ // Webkit will try to pause before seeking, but due to the asynchronous nature
+ // of the backend, the player may not actually be paused yet.
+ // In this case, we should queue the seek and wait until pausing has completed
+ // before attempting to seek.
+ if (m_mediaPlayer->state() == QMediaPlayer::PlayingState) {
+ m_mediaPlayer->pause();
+ m_isSeeking = true;
+ m_queuedSeek = static_cast<qint64>(position * 1000);
+
+ // Set a timeout, so that in the event that we don't get a state changed
+ // signal, we still attempt the seek.
+ QTimer::singleShot(1000, this, SLOT(queuedSeekTimeout()));
+ } else {
+ m_isSeeking = true;
+ m_mediaPlayer->setPosition(static_cast<qint64>(position * 1000));
+
+ // Set a timeout, in case we don't get a position changed signal
+ QTimer::singleShot(10000, this, SLOT(seekTimeout()));
+ }
+}
+
+bool MediaPlayerPrivateQt::seeking() const
+{
+ return m_isSeeking;
+}
+
+float MediaPlayerPrivateQt::duration() const
+{
+ if (m_readyState < MediaPlayer::HaveMetadata)
+ return 0.0f;
+
+ float duration = m_mediaPlayer->duration() / 1000.0f;
+
+ // We are streaming
+ if (duration <= 0.0f)
+ duration = std::numeric_limits<float>::infinity();
+
+ return duration;
+}
+
+float MediaPlayerPrivateQt::currentTime() const
+{
+ return m_mediaPlayer->position() / 1000.0f;
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivateQt::buffered() const
+{
+ RefPtr<TimeRanges> buffered = TimeRanges::create();
+
+ if (!m_mediaPlayerControl)
+ return buffered;
+
+ QMediaTimeRange playbackRanges = m_mediaPlayerControl->availablePlaybackRanges();
+
+ foreach (const QMediaTimeInterval interval, playbackRanges.intervals()) {
+ float rangeMin = static_cast<float>(interval.start()) / 1000.0f;
+ float rangeMax = static_cast<float>(interval.end()) / 1000.0f;
+ buffered->add(rangeMin, rangeMax);
+ }
+
+ return buffered.release();
+}
+
+float MediaPlayerPrivateQt::maxTimeSeekable() const
+{
+ if (!m_mediaPlayerControl)
+ return 0;
+
+ return static_cast<float>(m_mediaPlayerControl->availablePlaybackRanges().latestTime()) / 1000.0f;
+}
+
+unsigned MediaPlayerPrivateQt::bytesLoaded() const
+{
+ QLatin1String bytesLoadedKey("bytes-loaded");
+ if (m_mediaPlayer->availableExtendedMetaData().contains(bytesLoadedKey))
+ return m_mediaPlayer->extendedMetaData(bytesLoadedKey).toInt();
+
+ return m_mediaPlayer->bufferStatus();
+}
+
+unsigned MediaPlayerPrivateQt::totalBytes() const
+{
+ if (m_mediaPlayer->availableMetaData().contains(QtMultimediaKit::Size))
+ return m_mediaPlayer->metaData(QtMultimediaKit::Size).toInt();
+
+ return 100;
+}
+
+void MediaPlayerPrivateQt::setPreload(MediaPlayer::Preload preload)
+{
+ m_preload = preload;
+ if (m_delayingLoad && m_preload != MediaPlayer::None)
+ resumeLoad();
+}
+
+void MediaPlayerPrivateQt::setRate(float rate)
+{
+ m_mediaPlayer->setPlaybackRate(rate);
+}
+
+void MediaPlayerPrivateQt::setVolume(float volume)
+{
+ m_mediaPlayer->setVolume(static_cast<int>(volume * 100.0));
+}
+
+bool MediaPlayerPrivateQt::supportsMuting() const
+{
+ return true;
+}
+
+void MediaPlayerPrivateQt::setMuted(bool muted)
+{
+ m_mediaPlayer->setMuted(muted);
+}
+
+MediaPlayer::NetworkState MediaPlayerPrivateQt::networkState() const
+{
+ return m_networkState;
+}
+
+MediaPlayer::ReadyState MediaPlayerPrivateQt::readyState() const
+{
+ return m_readyState;
+}
+
+void MediaPlayerPrivateQt::setVisible(bool visible)
+{
+ m_isVisible = visible;
+}
+
+void MediaPlayerPrivateQt::mediaStatusChanged(QMediaPlayer::MediaStatus)
+{
+ updateStates();
+}
+
+void MediaPlayerPrivateQt::handleError(QMediaPlayer::Error)
+{
+ updateStates();
+}
+
+void MediaPlayerPrivateQt::stateChanged(QMediaPlayer::State state)
+{
+ if (state != QMediaPlayer::PlayingState && m_isSeeking && m_queuedSeek >= 0) {
+ m_mediaPlayer->setPosition(m_queuedSeek);
+ m_queuedSeek = -1;
+ }
+}
+
+void MediaPlayerPrivateQt::nativeSizeChanged(const QSizeF& size)
+{
+ LOG(Media, "MediaPlayerPrivateQt::naturalSizeChanged(%dx%d)",
+ size.toSize().width(), size.toSize().height());
+
+ if (!size.isValid())
+ return;
+
+ m_naturalSize = size.toSize();
+ m_webCorePlayer->sizeChanged();
+}
+
+void MediaPlayerPrivateQt::queuedSeekTimeout()
+{
+ // If we haven't heard anything, assume the player is now paused
+ // and we can attempt the seek
+ if (m_isSeeking && m_queuedSeek >= 0) {
+ m_mediaPlayer->setPosition(m_queuedSeek);
+ m_queuedSeek = -1;
+
+ // Set a timeout, in case we don't get a position changed signal
+ QTimer::singleShot(10000, this, SLOT(seekTimeout()));
+ }
+}
+
+void MediaPlayerPrivateQt::seekTimeout()
+{
+ // If we haven't heard anything, assume the seek succeeded
+ if (m_isSeeking) {
+ m_webCorePlayer->timeChanged();
+ m_isSeeking = false;
+ }
+}
+
+void MediaPlayerPrivateQt::positionChanged(qint64)
+{
+ // Only propagate this event if we are seeking
+ if (m_isSeeking && m_queuedSeek == -1) {
+ m_webCorePlayer->timeChanged();
+ m_isSeeking = false;
+ }
+}
+
+void MediaPlayerPrivateQt::bufferStatusChanged(int)
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivateQt::durationChanged(qint64)
+{
+ m_webCorePlayer->durationChanged();
+}
+
+void MediaPlayerPrivateQt::volumeChanged(int volume)
+{
+ m_webCorePlayer->volumeChanged(static_cast<float>(volume) / 100.0);
+}
+
+void MediaPlayerPrivateQt::mutedChanged(bool muted)
+{
+ m_webCorePlayer->muteChanged(muted);
+}
+
+void MediaPlayerPrivateQt::updateStates()
+{
+ // Store the old states so that we can detect a change and raise change events
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ QMediaPlayer::MediaStatus currentStatus = m_mediaPlayer->mediaStatus();
+ QMediaPlayer::Error currentError = m_mediaPlayer->error();
+
+ if (currentError != QMediaPlayer::NoError) {
+ m_readyState = MediaPlayer::HaveNothing;
+ if (currentError == QMediaPlayer::FormatError)
+ m_networkState = MediaPlayer::FormatError;
+ else
+ m_networkState = MediaPlayer::NetworkError;
+ } else if (currentStatus == QMediaPlayer::UnknownMediaStatus
+ || currentStatus == QMediaPlayer::NoMedia) {
+ m_networkState = MediaPlayer::Idle;
+ m_readyState = MediaPlayer::HaveNothing;
+ } else if (currentStatus == QMediaPlayer::LoadingMedia) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveNothing;
+ } else if (currentStatus == QMediaPlayer::LoadedMedia) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveMetadata;
+ } else if (currentStatus == QMediaPlayer::BufferingMedia) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveFutureData;
+ } else if (currentStatus == QMediaPlayer::StalledMedia) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveCurrentData;
+ } else if (currentStatus == QMediaPlayer::BufferedMedia
+ || currentStatus == QMediaPlayer::EndOfMedia) {
+ m_networkState = MediaPlayer::Idle;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (currentStatus == QMediaPlayer::InvalidMedia) {
+ m_networkState = MediaPlayer::NetworkError;
+ m_readyState = MediaPlayer::HaveNothing;
+ }
+
+ // Log the state changes and raise the state change events
+ // NB: The readyStateChanged event must come before the networkStateChanged event.
+ // Breaking this invariant will cause the resource selection algorithm for multiple
+ // sources to fail.
+ if (m_readyState != oldReadyState)
+ m_webCorePlayer->readyStateChanged();
+
+ if (m_networkState != oldNetworkState)
+ m_webCorePlayer->networkStateChanged();
+}
+
+void MediaPlayerPrivateQt::setSize(const IntSize& size)
+{
+ LOG(Media, "MediaPlayerPrivateQt::setSize(%dx%d)",
+ size.width(), size.height());
+
+ if (size == m_currentSize)
+ return;
+
+ m_currentSize = size;
+ m_videoItem->setSize(QSizeF(QSize(size)));
+}
+
+IntSize MediaPlayerPrivateQt::naturalSize() const
+{
+ if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) {
+ LOG(Media, "MediaPlayerPrivateQt::naturalSize() -> 0x0 (!hasVideo || !haveMetaData)");
+ return IntSize();
+ }
+
+ LOG(Media, "MediaPlayerPrivateQt::naturalSize() -> %dx%d (m_naturalSize)",
+ m_naturalSize.width(), m_naturalSize.height());
+
+ return m_naturalSize;
+}
+
+void MediaPlayerPrivateQt::paint(GraphicsContext* context, const IntRect& rect)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_composited)
+ return;
+#endif
+ if (context->paintingDisabled())
+ return;
+
+ if (!m_isVisible)
+ return;
+
+ QPainter* painter = context->platformContext();
+ m_videoScene->render(painter, QRectF(QRect(rect)), m_videoItem->sceneBoundingRect());
+}
+
+void MediaPlayerPrivateQt::repaint()
+{
+ m_webCorePlayer->repaint();
+}
+
+#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
+
+class TextureMapperVideoLayerQt : public virtual TextureMapperVideoLayer {
+public:
+ TextureMapperVideoLayerQt(QGraphicsVideoItem* videoItem)
+ : m_videoItem(videoItem)
+ {
+ }
+
+ virtual void setPlatformLayerClient(TextureMapperLayerClient* client)
+ {
+ m_client = client;
+ }
+
+ virtual void paint(GraphicsContext* context)
+ {
+ if (!m_videoItem)
+ return;
+
+ QStyleOptionGraphicsItem opt;
+ opt.exposedRect = m_videoItem.data()->sceneBoundingRect();
+ opt.rect = opt.exposedRect.toRect();
+ m_videoItem.data()->paint(context->platformContext(), &opt);
+ }
+
+ virtual IntSize size() const
+ {
+ return m_videoItem ? IntSize(m_videoItem.data()->size().width(), m_videoItem.data()->size().height()) : IntSize();
+ }
+
+ QWeakPointer<QGraphicsVideoItem> m_videoItem;
+ TextureMapperLayerClient* m_client;
+};
+
+
+void MediaPlayerPrivateQt::acceleratedRenderingStateChanged()
+{
+ MediaPlayerClient* client = m_webCorePlayer->mediaPlayerClient();
+ bool composited = client->mediaPlayerRenderingCanBeAccelerated(m_webCorePlayer);
+ if (composited == m_composited)
+ return;
+
+ m_composited = composited;
+ if (composited)
+ m_platformLayer = new TextureMapperVideoLayerQt(m_videoItem);
+}
+
+PlatformLayer* MediaPlayerPrivateQt::platformLayer() const
+{
+ return m_composited ? m_platformLayer.get() : 0;
+}
+#endif
+
+PlatformMedia MediaPlayerPrivateQt::platformMedia() const
+{
+ PlatformMedia pm;
+ pm.type = PlatformMedia::QtMediaPlayerType;
+ pm.media.qtMediaPlayer = const_cast<MediaPlayerPrivateQt*>(this);
+ return pm;
+}
+
+} // namespace WebCore
+
+#include "moc_MediaPlayerPrivateQt.cpp"
diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h
new file mode 100644
index 0000000..93c9d1c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h
@@ -0,0 +1,156 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MediaPlayerPrivateQt_h
+#define MediaPlayerPrivateQt_h
+
+#include "MediaPlayerPrivate.h"
+
+#include <QMediaPlayer>
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+class QMediaPlayerControl;
+class QGraphicsVideoItem;
+class QGraphicsScene;
+QT_END_NAMESPACE
+
+namespace WebCore {
+
+class TextureMapperVideoLayer;
+
+class MediaPlayerPrivateQt : public QObject, public MediaPlayerPrivateInterface {
+
+ Q_OBJECT
+
+public:
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+ ~MediaPlayerPrivateQt();
+
+ static void registerMediaEngine(MediaEngineRegistrar);
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String&, const String&);
+ static bool isAvailable() { return true; }
+
+ bool hasVideo() const;
+ bool hasAudio() const;
+
+ void load(const String &url);
+ void commitLoad(const String& url);
+ void resumeLoad();
+ void cancelLoad();
+
+ void play();
+ void pause();
+ void prepareToPlay();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float);
+
+ void setRate(float);
+ void setVolume(float);
+
+ bool supportsMuting() const;
+ void setMuted(bool);
+
+ void setPreload(MediaPlayer::Preload);
+
+ MediaPlayer::NetworkState networkState() const;
+ MediaPlayer::ReadyState readyState() const;
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+
+ IntSize naturalSize() const;
+ void setSize(const IntSize&);
+
+ void paint(GraphicsContext*, const IntRect&);
+
+ bool supportsFullscreen() const { return false; }
+
+#if USE(ACCELERATED_COMPOSITING)
+#if USE(TEXTURE_MAPPER)
+ // whether accelerated rendering is supported by the media engine for the current media.
+ virtual bool supportsAcceleratedRendering() const { return true; }
+ // called when the rendering system flips the into or out of accelerated rendering mode.
+ virtual void acceleratedRenderingStateChanged();
+ // returns an object that can be directly composited via GraphicsLayerQt (essentially a QGraphicsItem*)
+ virtual PlatformLayer* platformLayer() const;
+#else
+ virtual bool supportsAcceleratedRendering() const { return false; }
+ virtual void acceleratedRenderingStateChanged() { }
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
+#endif
+
+ virtual PlatformMedia platformMedia() const;
+private slots:
+ void mediaStatusChanged(QMediaPlayer::MediaStatus);
+ void handleError(QMediaPlayer::Error);
+ void stateChanged(QMediaPlayer::State);
+ void nativeSizeChanged(const QSizeF&);
+ void queuedSeekTimeout();
+ void seekTimeout();
+ void positionChanged(qint64);
+ void durationChanged(qint64);
+ void bufferStatusChanged(int);
+ void volumeChanged(int);
+ void mutedChanged(bool);
+ void repaint();
+
+private:
+ void updateStates();
+
+private:
+ MediaPlayerPrivateQt(MediaPlayer*);
+
+ MediaPlayer* m_webCorePlayer;
+ QMediaPlayer* m_mediaPlayer;
+ QMediaPlayerControl* m_mediaPlayerControl;
+ QGraphicsVideoItem* m_videoItem;
+ QGraphicsScene* m_videoScene;
+#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
+ OwnPtr<TextureMapperVideoLayer> m_platformLayer;
+#endif
+
+ mutable MediaPlayer::NetworkState m_networkState;
+ mutable MediaPlayer::ReadyState m_readyState;
+
+ IntSize m_currentSize;
+ IntSize m_naturalSize;
+ bool m_isVisible;
+ bool m_isSeeking;
+ bool m_composited;
+ qint64 m_queuedSeek;
+ MediaPlayer::Preload m_preload;
+ bool m_delayingLoad;
+ String m_mediaUrl;
+
+};
+}
+
+#endif // MediaPlayerPrivateQt_h
diff --git a/Source/WebCore/platform/graphics/qt/PathQt.cpp b/Source/WebCore/platform/graphics/qt/PathQt.cpp
new file mode 100644
index 0000000..571b405
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/PathQt.cpp
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * 2006 Rob Buis <buis@kde.org>
+ * 2009, 2010 Dirk Schulze <krit@webkit.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "PlatformString.h"
+#include "StrokeStyleApplier.h"
+#include <QPainterPath>
+#include <QTransform>
+#include <QString>
+#include <wtf/OwnPtr.h>
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+namespace WebCore {
+
+Path::Path()
+{
+}
+
+Path::~Path()
+{
+}
+
+Path::Path(const Path& other)
+ : m_path(other.m_path)
+{
+}
+
+Path& Path::operator=(const Path& other)
+{
+ m_path = other.m_path;
+ return *this;
+}
+
+static inline bool areCollinear(const QPointF& a, const QPointF& b, const QPointF& c)
+{
+ // Solved from comparing the slopes of a to b and b to c: (ay-by)/(ax-bx) == (cy-by)/(cx-bx)
+ return qFuzzyCompare((c.y() - b.y()) * (a.x() - b.x()), (a.y() - b.y()) * (c.x() - b.x()));
+}
+
+static inline bool withinRange(qreal p, qreal a, qreal b)
+{
+ return (p >= a && p <= b) || (p >= b && p <= a);
+}
+
+// Check whether a point is on the border
+static bool isPointOnPathBorder(const QPolygonF& border, const QPointF& p)
+{
+ // null border doesn't contain points
+ if (border.isEmpty())
+ return false;
+
+ QPointF p1 = border.at(0);
+ QPointF p2;
+
+ for (int i = 1; i < border.size(); ++i) {
+ p2 = border.at(i);
+ if (areCollinear(p, p1, p2)
+ // Once we know that the points are collinear we
+ // only need to check one of the coordinates
+ && (qAbs(p2.x() - p1.x()) > qAbs(p2.y() - p1.y()) ?
+ withinRange(p.x(), p1.x(), p2.x()) :
+ withinRange(p.y(), p1.y(), p2.y()))) {
+ return true;
+ }
+ p1 = p2;
+ }
+ return false;
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ Qt::FillRule savedRule = m_path.fillRule();
+ const_cast<QPainterPath*>(&m_path)->setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
+
+ bool contains = m_path.contains(point);
+
+ if (!contains) {
+ // check whether the point is on the border
+ contains = isPointOnPathBorder(m_path.toFillPolygon(), point);
+ }
+
+ const_cast<QPainterPath*>(&m_path)->setFillRule(savedRule);
+ return contains;
+}
+
+static GraphicsContext* scratchContext()
+{
+ static QImage image(1, 1, QImage::Format_ARGB32_Premultiplied);
+ static QPainter painter(&image);
+ static GraphicsContext* context = new GraphicsContext(&painter);
+ return context;
+}
+
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+
+ QPainterPathStroker stroke;
+ GraphicsContext* context = scratchContext();
+ applier->strokeStyle(context);
+
+ QPen pen = context->platformContext()->pen();
+ stroke.setWidth(pen.widthF());
+ stroke.setCapStyle(pen.capStyle());
+ stroke.setJoinStyle(pen.joinStyle());
+ stroke.setMiterLimit(pen.miterLimit());
+ stroke.setDashPattern(pen.dashPattern());
+ stroke.setDashOffset(pen.dashOffset());
+
+ return stroke.createStroke(m_path).contains(point);
+}
+
+void Path::translate(const FloatSize& size)
+{
+ QTransform matrix;
+ matrix.translate(size.width(), size.height());
+ m_path = m_path * matrix;
+}
+
+FloatRect Path::boundingRect() const
+{
+ return m_path.boundingRect();
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ GraphicsContext* context = scratchContext();
+ QPainterPathStroker stroke;
+ if (applier) {
+ applier->strokeStyle(context);
+
+ QPen pen = context->platformContext()->pen();
+ stroke.setWidth(pen.widthF());
+ stroke.setCapStyle(pen.capStyle());
+ stroke.setJoinStyle(pen.joinStyle());
+ stroke.setMiterLimit(pen.miterLimit());
+ stroke.setDashPattern(pen.dashPattern());
+ stroke.setDashOffset(pen.dashOffset());
+ }
+ return stroke.createStroke(m_path).boundingRect();
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ m_path.moveTo(point);
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ m_path.lineTo(p);
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
+{
+ m_path.quadTo(cp, p);
+}
+
+void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
+{
+ m_path.cubicTo(cp1, cp2, p);
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ FloatPoint p0(m_path.currentPosition());
+
+ FloatPoint p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
+ FloatPoint p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
+ float p1p0_length = sqrtf(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
+ float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+
+ double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+
+ // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
+ // We could have used areCollinear() here, but since we're reusing
+ // the variables computed above later on we keep this logic.
+ if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
+ m_path.lineTo(p1);
+ return;
+ }
+
+ float tangent = radius / tan(acos(cos_phi) / 2);
+ float factor_p1p0 = tangent / p1p0_length;
+ FloatPoint t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
+
+ FloatPoint orth_p1p0(p1p0.y(), -p1p0.x());
+ float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
+ float factor_ra = radius / orth_p1p0_length;
+
+ // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
+ double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ if (cos_alpha < 0.f)
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+
+ FloatPoint p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
+
+ // calculate angles for addArc
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+ float sa = acos(orth_p1p0.x() / orth_p1p0_length);
+ if (orth_p1p0.y() < 0.f)
+ sa = 2 * piDouble - sa;
+
+ // anticlockwise logic
+ bool anticlockwise = false;
+
+ float factor_p1p2 = tangent / p1p2_length;
+ FloatPoint t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
+ FloatPoint orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
+ float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
+ float ea = acos(orth_p1p2.x() / orth_p1p2_length);
+ if (orth_p1p2.y() < 0)
+ ea = 2 * piDouble - ea;
+ if ((sa > ea) && ((sa - ea) < piDouble))
+ anticlockwise = true;
+ if ((sa < ea) && ((ea - sa) > piDouble))
+ anticlockwise = true;
+
+ m_path.lineTo(t_p1p0);
+
+ addArc(p, radius, sa, ea, anticlockwise);
+}
+
+void Path::closeSubpath()
+{
+ m_path.closeSubpath();
+}
+
+#define DEGREES(t) ((t) * 180.0 / M_PI)
+void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise)
+{
+ qreal xc = p.x();
+ qreal yc = p.y();
+ qreal radius = r;
+
+
+ //### HACK
+ // In Qt we don't switch the coordinate system for degrees
+ // and still use the 0,0 as bottom left for degrees so we need
+ // to switch
+ sar = -sar;
+ ear = -ear;
+ anticlockwise = !anticlockwise;
+ //end hack
+
+ float sa = DEGREES(sar);
+ float ea = DEGREES(ear);
+
+ double span = 0;
+
+ double xs = xc - radius;
+ double ys = yc - radius;
+ double width = radius*2;
+ double height = radius*2;
+
+ if ((!anticlockwise && (ea - sa >= 360)) || (anticlockwise && (sa - ea >= 360))) {
+ // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
+ // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
+ // circumference of this circle.
+ span = 360;
+
+ if (anticlockwise)
+ span = -span;
+ } else {
+ if (!anticlockwise && (ea < sa))
+ span += 360;
+ else if (anticlockwise && (sa < ea))
+ span -= 360;
+
+ // this is also due to switched coordinate system
+ // we would end up with a 0 span instead of 360
+ if (!(qFuzzyCompare(span + (ea - sa) + 1, 1.0)
+ && qFuzzyCompare(qAbs(span), 360.0))) {
+ // mod 360
+ span += (ea - sa) - (static_cast<int>((ea - sa) / 360)) * 360;
+ }
+ }
+
+ // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
+ // NOTE: QPainterPath::isEmpty() won't work here since it ignores a lone MoveToElement
+ if (!m_path.elementCount())
+ m_path.arcMoveTo(xs, ys, width, height, sa);
+ else if (!radius) {
+ m_path.lineTo(xc, yc);
+ return;
+ }
+
+ m_path.arcTo(xs, ys, width, height, sa, span);
+
+}
+
+void Path::addRect(const FloatRect& r)
+{
+ m_path.addRect(r.x(), r.y(), r.width(), r.height());
+}
+
+void Path::addEllipse(const FloatRect& r)
+{
+ m_path.addEllipse(r.x(), r.y(), r.width(), r.height());
+}
+
+void Path::clear()
+{
+ if (!m_path.elementCount())
+ return;
+ m_path = QPainterPath();
+}
+
+bool Path::isEmpty() const
+{
+ // Don't use QPainterPath::isEmpty(), as that also returns true if there's only
+ // one initial MoveTo element in the path.
+ return !m_path.elementCount();
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
+
+FloatPoint Path::currentPoint() const
+{
+ return m_path.currentPosition();
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ PathElement pelement;
+ FloatPoint points[3];
+ pelement.points = points;
+ for (int i = 0; i < m_path.elementCount(); ++i) {
+ const QPainterPath::Element& cur = m_path.elementAt(i);
+
+ switch (cur.type) {
+ case QPainterPath::MoveToElement:
+ pelement.type = PathElementMoveToPoint;
+ pelement.points[0] = QPointF(cur);
+ function(info, &pelement);
+ break;
+ case QPainterPath::LineToElement:
+ pelement.type = PathElementAddLineToPoint;
+ pelement.points[0] = QPointF(cur);
+ function(info, &pelement);
+ break;
+ case QPainterPath::CurveToElement:
+ {
+ const QPainterPath::Element& c1 = m_path.elementAt(i + 1);
+ const QPainterPath::Element& c2 = m_path.elementAt(i + 2);
+
+ Q_ASSERT(c1.type == QPainterPath::CurveToDataElement);
+ Q_ASSERT(c2.type == QPainterPath::CurveToDataElement);
+
+ pelement.type = PathElementAddCurveToPoint;
+ pelement.points[0] = QPointF(cur);
+ pelement.points[1] = QPointF(c1);
+ pelement.points[2] = QPointF(c2);
+ function(info, &pelement);
+
+ i += 2;
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ Q_ASSERT(false);
+ }
+ }
+}
+
+void Path::transform(const AffineTransform& transform)
+{
+ QTransform qTransform(transform);
+#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
+ // Workaround for http://bugreports.qt.nokia.com/browse/QTBUG-11264
+ // QTransform.map doesn't handle the MoveTo element because of the isEmpty issue
+ if (m_path.isEmpty() && m_path.elementCount()) {
+ QPointF point = qTransform.map(m_path.currentPosition());
+ moveTo(point);
+ } else
+#endif
+ m_path = qTransform.map(m_path);
+}
+
+float Path::length()
+{
+ return m_path.length();
+}
+
+FloatPoint Path::pointAtLength(float length, bool& ok)
+{
+ ok = (length >= 0 && length <= m_path.length());
+
+ qreal percent = m_path.percentAtLength(length);
+ QPointF point = m_path.pointAtPercent(percent);
+
+ return point;
+}
+
+float Path::normalAngleAtLength(float length, bool& ok)
+{
+ ok = (length >= 0 && length <= m_path.length());
+
+ qreal percent = m_path.percentAtLength(length);
+ qreal angle = m_path.angleAtPercent(percent);
+
+ return angle;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/PatternQt.cpp b/Source/WebCore/platform/graphics/qt/PatternQt.cpp
new file mode 100644
index 0000000..af7b128
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/PatternQt.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Pattern.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+QBrush Pattern::createPlatformPattern(const AffineTransform&) const
+{
+ QPixmap* pixmap = tileImage()->nativeImageForCurrentFrame();
+ if (!pixmap)
+ return QBrush();
+
+ // Qt merges patter space and user space itself
+ QBrush brush(*pixmap);
+ brush.setTransform(m_patternSpaceTransformation);
+
+ return brush;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
new file mode 100644
index 0000000..47ddf02
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include <QFontMetrics>
+
+namespace WebCore {
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = m_platformData.font().fixedPitch();
+}
+
+bool SimpleFontData::containsCharacters(const UChar*, int) const
+{
+ return true;
+}
+
+void SimpleFontData::platformInit()
+{
+ if (!m_platformData.size()) {
+ m_ascent = 0;
+ m_descent = 0;
+ m_lineGap = 0;
+ m_lineSpacing = 0;
+ m_avgCharWidth = 0;
+ m_maxCharWidth = 0;
+ m_xHeight = 0;
+ m_unitsPerEm = 0;
+ return;
+ }
+
+ QFontMetrics fm(m_platformData.font());
+
+ m_ascent = fm.ascent();
+ m_descent = fm.descent();
+ m_lineSpacing = fm.lineSpacing();
+ m_xHeight = fm.xHeight();
+ m_spaceWidth = fm.width(QLatin1Char(' '));
+ m_lineGap = fm.leading();
+}
+
+void SimpleFontData::platformGlyphInit()
+{
+ if (!m_platformData.size())
+ return;
+ m_spaceGlyph = 0;
+ m_adjustedSpaceWidth = m_spaceWidth;
+ determinePitch();
+ m_missingGlyphData.fontData = this;
+ m_missingGlyphData.glyph = 0;
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ if (!m_platformData.size())
+ return;
+ QFontMetrics fm(m_platformData.font());
+ m_avgCharWidth = fm.averageCharWidth();
+ m_maxCharWidth = fm.maxWidth();
+}
+
+void SimpleFontData::platformDestroy()
+{
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/StillImageQt.cpp b/Source/WebCore/platform/graphics/qt/StillImageQt.cpp
new file mode 100644
index 0000000..3b08995
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/StillImageQt.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "StillImageQt.h"
+
+#include "ContextShadow.h"
+#include "GraphicsContext.h"
+#include "IntSize.h"
+
+#include <QPainter>
+
+namespace WebCore {
+
+StillImage::StillImage(const QPixmap& pixmap)
+ : m_pixmap(new QPixmap(pixmap))
+ , m_ownsPixmap(true)
+{}
+
+StillImage::StillImage(const QPixmap* pixmap)
+ : m_pixmap(pixmap)
+ , m_ownsPixmap(false)
+{}
+
+StillImage::~StillImage()
+{
+ if (m_ownsPixmap)
+ delete m_pixmap;
+}
+
+IntSize StillImage::size() const
+{
+ return IntSize(m_pixmap->width(), m_pixmap->height());
+}
+
+NativeImagePtr StillImage::nativeImageForCurrentFrame()
+{
+ return const_cast<NativeImagePtr>(m_pixmap);
+}
+
+void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
+ const FloatRect& src, ColorSpace, CompositeOperator op)
+{
+ if (m_pixmap->isNull())
+ return;
+
+ FloatRect normalizedSrc = src.normalized();
+ FloatRect normalizedDst = dst.normalized();
+
+ CompositeOperator previousOperator = ctxt->compositeOperation();
+ ctxt->setCompositeOperation(op);
+
+ ContextShadow* shadow = ctxt->contextShadow();
+ if (shadow->m_type != ContextShadow::NoShadow) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst);
+ if (shadowPainter) {
+ shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255);
+ shadowPainter->drawPixmap(normalizedDst, *m_pixmap, normalizedSrc);
+ shadow->endShadowLayer(ctxt);
+ }
+ }
+
+ ctxt->platformContext()->drawPixmap(normalizedDst, *m_pixmap, normalizedSrc);
+ ctxt->setCompositeOperation(previousOperator);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/StillImageQt.h b/Source/WebCore/platform/graphics/qt/StillImageQt.h
new file mode 100644
index 0000000..58071d9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/StillImageQt.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 StillImageQt_h
+#define StillImageQt_h
+
+#include "Image.h"
+
+namespace WebCore {
+
+ class StillImage : public Image {
+ public:
+ static PassRefPtr<StillImage> create(const QPixmap& pixmap)
+ {
+ return adoptRef(new StillImage(pixmap));
+ }
+
+ static PassRefPtr<StillImage> createForRendering(const QPixmap* pixmap)
+ {
+ return adoptRef(new StillImage(pixmap));
+ }
+
+ // FIXME: StillImages are underreporting decoded sizes and will be unable
+ // to prune because these functions are not implemented yet.
+ virtual void destroyDecodedData(bool destroyAll = true) { Q_UNUSED(destroyAll); }
+ virtual unsigned decodedSize() const { return 0; }
+
+ virtual IntSize size() const;
+ virtual NativeImagePtr nativeImageForCurrentFrame();
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
+
+ private:
+ StillImage(const QPixmap& pixmap);
+ StillImage(const QPixmap* pixmap);
+ ~StillImage();
+
+ const QPixmap* m_pixmap;
+ bool m_ownsPixmap;
+ };
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp b/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp
new file mode 100644
index 0000000..6fdd7df
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp
@@ -0,0 +1,214 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "TextureMapperQt.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qpaintengine.h>
+#include <QtGui/qpixmap.h>
+
+#ifdef QT_OPENGL_LIB
+# include "opengl/TextureMapperGL.h"
+#endif
+
+namespace WebCore {
+
+void BitmapTextureQt::destroy()
+{
+ if (m_pixmap.paintingActive())
+ qFatal("Destroying an active pixmap");
+ m_pixmap = QPixmap();
+}
+
+void BitmapTextureQt::reset(const IntSize& size, bool isOpaque)
+{
+ BitmapTexture::reset(size, isOpaque);
+
+ if (size.width() > m_pixmap.size().width() || size.height() > m_pixmap.size().height() || m_pixmap.isNull())
+ m_pixmap = QPixmap(size.width(), size.height());
+ if (!isOpaque)
+ m_pixmap.fill(Qt::transparent);
+}
+
+PlatformGraphicsContext* BitmapTextureQt::beginPaint(const IntRect& dirtyRect)
+{
+ m_painter.begin(&m_pixmap);
+ TextureMapperQt::initialize(&m_painter);
+ m_painter.setCompositionMode(QPainter::CompositionMode_Clear);
+ m_painter.fillRect(QRect(dirtyRect), Qt::transparent);
+ m_painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ return &m_painter;
+}
+
+void BitmapTextureQt::endPaint()
+{
+ m_painter.end();
+}
+
+bool BitmapTextureQt::save(const String& path)
+{
+ return m_pixmap.save(path, "PNG");
+}
+
+void BitmapTextureQt::setContentsToImage(Image* image)
+{
+ if (!image)
+ return;
+ const QPixmap* pixmap = image->nativeImageForCurrentFrame();
+ if (!pixmap)
+ return;
+ BitmapTexture::reset(pixmap->size(), !pixmap->hasAlphaChannel());
+ m_pixmap = *pixmap;
+}
+
+void BitmapTextureQt::pack()
+{
+ if (m_pixmap.isNull())
+ return;
+
+ m_image = m_pixmap.toImage();
+ m_pixmap = QPixmap();
+ m_isPacked = true;
+}
+
+void BitmapTextureQt::unpack()
+{
+ m_isPacked = false;
+ if (m_image.isNull())
+ return;
+
+ m_pixmap = QPixmap::fromImage(m_image);
+ m_image = QImage();
+}
+
+void TextureMapperQt::setClip(const IntRect& rect)
+{
+ QPainter* painter = m_currentSurface ? &m_currentSurface->m_painter : m_painter;
+ painter->setClipRect(rect);
+}
+
+TextureMapperQt::TextureMapperQt()
+ : m_currentSurface(0)
+{
+}
+
+void TextureMapperQt::setGraphicsContext(GraphicsContext* context)
+{
+ m_painter = context->platformContext();
+ initialize(m_painter);
+}
+
+void TextureMapperQt::bindSurface(BitmapTexture* surface)
+{
+ if (m_currentSurface == surface)
+ return;
+ if (m_currentSurface)
+ m_currentSurface->m_painter.end();
+ if (!surface) {
+ m_currentSurface = 0;
+ return;
+ }
+ BitmapTextureQt* surfaceQt = static_cast<BitmapTextureQt*>(surface);
+ if (!surfaceQt->m_painter.isActive())
+ surfaceQt->m_painter.begin(&surfaceQt->m_pixmap);
+ m_currentSurface = surfaceQt;
+}
+
+
+void TextureMapperQt::drawTexture(const BitmapTexture& texture, const IntRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* maskTexture)
+{
+ const BitmapTextureQt& textureQt = static_cast<const BitmapTextureQt&>(texture);
+ QPainter* painter = m_painter;
+ QPixmap pixmap = textureQt.m_pixmap;
+ if (m_currentSurface)
+ painter = &m_currentSurface->m_painter;
+
+ if (maskTexture && maskTexture->isValid()) {
+ const BitmapTextureQt* mask = static_cast<const BitmapTextureQt*>(maskTexture);
+ QPixmap intermediatePixmap(pixmap.size());
+ intermediatePixmap.fill(Qt::transparent);
+ QPainter maskPainter(&intermediatePixmap);
+ maskPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ maskPainter.drawPixmap(0, 0, pixmap);
+ maskPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ maskPainter.drawPixmap(QRect(0, 0, pixmap.width(), pixmap.height()), mask->m_pixmap, mask->sourceRect());
+ maskPainter.end();
+ pixmap = intermediatePixmap;
+ }
+
+ const qreal prevOpacity = painter->opacity();
+ const QTransform prevTransform = painter->transform();
+ painter->setOpacity(opacity);
+ painter->setTransform(matrix, true);
+ painter->drawPixmap(targetRect, pixmap, textureQt.sourceRect());
+ painter->setTransform(prevTransform);
+ painter->setOpacity(prevOpacity);
+}
+
+PassOwnPtr<TextureMapper> TextureMapper::create(GraphicsContext* context)
+{
+#ifdef QT_OPENGL_LIB
+ if (context && context->platformContext()->paintEngine()->type() == QPaintEngine::OpenGL2)
+ return new TextureMapperGL;
+#endif
+ return new TextureMapperQt;
+}
+
+PassRefPtr<BitmapTexture> TextureMapperQt::createTexture()
+{
+ return adoptRef(new BitmapTextureQt());
+}
+
+BitmapTextureQt::BitmapTextureQt()
+ : m_isPacked(false)
+{
+
+}
+
+#ifdef QT_OPENGL_LIB
+class RGBA32PremultimpliedBufferQt : public RGBA32PremultimpliedBuffer {
+public:
+ virtual PlatformGraphicsContext* beginPaint(const IntRect& rect, bool opaque)
+ {
+ // m_image is only using during paint, it's safe to override it.
+ m_image = QImage(rect.size().width(), rect.size().height(), QImage::Format_ARGB32_Premultiplied);
+ if (!opaque)
+ m_image.fill(0);
+ m_painter.begin(&m_image);
+ TextureMapperQt::initialize(&m_painter);
+ m_painter.translate(-rect.x(), -rect.y());
+ return &m_painter;
+ }
+
+ virtual void endPaint() { m_painter.end(); }
+ virtual const void* data() const { return m_image.constBits(); }
+
+private:
+ QPainter m_painter;
+ QImage m_image;
+};
+
+PassRefPtr<RGBA32PremultimpliedBuffer> RGBA32PremultimpliedBuffer::create()
+{
+ return adoptRef(new RGBA32PremultimpliedBufferQt());
+}
+
+#endif
+};
diff --git a/Source/WebCore/platform/graphics/qt/TextureMapperQt.h b/Source/WebCore/platform/graphics/qt/TextureMapperQt.h
new file mode 100644
index 0000000..e17b968
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TextureMapperQt.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include "texmap/TextureMapper.h"
+
+#ifndef TextureMapperQt_h
+#define TextureMapperQt_h
+
+namespace WebCore {
+
+class BitmapTextureQt : public BitmapTexture {
+ friend class TextureMapperQt;
+public:
+ BitmapTextureQt();
+ ~BitmapTextureQt() { destroy(); }
+ virtual void destroy();
+ virtual IntSize size() const { return IntSize(m_pixmap.width(), m_pixmap.height()); }
+ virtual void reset(const IntSize&, bool opaque);
+ virtual PlatformGraphicsContext* beginPaint(const IntRect& dirtyRect);
+ virtual void endPaint();
+ virtual void setContentsToImage(Image*);
+ virtual bool save(const String& path);
+ virtual bool isValid() const { return !m_pixmap.isNull() || !m_image.isNull(); }
+ IntRect sourceRect() const { return IntRect(0, 0, contentSize().width(), contentSize().height()); }
+ virtual void pack();
+ virtual void unpack();
+ virtual bool isPacked() const { return m_isPacked; }
+
+private:
+ QPainter m_painter;
+ QPixmap m_pixmap;
+ QImage m_image;
+ bool m_isPacked;
+};
+
+class TextureMapperQt : public TextureMapper {
+public:
+ TextureMapperQt();
+
+ virtual void drawTexture(const BitmapTexture& texture, const IntRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* maskTexture);
+ virtual void bindSurface(BitmapTexture* surface);
+ virtual void setClip(const IntRect&);
+ virtual void setGraphicsContext(GraphicsContext*);
+ virtual bool allowSurfaceForRoot() const { return false; }
+ virtual PassRefPtr<BitmapTexture> createTexture();
+
+ static void initialize(QPainter* painter)
+ {
+ painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
+ }
+
+ static PassOwnPtr<TextureMapper> create() { return new TextureMapperQt; }
+
+private:
+ QPainter* m_painter;
+ RefPtr<BitmapTextureQt> m_currentSurface;
+};
+
+}
+#endif
diff --git a/Source/WebCore/platform/graphics/qt/TileQt.cpp b/Source/WebCore/platform/graphics/qt/TileQt.cpp
new file mode 100644
index 0000000..096ce14
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TileQt.cpp
@@ -0,0 +1,179 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Tile.h"
+
+#if ENABLE(TILED_BACKING_STORE)
+
+#include "GraphicsContext.h"
+#include "TiledBackingStore.h"
+#include "TiledBackingStoreClient.h"
+#include <QApplication>
+#include <QObject>
+#include <QPainter>
+#include <QRegion>
+
+namespace WebCore {
+
+static const unsigned checkerSize = 16;
+static const unsigned checkerColor1 = 0xff555555;
+static const unsigned checkerColor2 = 0xffaaaaaa;
+
+static QPixmap& checkeredPixmap()
+{
+ static QPixmap* pixmap;
+ if (!pixmap) {
+ pixmap = new QPixmap(checkerSize, checkerSize);
+ QPainter painter(pixmap);
+ QColor color1(checkerColor1);
+ QColor color2(checkerColor2);
+ for (unsigned y = 0; y < checkerSize; y += checkerSize / 2) {
+ bool alternate = y % checkerSize;
+ for (unsigned x = 0; x < checkerSize; x += checkerSize / 2) {
+ painter.fillRect(x, y, checkerSize / 2, checkerSize / 2, alternate ? color1 : color2);
+ alternate = !alternate;
+ }
+ }
+ }
+ return *pixmap;
+}
+
+Tile::Tile(TiledBackingStore* backingStore, const Coordinate& tileCoordinate)
+ : m_backingStore(backingStore)
+ , m_coordinate(tileCoordinate)
+ , m_rect(m_backingStore->tileRectForCoordinate(tileCoordinate))
+ , m_buffer(0)
+ , m_backBuffer(0)
+ , m_dirtyRegion(new QRegion(m_rect))
+{
+}
+
+Tile::~Tile()
+{
+ delete m_buffer;
+ delete m_backBuffer;
+ delete m_dirtyRegion;
+}
+
+bool Tile::isDirty() const
+{
+ return !m_dirtyRegion->isEmpty();
+}
+
+bool Tile::isReadyToPaint() const
+{
+ return m_buffer;
+}
+
+void Tile::invalidate(const IntRect& dirtyRect)
+{
+ IntRect tileDirtyRect = intersection(dirtyRect, m_rect);
+ if (tileDirtyRect.isEmpty())
+ return;
+
+ *m_dirtyRegion += tileDirtyRect;
+}
+
+void Tile::updateBackBuffer()
+{
+ if (m_buffer && !isDirty())
+ return;
+
+ if (!m_backBuffer) {
+ if (!m_buffer) {
+ m_backBuffer = new QPixmap(m_backingStore->m_tileSize.width(), m_backingStore->m_tileSize.height());
+ m_backBuffer->fill(m_backingStore->m_client->tiledBackingStoreBackgroundColor());
+ } else {
+ // Currently all buffers are updated synchronously at the same time so there is no real need
+ // to have separate back and front buffers. Just use the existing buffer.
+ m_backBuffer = m_buffer;
+ m_buffer = 0;
+ }
+ }
+
+ QVector<QRect> dirtyRects = m_dirtyRegion->rects();
+ *m_dirtyRegion = QRegion();
+
+ QPainter painter(m_backBuffer);
+ GraphicsContext context(&painter);
+ context.translate(-m_rect.x(), -m_rect.y());
+
+ int size = dirtyRects.size();
+ for (int n = 0; n < size; ++n) {
+ context.save();
+ IntRect rect = dirtyRects[n];
+ context.clip(FloatRect(rect));
+ context.scale(FloatSize(m_backingStore->m_contentsScale, m_backingStore->m_contentsScale));
+ m_backingStore->m_client->tiledBackingStorePaint(&context, m_backingStore->mapToContents(rect));
+ context.restore();
+ }
+}
+
+void Tile::swapBackBufferToFront()
+{
+ if (!m_backBuffer)
+ return;
+ delete m_buffer;
+ m_buffer = m_backBuffer;
+ m_backBuffer = 0;
+}
+
+void Tile::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_buffer)
+ return;
+
+ IntRect target = intersection(rect, m_rect);
+ IntRect source((target.x() - m_rect.x()),
+ (target.y() - m_rect.y()),
+ target.width(),
+ target.height());
+
+ context->platformContext()->drawPixmap(target, *m_buffer, source);
+}
+
+void Tile::paintCheckerPattern(GraphicsContext* context, const FloatRect& target)
+{
+ QPainter* painter = context->platformContext();
+ QTransform worldTransform = painter->worldTransform();
+ qreal scaleX = worldTransform.m11();
+ qreal scaleY = worldTransform.m22();
+
+ QRect targetViewRect = QRectF(target.x() * scaleX,
+ target.y() * scaleY,
+ target.width() * scaleX,
+ target.height() * scaleY).toAlignedRect();
+
+ QTransform adjustedTransform(1., worldTransform.m12(), worldTransform.m13(),
+ worldTransform.m21(), 1., worldTransform.m23(),
+ worldTransform.m31(), worldTransform.m32(), worldTransform.m33());
+ painter->setWorldTransform(adjustedTransform);
+
+ painter->drawTiledPixmap(targetViewRect,
+ checkeredPixmap(),
+ QPoint(targetViewRect.left() % checkerSize,
+ targetViewRect.top() % checkerSize));
+
+ painter->setWorldTransform(worldTransform);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp b/Source/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
new file mode 100644
index 0000000..a5bc3c3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+#include "TransformationMatrix.h"
+
+#include "IntRect.h"
+#include "FloatRect.h"
+
+namespace WebCore {
+
+TransformationMatrix::operator QTransform() const
+{
+ return QTransform(m11(), m12(), m14(), m21(), m22(), m24(), m41(), m42(), m44());
+}
+
+AffineTransform::operator QTransform() const
+{
+ return QTransform(a(), b(), c(), d(), e(), f());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/TransparencyLayer.h b/Source/WebCore/platform/graphics/qt/TransparencyLayer.h
new file mode 100644
index 0000000..5b2f8b2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TransparencyLayer.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org>
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 TransparencyLayer_h
+#define TransparencyLayer_h
+
+#include <QPaintEngine>
+#include <QPainter>
+#include <QPixmap>
+
+namespace WebCore {
+
+struct TransparencyLayer : FastAllocBase {
+ TransparencyLayer(const QPainter* p, const QRect &rect, qreal opacity, QPixmap& alphaMask)
+ : pixmap(rect.width(), rect.height())
+ , opacity(opacity)
+ , alphaMask(alphaMask)
+ , saveCounter(1) // see the comment for saveCounter
+ {
+ offset = rect.topLeft();
+ pixmap.fill(Qt::transparent);
+ painter.begin(&pixmap);
+ painter.setRenderHints(p->renderHints());
+ painter.translate(-offset);
+ painter.setPen(p->pen());
+ painter.setBrush(p->brush());
+ painter.setTransform(p->transform(), true);
+ painter.setOpacity(p->opacity());
+ painter.setFont(p->font());
+ if (painter.paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ painter.setCompositionMode(p->compositionMode());
+ }
+
+ TransparencyLayer()
+ {
+ }
+
+ QPixmap pixmap;
+ QPoint offset;
+ QPainter painter;
+ qreal opacity;
+ // for clipToImageBuffer
+ QPixmap alphaMask;
+ // saveCounter is only used in combination with alphaMask
+ // otherwise, its value is unspecified
+ int saveCounter;
+private:
+ TransparencyLayer(const TransparencyLayer &) {}
+ TransparencyLayer & operator=(const TransparencyLayer &) { return *this; }
+};
+
+} // namespace WebCore
+
+#endif // TransparencyLayer_h
diff --git a/Source/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h b/Source/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h
new file mode 100644
index 0000000..553f203
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2006,2007,2008, 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 BitmapImageSingleFrameSkia_h
+#define BitmapImageSingleFrameSkia_h
+
+#include "Image.h"
+#include "NativeImageSkia.h"
+
+namespace WebCore {
+
+// This image class can be used in places which need an Image, but have
+// raw pixel data rather than undecoded image data.
+// The Image is simpler than a BitmapImage, as it does not have image
+// observers, animation, multiple frames, or non-decoded data.
+// Therefore trimming the decoded data (destroyDecodedData()) has no effect.
+//
+// The difficulty with putting this in BitmapImage::create(NativeImagePtr)
+// is that NativeImagePtr = NativeImageSkia, yet callers have SkBitmap.
+class BitmapImageSingleFrameSkia : public Image {
+public:
+ // Creates a new Image from the given SkBitmap. If "copyPixels" is true, a
+ // deep copy is done. Otherwise, a shallow copy is done (pixel data is
+ // ref'ed).
+ static PassRefPtr<BitmapImageSingleFrameSkia> create(const SkBitmap&, bool copyPixels);
+
+ virtual bool isBitmapImage() const { return true; }
+
+ virtual IntSize size() const
+ {
+ return IntSize(m_nativeImage.width(), m_nativeImage.height());
+ }
+
+ // Do nothing, as we only have the one representation of data (decoded).
+ virtual void destroyDecodedData(bool destroyAll = true) { }
+
+ virtual unsigned decodedSize() const
+ {
+ return m_nativeImage.decodedSize();
+ }
+
+ // We only have a single frame.
+ virtual NativeImagePtr nativeImageForCurrentFrame()
+ {
+ return &m_nativeImage;
+ }
+
+protected:
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
+
+private:
+ NativeImageSkia m_nativeImage;
+
+ // Creates a new Image from the given SkBitmap, using a shallow copy.
+ explicit BitmapImageSingleFrameSkia(const SkBitmap&);
+};
+
+} // namespace WebCore
+
+#endif // BitmapImageSingleFrameSkia_h
diff --git a/Source/WebCore/platform/graphics/skia/FloatPointSkia.cpp b/Source/WebCore/platform/graphics/skia/FloatPointSkia.cpp
new file mode 100644
index 0000000..054a772
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/FloatPointSkia.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+#include "FloatPoint.h"
+
+#include "SkPoint.h"
+#include "SkiaUtils.h"
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const SkPoint& p)
+ : m_x(p.fX)
+ , m_y(p.fY)
+{
+}
+
+FloatPoint::operator SkPoint() const
+{
+ SkPoint p = { WebCoreFloatToSkScalar(m_x), WebCoreFloatToSkScalar(m_y) };
+ return p;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/FloatRectSkia.cpp b/Source/WebCore/platform/graphics/skia/FloatRectSkia.cpp
new file mode 100644
index 0000000..a10371f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/FloatRectSkia.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#include "SkRect.h"
+
+namespace WebCore {
+
+FloatRect::FloatRect(const SkRect& r)
+ : m_location(r.fLeft, r.fTop)
+ , m_size(r.width(), r.height())
+{
+}
+
+FloatRect::operator SkRect() const
+{
+ SkRect rect = { x(), y(), right(), bottom() };
+ return rect;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..e94c417
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ * Copyright (c) 2007, 2008, 2009, Google Inc. All rights reserved.
+ * Copyright (C) 2010 Company 100, 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.
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#if OS(WINDOWS)
+#include "Base64.h"
+#include "ChromiumBridge.h"
+#include "OpenTypeUtilities.h"
+#elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
+#include "SkStream.h"
+#endif
+
+#include "FontPlatformData.h"
+#include "NotImplemented.h"
+#include "OpenTypeSanitizer.h"
+#include "SharedBuffer.h"
+
+#if OS(WINDOWS)
+#include <objbase.h>
+#elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
+#include <cstring>
+#endif
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+#if OS(WINDOWS)
+ if (m_fontReference)
+ RemoveFontMemResourceEx(m_fontReference);
+#elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
+ if (m_fontReference)
+ m_fontReference->unref();
+#endif
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, FontRenderingMode mode)
+{
+#if OS(WINDOWS)
+ ASSERT(m_fontReference);
+
+ LOGFONT logFont;
+ // m_name comes from createUniqueFontName, which, in turn, gets
+ // it from base64-encoded uuid (128-bit). So, m_name
+ // can never be longer than LF_FACESIZE (32).
+ if (m_name.length() + 1 >= LF_FACESIZE) {
+ ASSERT_NOT_REACHED();
+ return FontPlatformData();
+ }
+ memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(),
+ sizeof(logFont.lfFaceName[0]) * (1 + m_name.length()));
+
+ // FIXME: almost identical to FillLogFont in FontCacheWin.cpp.
+ // Need to refactor.
+ logFont.lfHeight = -size;
+ logFont.lfWidth = 0;
+ logFont.lfEscapement = 0;
+ logFont.lfOrientation = 0;
+ logFont.lfUnderline = false;
+ logFont.lfStrikeOut = false;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ logFont.lfQuality = ChromiumBridge::layoutTestMode() ?
+ NONANTIALIASED_QUALITY :
+ DEFAULT_QUALITY; // Honor user's desktop settings.
+ logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ logFont.lfItalic = italic;
+ logFont.lfWeight = bold ? 700 : 400;
+
+ HFONT hfont = CreateFontIndirect(&logFont);
+ return FontPlatformData(hfont, size);
+#elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
+ ASSERT(m_fontReference);
+ return FontPlatformData(m_fontReference, "", size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic(), orientation);
+#else
+ notImplemented();
+ return FontPlatformData();
+#endif
+}
+
+#if OS(WINDOWS)
+// Creates a unique and unpredictable font name, in order to avoid collisions and to
+// not allow access from CSS.
+static String createUniqueFontName()
+{
+ Vector<char> fontUuid(sizeof(GUID));
+ CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data()));
+
+ Vector<char> fontNameVector;
+ base64Encode(fontUuid, fontNameVector);
+ ASSERT(fontNameVector.size() < LF_FACESIZE);
+ return String(fontNameVector.data(), fontNameVector.size());
+}
+#endif
+
+#if OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
+class RemoteFontStream : public SkStream {
+public:
+ explicit RemoteFontStream(PassRefPtr<SharedBuffer> buffer)
+ : m_buffer(buffer)
+ , m_offset(0)
+ {
+ }
+
+ virtual ~RemoteFontStream()
+ {
+ }
+
+ virtual bool rewind()
+ {
+ m_offset = 0;
+ return true;
+ }
+
+ virtual size_t read(void* buffer, size_t size)
+ {
+ if (!buffer && !size) {
+ // This is request for the length of the stream.
+ return m_buffer->size();
+ }
+ // This is a request to read bytes or skip bytes (when buffer is 0).
+ if (!m_buffer->data() || !m_buffer->size())
+ return 0;
+ size_t left = m_buffer->size() - m_offset;
+ size_t bytesToConsume = std::min(left, size);
+ if (buffer)
+ std::memcpy(buffer, m_buffer->data() + m_offset, bytesToConsume);
+ m_offset += bytesToConsume;
+ return bytesToConsume;
+ }
+
+private:
+ RefPtr<SharedBuffer> m_buffer;
+ size_t m_offset;
+};
+#endif
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+#if ENABLE(OPENTYPE_SANITIZER)
+ OpenTypeSanitizer sanitizer(buffer);
+ RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize();
+ if (!transcodeBuffer)
+ return 0; // validation failed.
+ buffer = transcodeBuffer.get();
+#endif
+
+#if OS(WINDOWS)
+ // Introduce the font to GDI. AddFontMemResourceEx should be used with care, because it will pollute the process's
+ // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the
+ // entire process first).
+ String fontName = createUniqueFontName();
+ HANDLE fontReference = renameAndActivateFont(buffer, fontName);
+ if (!fontReference)
+ return 0;
+ return new FontCustomPlatformData(fontReference, fontName);
+#elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
+ RemoteFontStream* stream = new RemoteFontStream(buffer);
+ SkTypeface* typeface = SkTypeface::CreateFromStream(stream);
+ if (!typeface)
+ return 0;
+ return new FontCustomPlatformData(typeface);
+#else
+ notImplemented();
+ return 0;
+#endif
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype")
+#if ENABLE(OPENTYPE_SANITIZER)
+ || equalIgnoringCase(format, "woff")
+#endif
+ ;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h
new file mode 100644
index 0000000..e51b6b6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ * Copyright (c) 2007, 2008, 2009, 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 FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+#if OS(WINDOWS)
+#include "PlatformString.h"
+#include <windows.h>
+#elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
+#include "SkTypeface.h"
+#endif
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+#if OS(WINDOWS)
+ FontCustomPlatformData(HANDLE fontReference, const String& name)
+ : m_fontReference(fontReference)
+ , m_name(name)
+ {}
+#elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
+ explicit FontCustomPlatformData(SkTypeface* typeface)
+ : m_fontReference(typeface)
+ {}
+#endif
+
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal,
+ FontRenderingMode = NormalRenderingMode);
+
+ static bool supportsFormat(const String&);
+
+#if OS(WINDOWS)
+ HANDLE m_fontReference;
+ String m_name;
+#elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
+ SkTypeface* m_fontReference;
+#endif
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+}
+
+#endif // FontCustomPlatformData_h
diff --git a/Source/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp b/Source/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp
new file mode 100644
index 0000000..66e6839
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2008, 2009 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.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "Font.h"
+#include "HarfbuzzSkia.h"
+#include "SimpleFontData.h"
+
+#include "SkTemplates.h"
+#include "SkPaint.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+static int substituteWithVerticalGlyphs(const SimpleFontData* fontData, uint16_t* glyphs, unsigned bufferLength)
+{
+ HB_FaceRec_* hbFace = fontData->platformData().harfbuzzFace();
+ if (!hbFace->gsub) {
+ // if there is no GSUB table, treat it as not covered
+ return 0Xffff;
+ }
+
+ HB_Buffer buffer;
+ hb_buffer_new(&buffer);
+ for (unsigned i = 0; i < bufferLength; ++i)
+ hb_buffer_add_glyph(buffer, glyphs[i], 0, i);
+
+ HB_UShort scriptIndex;
+ HB_UShort featureIndex;
+
+ HB_GSUB_Select_Script(hbFace->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &scriptIndex);
+ HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'e', 'r', 't'), scriptIndex, 0xffff, &featureIndex);
+ HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1);
+ HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'r', 't', '2'), scriptIndex, 0xffff, &featureIndex);
+ HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1);
+
+ int error = HB_GSUB_Apply_String(hbFace->gsub, buffer);
+ if (!error) {
+ for (unsigned i = 0; i < bufferLength; ++i)
+ glyphs[i] = static_cast<Glyph>(buffer->out_string[i].gindex);
+ }
+ return error;
+}
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) {
+ SkDebugf("%s last char is high-surrogate", __FUNCTION__);
+ return false;
+ }
+
+ SkPaint paint;
+ fontData->platformData().setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length);
+ uint16_t* glyphs = glyphStorage.get();
+ // textToGlyphs takes a byte count, not a glyph count so we multiply by two.
+ unsigned count = paint.textToGlyphs(buffer, bufferLength * 2, glyphs);
+ if (count != length) {
+ SkDebugf("%s count != length\n", __FUNCTION__);
+ return false;
+ }
+
+ if ((fontData->orientation() == Vertical) && (!fontData->isBrokenIdeographFont())) {
+ bool lookVariants = false;
+ for (unsigned i = 0; i < bufferLength; ++i) {
+ if (!Font::isCJKIdeograph(buffer[i])) {
+ lookVariants = true;
+ continue;
+ }
+ }
+ if (lookVariants)
+ substituteWithVerticalGlyphs(fontData, glyphs, bufferLength);
+ }
+
+ unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero
+ for (unsigned i = 0; i < length; i++) {
+ setGlyphDataForIndex(offset + i, glyphs[i], glyphs[i] ? fontData : NULL);
+ allGlyphs |= glyphs[i];
+ }
+
+ return allGlyphs != 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/GradientSkia.cpp b/Source/WebCore/platform/graphics/skia/GradientSkia.cpp
new file mode 100644
index 0000000..a636d10
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/GradientSkia.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+
+#include "SkGradientShader.h"
+#include "SkiaUtils.h"
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ if (m_gradient)
+ SkSafeUnref(m_gradient);
+ m_gradient = 0;
+}
+
+static inline U8CPU F2B(float x)
+{
+ return static_cast<int>(x * 255);
+}
+
+static SkColor makeSkColor(float a, float r, float g, float b)
+{
+ return SkColorSetARGB(F2B(a), F2B(r), F2B(g), F2B(b));
+}
+
+// Determine the total number of stops needed, including pseudo-stops at the
+// ends as necessary.
+static size_t totalStopsNeeded(const Gradient::ColorStop* stopData, size_t count)
+{
+ // N.B.: The tests in this function should kept in sync with the ones in
+ // fillStops(), or badness happens.
+ const Gradient::ColorStop* stop = stopData;
+ size_t countUsed = count;
+ if (count < 1 || stop->stop > 0.0)
+ countUsed++;
+ stop += count - 1;
+ if (count < 1 || stop->stop < 1.0)
+ countUsed++;
+ return countUsed;
+}
+
+// Collect sorted stop position and color information into the pos and colors
+// buffers, ensuring stops at both 0.0 and 1.0. The buffers must be large
+// enough to hold information for all stops, including the new endpoints if
+// stops at 0.0 and 1.0 aren't already included.
+static void fillStops(const Gradient::ColorStop* stopData,
+ size_t count, SkScalar* pos, SkColor* colors)
+{
+ const Gradient::ColorStop* stop = stopData;
+ size_t start = 0;
+ if (count < 1) {
+ // A gradient with no stops must be transparent black.
+ pos[0] = WebCoreFloatToSkScalar(0.0);
+ colors[0] = makeSkColor(0.0, 0.0, 0.0, 0.0);
+ start = 1;
+ } else if (stop->stop > 0.0) {
+ // Copy the first stop to 0.0. The first stop position may have a slight
+ // rounding error, but we don't care in this float comparison, since
+ // 0.0 comes through cleanly and people aren't likely to want a gradient
+ // with a stop at (0 + epsilon).
+ pos[0] = WebCoreFloatToSkScalar(0.0);
+ colors[0] = makeSkColor(stop->alpha, stop->red, stop->green, stop->blue);
+ start = 1;
+ }
+
+ for (size_t i = start; i < start + count; i++) {
+ pos[i] = WebCoreFloatToSkScalar(stop->stop);
+ colors[i] = makeSkColor(stop->alpha, stop->red, stop->green, stop->blue);
+ ++stop;
+ }
+
+ // Copy the last stop to 1.0 if needed. See comment above about this float
+ // comparison.
+ if (count < 1 || (--stop)->stop < 1.0) {
+ pos[start + count] = WebCoreFloatToSkScalar(1.0);
+ colors[start + count] = colors[start + count - 1];
+ }
+}
+
+static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
+{
+ return a.stop < b.stop;
+}
+
+SkShader* Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ // FIXME: This and compareStops() are also in Gradient.cpp and
+ // CSSGradientValue.cpp; probably should refactor in WebKit.
+ if (!m_stopsSorted) {
+ if (m_stops.size())
+ std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
+ m_stopsSorted = true;
+ }
+ size_t countUsed = totalStopsNeeded(m_stops.data(), m_stops.size());
+ ASSERT(countUsed >= 2);
+ ASSERT(countUsed >= m_stops.size());
+
+ // FIXME: Why is all this manual pointer math needed?!
+ SkAutoMalloc storage(countUsed * (sizeof(SkColor) + sizeof(SkScalar)));
+ SkColor* colors = (SkColor*)storage.get();
+ SkScalar* pos = (SkScalar*)(colors + countUsed);
+
+ fillStops(m_stops.data(), m_stops.size(), pos, colors);
+
+ SkShader::TileMode tile = SkShader::kClamp_TileMode;
+ switch (m_spreadMethod) {
+ case SpreadMethodReflect:
+ tile = SkShader::kMirror_TileMode;
+ break;
+ case SpreadMethodRepeat:
+ tile = SkShader::kRepeat_TileMode;
+ break;
+ case SpreadMethodPad:
+ tile = SkShader::kClamp_TileMode;
+ break;
+ }
+
+ if (m_radial) {
+ // Since the two-point radial gradient is slower than the plain radial,
+ // only use it if we have to.
+ if (m_p0 == m_p1 && m_r0 <= 0.0f) {
+ // The radius we give to Skia must be positive (and non-zero). If
+ // we're given a zero radius, just ask for a very small radius so
+ // Skia will still return an object.
+ SkScalar radius = m_r1 > 0 ? WebCoreFloatToSkScalar(m_r1) : SK_ScalarMin;
+ m_gradient = SkGradientShader::CreateRadial(m_p1, radius, colors, pos, static_cast<int>(countUsed), tile);
+ } else {
+ // The radii we give to Skia must be positive. If we're given a
+ // negative radius, ask for zero instead.
+ SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0;
+ SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0;
+ m_gradient = SkGradientShader::CreateTwoPointRadial(m_p0, radius0, m_p1, radius1, colors, pos, static_cast<int>(countUsed), tile);
+ }
+ } else {
+ SkPoint pts[2] = { m_p0, m_p1 };
+ m_gradient = SkGradientShader::CreateLinear(pts, colors, pos,
+ static_cast<int>(countUsed), tile);
+ }
+
+ ASSERT(m_gradient);
+
+ SkMatrix matrix = m_gradientSpaceTransformation;
+ m_gradient->setLocalMatrix(matrix);
+
+ return m_gradient;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ context->setFillGradient(this);
+ context->fillRect(rect);
+}
+
+void Gradient::setPlatformGradientSpaceTransform(const AffineTransform& matrix)
+{
+ if (m_gradient)
+ m_gradient->setLocalMatrix(m_gradientSpaceTransformation);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp
new file mode 100644
index 0000000..c4b753b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#include "Image.h"
+#include "ImageSource.h"
+#include "NativeImageSkia.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+#include <algorithm>
+
+namespace WebCore {
+
+bool GraphicsContext3D::getImageData(Image* image,
+ GC3Denum format,
+ GC3Denum type,
+ bool premultiplyAlpha,
+ bool ignoreGammaAndColorProfile,
+ Vector<uint8_t>& outputVector)
+{
+ if (!image)
+ return false;
+ OwnPtr<NativeImageSkia> pixels;
+ NativeImageSkia* skiaImage = 0;
+ AlphaOp neededAlphaOp = AlphaDoNothing;
+ if (image->data()) {
+ ImageSource decoder(ImageSource::AlphaNotPremultiplied,
+ ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied);
+ decoder.setData(image->data(), true);
+ if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0))
+ return false;
+ bool hasAlpha = decoder.frameHasAlphaAtIndex(0);
+ pixels = adoptPtr(decoder.createFrameAtIndex(0));
+ if (!pixels.get() || !pixels->isDataComplete() || !pixels->width() || !pixels->height())
+ return false;
+ SkBitmap::Config skiaConfig = pixels->config();
+ if (skiaConfig != SkBitmap::kARGB_8888_Config)
+ return false;
+ skiaImage = pixels.get();
+ if (hasAlpha && premultiplyAlpha)
+ neededAlphaOp = AlphaDoPremultiply;
+ } else {
+ // This is a special case for texImage2D with HTMLCanvasElement input.
+ skiaImage = image->nativeImageForCurrentFrame();
+ if (!premultiplyAlpha)
+ neededAlphaOp = AlphaDoUnmultiply;
+ }
+ if (!skiaImage)
+ return false;
+ SkBitmap& skiaImageRef = *skiaImage;
+ SkAutoLockPixels lock(skiaImageRef);
+ ASSERT(skiaImage->rowBytes() == skiaImage->width() * 4);
+ outputVector.resize(skiaImage->rowBytes() * skiaImage->height());
+ return packPixels(reinterpret_cast<const uint8_t*>(skiaImage->getPixels()),
+ SourceFormatBGRA8, skiaImage->width(), skiaImage->height(), 0,
+ format, type, neededAlphaOp, outputVector.data());
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h b/Source/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h
new file mode 100644
index 0000000..5e12ad6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2008, 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 GraphicsContextPlatformPrivate_h
+#define GraphicsContextPlatformPrivate_h
+
+#include <wtf/Noncopyable.h>
+
+class PlatformContextSkia;
+
+namespace WebCore {
+
+// This class just holds onto a PlatformContextSkia for GraphicsContext.
+class GraphicsContextPlatformPrivate : public Noncopyable {
+public:
+ GraphicsContextPlatformPrivate(PlatformContextSkia* platformContext)
+ : m_context(platformContext) { }
+
+ PlatformContextSkia* context() { return m_context; }
+
+private:
+ // Non-owning pointer to the PlatformContext.
+ PlatformContextSkia* m_context;
+};
+
+} // namespace WebCore
+
+#endif // GraphicsContextPlatformPrivate_h
diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
new file mode 100644
index 0000000..51e2477
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
@@ -0,0 +1,1262 @@
+/*
+ * Copyright (c) 2006, 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.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "Color.h"
+#include "FloatRect.h"
+#include "GLES2Canvas.h"
+#include "Gradient.h"
+#include "GraphicsContextPlatformPrivate.h"
+#include "ImageBuffer.h"
+#include "IntRect.h"
+#include "NativeImageSkia.h"
+#include "NotImplemented.h"
+#include "PlatformContextSkia.h"
+
+#include "SkBitmap.h"
+#include "SkBlurDrawLooper.h"
+#include "SkCornerPathEffect.h"
+#include "SkShader.h"
+#include "SkiaUtils.h"
+#include "skia/ext/platform_canvas.h"
+
+#include <math.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/UnusedParam.h>
+
+using namespace std;
+
+namespace WebCore {
+
+namespace {
+
+inline int fastMod(int value, int max)
+{
+ int sign = SkExtractSign(value);
+
+ value = SkApplySign(value, sign);
+ if (value >= max)
+ value %= max;
+ return SkApplySign(value, sign);
+}
+
+inline float square(float n)
+{
+ return n * n;
+}
+
+} // namespace
+
+// "Seatbelt" functions ------------------------------------------------------
+//
+// These functions check certain graphics primitives for being "safe".
+// Skia has historically crashed when sent crazy data. These functions do
+// additional checking to prevent crashes.
+//
+// Ideally, all of these would be fixed in the graphics layer and we would not
+// have to do any checking. You can uncomment the ENSURE_VALUE_SAFETY_FOR_SKIA
+// flag to check the graphics layer.
+
+// Disabling these checks (20/01/2010), since we think we've fixed all the Skia
+// bugs. Leaving the code in for now, so we can revert easily if necessary.
+// #define ENSURE_VALUE_SAFETY_FOR_SKIA
+
+#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
+static bool isCoordinateSkiaSafe(float coord)
+{
+ // First check for valid floats.
+#if defined(_MSC_VER)
+ if (!_finite(coord))
+#else
+ if (!finite(coord))
+#endif
+ return false;
+
+ // Skia uses 16.16 fixed point and 26.6 fixed point in various places. If
+ // the transformed point exceeds 15 bits, we just declare that it's
+ // unreasonable to catch both of these cases.
+ static const int maxPointMagnitude = 32767;
+ if (coord > maxPointMagnitude || coord < -maxPointMagnitude)
+ return false;
+
+ return true;
+}
+#endif
+
+static bool isPointSkiaSafe(const SkMatrix& transform, const SkPoint& pt)
+{
+#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
+ // Now check for points that will overflow. We check the *transformed*
+ // points since this is what will be rasterized.
+ SkPoint xPt;
+ transform.mapPoints(&xPt, &pt, 1);
+ return isCoordinateSkiaSafe(xPt.fX) && isCoordinateSkiaSafe(xPt.fY);
+#else
+ return true;
+#endif
+}
+
+static bool isRectSkiaSafe(const SkMatrix& transform, const SkRect& rc)
+{
+#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
+ SkPoint topleft = {rc.fLeft, rc.fTop};
+ SkPoint bottomright = {rc.fRight, rc.fBottom};
+ return isPointSkiaSafe(transform, topleft) && isPointSkiaSafe(transform, bottomright);
+#else
+ return true;
+#endif
+}
+
+bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path)
+{
+#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
+ SkPoint current_points[4];
+ SkPath::Iter iter(path, false);
+ for (SkPath::Verb verb = iter.next(current_points);
+ verb != SkPath::kDone_Verb;
+ verb = iter.next(current_points)) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ // This move will be duplicated in the next verb, so we can ignore.
+ break;
+ case SkPath::kLine_Verb:
+ // iter.next returns 2 points.
+ if (!isPointSkiaSafe(transform, current_points[0])
+ || !isPointSkiaSafe(transform, current_points[1]))
+ return false;
+ break;
+ case SkPath::kQuad_Verb:
+ // iter.next returns 3 points.
+ if (!isPointSkiaSafe(transform, current_points[0])
+ || !isPointSkiaSafe(transform, current_points[1])
+ || !isPointSkiaSafe(transform, current_points[2]))
+ return false;
+ break;
+ case SkPath::kCubic_Verb:
+ // iter.next returns 4 points.
+ if (!isPointSkiaSafe(transform, current_points[0])
+ || !isPointSkiaSafe(transform, current_points[1])
+ || !isPointSkiaSafe(transform, current_points[2])
+ || !isPointSkiaSafe(transform, current_points[3]))
+ return false;
+ break;
+ case SkPath::kClose_Verb:
+ case SkPath::kDone_Verb:
+ default:
+ break;
+ }
+ }
+ return true;
+#else
+ return true;
+#endif
+}
+
+// Local helper functions ------------------------------------------------------
+
+void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle)
+{
+ SkIRect ir;
+ int rx = SkMin32(SkScalarRound(rect.width()), size.width());
+ int ry = SkMin32(SkScalarRound(rect.height()), size.height());
+
+ ir.set(-rx, -ry, rx, ry);
+ switch (startAngle) {
+ case 0:
+ ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom);
+ break;
+ case 90:
+ ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom);
+ break;
+ case 180:
+ ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop);
+ break;
+ case 270:
+ ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop);
+ break;
+ default:
+ ASSERT(0);
+ }
+
+ SkRect r;
+ r.set(ir);
+ path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);
+}
+
+// -----------------------------------------------------------------------------
+
+// This may be called with a NULL pointer to create a graphics context that has
+// no painting.
+void GraphicsContext::platformInit(PlatformGraphicsContext* gc)
+{
+ m_data = new GraphicsContextPlatformPrivate(gc);
+ setPaintingDisabled(!gc || !platformContext()->canvas());
+}
+
+void GraphicsContext::platformDestroy()
+{
+ delete m_data;
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ ASSERT(!paintingDisabled());
+ return m_data->context();
+}
+
+// State saving ----------------------------------------------------------------
+
+void GraphicsContext::savePlatformState()
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU())
+ platformContext()->gpuCanvas()->save();
+
+ // Save our private State.
+ platformContext()->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU())
+ platformContext()->gpuCanvas()->restore();
+
+ // Restore our private State.
+ platformContext()->restore();
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ // We need the "alpha" layer flag here because the base layer is opaque
+ // (the surface of the page) but layers on top may have transparent parts.
+ // Without explicitly setting the alpha flag, the layer will inherit the
+ // opaque setting of the base and some things won't work properly.
+ platformContext()->canvas()->saveLayerAlpha(
+ 0,
+ static_cast<unsigned char>(opacity * 255),
+ static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag |
+ SkCanvas::kFullColorLayer_SaveFlag));
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->canvas()->restore();
+}
+
+// Graphics primitives ---------------------------------------------------------
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r(rect);
+ if (!isRectSkiaSafe(getCTM(), r))
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+ SkPath path;
+ path.addOval(r, SkPath::kCW_Direction);
+ // only perform the inset if we won't invert r
+ if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
+ // Adding one to the thickness doesn't make the border too thick as
+ // it's painted over afterwards. But without this adjustment the
+ // border appears a little anemic after anti-aliasing.
+ r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
+ path.addOval(r, SkPath::kCCW_Direction);
+ }
+ platformContext()->clipPathAntiAliased(path);
+}
+
+void GraphicsContext::addPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->addPath(*path.platformPath());
+}
+
+void GraphicsContext::beginPath()
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->beginPath();
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->setDrawLooper(0);
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU() && !platformContext()->canvasClipApplied()) {
+ platformContext()->prepareForHardwareDraw();
+ platformContext()->gpuCanvas()->clearRect(rect);
+ return;
+ }
+
+ // Force a readback here (if we're using the GPU), since clearRect() is
+ // incompatible with mixed-mode rendering.
+ platformContext()->syncSoftwareCanvas();
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r))
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+
+ SkPaint paint;
+ platformContext()->setupPaintForFilling(&paint);
+ paint.setXfermodeMode(SkXfermode::kClear_Mode);
+ platformContext()->canvas()->drawRect(r, paint);
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r(rect);
+ if (!isRectSkiaSafe(getCTM(), r))
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+ platformContext()->canvas()->clipRect(r);
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ const SkPath& p = *path.platformPath();
+ if (!isPathSkiaSafe(getCTM(), p))
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+ platformContext()->clipPathAntiAliased(p);
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ const SkPath& p = *path.platformPath();
+ if (!isPathSkiaSafe(getCTM(), p))
+ return;
+
+ platformContext()->canvasClipPath(p);
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r(rect);
+ if (!isRectSkiaSafe(getCTM(), r))
+ return;
+
+ platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipOut(const Path& p)
+{
+ if (paintingDisabled())
+ return;
+
+ const SkPath& path = *p.platformPath();
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+
+ platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ // FIXME: Be smarter about this.
+ beginPath();
+ addPath(pathToClip);
+
+ SkPath path = platformContext()->currentPathInLocalCoordinates();
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+
+ path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
+ platformContext()->clipPathAntiAliased(path);
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& affine)
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU())
+ platformContext()->gpuCanvas()->concatCTM(affine);
+
+ platformContext()->canvas()->concat(affine);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t numPoints,
+ const FloatPoint* points,
+ bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ SkPath path;
+
+ path.incReserve(numPoints);
+ path.moveTo(WebCoreFloatToSkScalar(points[0].x()),
+ WebCoreFloatToSkScalar(points[0].y()));
+ for (size_t i = 1; i < numPoints; i++) {
+ path.lineTo(WebCoreFloatToSkScalar(points[i].x()),
+ WebCoreFloatToSkScalar(points[i].y()));
+ }
+
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+
+ SkPaint paint;
+ platformContext()->setupPaintForFilling(&paint);
+ platformContext()->canvas()->drawPath(path, paint);
+
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ platformContext()->setupPaintForStroking(&paint, 0, 0);
+ platformContext()->canvas()->drawPath(path, paint);
+ }
+}
+
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ // FIXME: IMPLEMENT!!
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& elipseRect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect rect = elipseRect;
+ if (!isRectSkiaSafe(getCTM(), rect))
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+ SkPaint paint;
+ platformContext()->setupPaintForFilling(&paint);
+ platformContext()->canvas()->drawOval(rect, paint);
+
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ platformContext()->setupPaintForStroking(&paint, &rect, 0);
+ platformContext()->canvas()->drawOval(rect, paint);
+ }
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ unsigned rectCount = rects.size();
+ if (!rectCount)
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+ SkRegion focusRingRegion;
+ const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.5);
+ for (unsigned i = 0; i < rectCount; i++) {
+ SkIRect r = rects[i];
+ r.inset(-focusRingOutset, -focusRingOutset);
+ focusRingRegion.op(r, SkRegion::kUnion_Op);
+ }
+
+ SkPath path;
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ paint.setColor(color.rgb());
+ paint.setStrokeWidth(focusRingOutset * 2);
+ paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref();
+ focusRingRegion.getBoundaryPath(&path);
+ platformContext()->canvas()->drawPath(path, paint);
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle penStyle = strokeStyle();
+ if (penStyle == NoStroke)
+ return;
+
+ SkPaint paint;
+ if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2))
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
+ int width = roundf(strokeThickness());
+
+ // We know these are vertical or horizontal lines, so the length will just
+ // be the sum of the displacement component vectors give or take 1 -
+ // probably worth the speed up of no square root, which also won't be exact.
+ FloatSize disp = p2 - p1;
+ int length = SkScalarRound(disp.width() + disp.height());
+ platformContext()->setupPaintForStroking(&paint, 0, length);
+
+ if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
+ // Do a rect fill of our endpoints. This ensures we always have the
+ // appearance of being a border. We then draw the actual dotted/dashed line.
+
+ SkRect r1, r2;
+ r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
+ r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);
+
+ if (isVerticalLine) {
+ r1.offset(-width / 2, 0);
+ r2.offset(-width / 2, -width);
+ } else {
+ r1.offset(0, -width / 2);
+ r2.offset(-width, -width / 2);
+ }
+ SkPaint fillPaint;
+ fillPaint.setColor(paint.getColor());
+ platformContext()->canvas()->drawRect(r1, fillPaint);
+ platformContext()->canvas()->drawRect(r2, fillPaint);
+ }
+
+ adjustLineToPixelBoundaries(p1, p2, width, penStyle);
+ SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };
+
+ platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
+}
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint& pt, int width, TextCheckingLineStyle style)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ // Create the pattern we'll use to draw the underline.
+ static SkBitmap* misspellBitmap = 0;
+ if (!misspellBitmap) {
+ // We use a 2-pixel-high misspelling indicator because that seems to be
+ // what WebKit is designed for, and how much room there is in a typical
+ // page for it.
+ const int rowPixels = 32; // Must be multiple of 4 for pattern below.
+ const int colPixels = 2;
+ misspellBitmap = new SkBitmap;
+ misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config,
+ rowPixels, colPixels);
+ misspellBitmap->allocPixels();
+
+ misspellBitmap->eraseARGB(0, 0, 0, 0);
+ const uint32_t lineColor = 0xFFFF0000; // Opaque red.
+ const uint32_t antiColor = 0x60600000; // Semitransparent red.
+
+ // Pattern: X o o X o o X
+ // o X o o X o
+ uint32_t* row1 = misspellBitmap->getAddr32(0, 0);
+ uint32_t* row2 = misspellBitmap->getAddr32(0, 1);
+ for (int x = 0; x < rowPixels; x++) {
+ switch (x % 4) {
+ case 0:
+ row1[x] = lineColor;
+ break;
+ case 1:
+ row1[x] = antiColor;
+ row2[x] = antiColor;
+ break;
+ case 2:
+ row2[x] = lineColor;
+ break;
+ case 3:
+ row1[x] = antiColor;
+ row2[x] = antiColor;
+ break;
+ }
+ }
+ }
+
+ // Offset it vertically by 1 so that there's some space under the text.
+ SkScalar originX = SkIntToScalar(pt.x());
+ SkScalar originY = SkIntToScalar(pt.y()) + 1;
+
+ // Make a shader for the bitmap with an origin of the box we'll draw. This
+ // shader is refcounted and will have an initial refcount of 1.
+ SkShader* shader = SkShader::CreateBitmapShader(
+ *misspellBitmap, SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ SkMatrix matrix;
+ matrix.reset();
+ matrix.postTranslate(originX, originY);
+ shader->setLocalMatrix(matrix);
+
+ // Assign the shader to the paint & release our reference. The paint will
+ // now own the shader and the shader will be destroyed when the paint goes
+ // out of scope.
+ SkPaint paint;
+ paint.setShader(shader);
+ shader->unref();
+
+ SkRect rect;
+ rect.set(originX,
+ originY,
+ originX + SkIntToScalar(width),
+ originY + SkIntToScalar(misspellBitmap->height()));
+ platformContext()->canvas()->drawRect(rect, paint);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& pt,
+ int width,
+ bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ if (width <= 0)
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
+ SkRect r;
+ r.fLeft = SkIntToScalar(pt.x());
+ r.fTop = SkIntToScalar(pt.y());
+ r.fRight = r.fLeft + SkIntToScalar(width);
+ r.fBottom = r.fTop + SkIntToScalar(thickness);
+
+ SkPaint paint;
+ platformContext()->setupPaintForFilling(&paint);
+ // Text lines are drawn using the stroke color.
+ paint.setColor(platformContext()->effectiveStrokeColor());
+ platformContext()->canvas()->drawRect(r, paint);
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r)) {
+ // See the fillRect below.
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ }
+
+ platformContext()->drawRect(r);
+}
+
+void GraphicsContext::fillPath(const Path& pathToFill)
+{
+ if (paintingDisabled())
+ return;
+
+ // FIXME: Be smarter about this.
+ beginPath();
+ addPath(pathToFill);
+
+ SkPath path = platformContext()->currentPathInLocalCoordinates();
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ const GraphicsContextState& state = m_state;
+ path.setFillType(state.fillRule == RULE_EVENODD ?
+ SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
+
+ SkPaint paint;
+ platformContext()->setupPaintForFilling(&paint);
+
+ platformContext()->canvas()->drawPath(path, paint);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r)) {
+ // See the other version of fillRect below.
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ }
+
+ if (platformContext()->useGPU() && platformContext()->canAccelerate()) {
+ platformContext()->prepareForHardwareDraw();
+ platformContext()->gpuCanvas()->fillRect(rect);
+ return;
+ }
+
+ platformContext()->save();
+
+ platformContext()->prepareForSoftwareDraw();
+
+ SkPaint paint;
+ platformContext()->setupPaintForFilling(&paint);
+ platformContext()->canvas()->drawRect(r, paint);
+
+ platformContext()->restore();
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU() && platformContext()->canAccelerate()) {
+ platformContext()->prepareForHardwareDraw();
+ platformContext()->gpuCanvas()->fillRect(rect, color, colorSpace);
+ return;
+ }
+
+ platformContext()->prepareForSoftwareDraw();
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r)) {
+ // Special case when the rectangle overflows fixed point. This is a
+ // workaround to fix bug 1212844. When the input rectangle is very
+ // large, it can overflow Skia's internal fixed point rect. This
+ // should be fixable in Skia (since the output bitmap isn't that
+ // large), but until that is fixed, we try to handle it ourselves.
+ //
+ // We manually clip the rectangle to the current clip rect. This
+ // will prevent overflow. The rectangle will be transformed to the
+ // canvas' coordinate space before it is converted to fixed point
+ // so we are guaranteed not to overflow after doing this.
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ }
+
+ SkPaint paint;
+ platformContext()->setupPaintCommon(&paint);
+ paint.setColor(color.rgb());
+ platformContext()->canvas()->drawRect(r, paint);
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect,
+ const IntSize& topLeft,
+ const IntSize& topRight,
+ const IntSize& bottomLeft,
+ const IntSize& bottomRight,
+ const Color& color,
+ ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r))
+ // See fillRect().
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+
+ if (topLeft.width() + topRight.width() > rect.width()
+ || bottomLeft.width() + bottomRight.width() > rect.width()
+ || topLeft.height() + bottomLeft.height() > rect.height()
+ || topRight.height() + bottomRight.height() > rect.height()) {
+ // Not all the radii fit, return a rect. This matches the behavior of
+ // Path::createRoundedRectangle. Without this we attempt to draw a round
+ // shadow for a square box.
+ fillRect(rect, color, colorSpace);
+ return;
+ }
+
+ SkPath path;
+ addCornerArc(&path, r, topRight, 270);
+ addCornerArc(&path, r, bottomRight, 0);
+ addCornerArc(&path, r, bottomLeft, 90);
+ addCornerArc(&path, r, topLeft, 180);
+
+ SkPaint paint;
+ platformContext()->setupPaintForFilling(&paint);
+ platformContext()->canvas()->drawPath(path, paint);
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ const SkMatrix& m = platformContext()->canvas()->getTotalMatrix();
+ return AffineTransform(SkScalarToDouble(m.getScaleX()),
+ SkScalarToDouble(m.getSkewY()),
+ SkScalarToDouble(m.getSkewX()),
+ SkScalarToDouble(m.getScaleY()),
+ SkScalarToDouble(m.getTranslateX()),
+ SkScalarToDouble(m.getTranslateY()));
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ // This logic is copied from GraphicsContextCG, eseidel 5/05/08
+
+ // It is not enough just to round to pixels in device space. The rotation
+ // part of the affine transform matrix to device space can mess with this
+ // conversion if we have a rotating image like the hands of the world clock
+ // widget. We just need the scale, so we get the affine transform matrix and
+ // extract the scale.
+
+ const SkMatrix& deviceMatrix = platformContext()->canvas()->getTotalMatrix();
+ if (deviceMatrix.isIdentity())
+ return rect;
+
+ float deviceScaleX = sqrtf(square(deviceMatrix.getScaleX())
+ + square(deviceMatrix.getSkewY()));
+ float deviceScaleY = sqrtf(square(deviceMatrix.getSkewX())
+ + square(deviceMatrix.getScaleY()));
+
+ FloatPoint deviceOrigin(rect.x() * deviceScaleX, rect.y() * deviceScaleY);
+ FloatPoint deviceLowerRight((rect.x() + rect.width()) * deviceScaleX,
+ (rect.y() + rect.height()) * deviceScaleY);
+
+ deviceOrigin.setX(roundf(deviceOrigin.x()));
+ deviceOrigin.setY(roundf(deviceOrigin.y()));
+ deviceLowerRight.setX(roundf(deviceLowerRight.x()));
+ deviceLowerRight.setY(roundf(deviceLowerRight.y()));
+
+ // Don't let the height or width round to 0 unless either was originally 0
+ if (deviceOrigin.y() == deviceLowerRight.y() && rect.height())
+ deviceLowerRight.move(0, 1);
+ if (deviceOrigin.x() == deviceLowerRight.x() && rect.width())
+ deviceLowerRight.move(1, 0);
+
+ FloatPoint roundedOrigin(deviceOrigin.x() / deviceScaleX,
+ deviceOrigin.y() / deviceScaleY);
+ FloatPoint roundedLowerRight(deviceLowerRight.x() / deviceScaleX,
+ deviceLowerRight.y() / deviceScaleY);
+ return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU())
+ platformContext()->gpuCanvas()->scale(size);
+
+ platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()),
+ WebCoreFloatToSkScalar(size.height()));
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU())
+ platformContext()->gpuCanvas()->setAlpha(alpha);
+
+ platformContext()->setAlpha(alpha);
+}
+
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU())
+ platformContext()->gpuCanvas()->setCompositeOperation(op);
+
+ platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ return platformContext()->interpolationQuality();
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality q)
+{
+ platformContext()->setInterpolationQuality(q);
+}
+
+void GraphicsContext::setLineCap(LineCap cap)
+{
+ if (paintingDisabled())
+ return;
+ switch (cap) {
+ case ButtCap:
+ platformContext()->setLineCap(SkPaint::kButt_Cap);
+ break;
+ case RoundCap:
+ platformContext()->setLineCap(SkPaint::kRound_Cap);
+ break;
+ case SquareCap:
+ platformContext()->setLineCap(SkPaint::kSquare_Cap);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ if (paintingDisabled())
+ return;
+
+ // FIXME: This is lifted directly off SkiaSupport, lines 49-74
+ // so it is not guaranteed to work correctly.
+ size_t dashLength = dashes.size();
+ if (!dashLength) {
+ // If no dash is set, revert to solid stroke
+ // FIXME: do we need to set NoStroke in some cases?
+ platformContext()->setStrokeStyle(SolidStroke);
+ platformContext()->setDashPathEffect(0);
+ return;
+ }
+
+ size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
+ SkScalar* intervals = new SkScalar[count];
+
+ for (unsigned int i = 0; i < count; i++)
+ intervals[i] = dashes[i % dashLength];
+
+ platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset));
+
+ delete[] intervals;
+}
+
+void GraphicsContext::setLineJoin(LineJoin join)
+{
+ if (paintingDisabled())
+ return;
+ switch (join) {
+ case MiterJoin:
+ platformContext()->setLineJoin(SkPaint::kMiter_Join);
+ break;
+ case RoundJoin:
+ platformContext()->setLineJoin(SkPaint::kRound_Join);
+ break;
+ case BevelJoin:
+ platformContext()->setLineJoin(SkPaint::kBevel_Join);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->setMiterLimit(limit);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU())
+ platformContext()->gpuCanvas()->setFillColor(color, colorSpace);
+
+ platformContext()->setFillColor(color.rgb());
+}
+
+void GraphicsContext::setPlatformFillGradient(Gradient* gradient)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setFillShader(gradient->platformGradient());
+}
+
+void GraphicsContext::setPlatformFillPattern(Pattern* pattern)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setFillShader(pattern->platformPattern(getCTM()));
+}
+
+void GraphicsContext::setPlatformShadow(const FloatSize& size,
+ float blurFloat,
+ const Color& color,
+ ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ // Detect when there's no effective shadow and clear the looper.
+ if (!size.width() && !size.height() && !blurFloat) {
+ platformContext()->setDrawLooper(0);
+ return;
+ }
+
+ double width = size.width();
+ double height = size.height();
+ double blur = blurFloat;
+
+ SkBlurDrawLooper::BlurFlags blurFlags = SkBlurDrawLooper::kNone_BlurFlag;
+
+ if (m_state.shadowsIgnoreTransforms) {
+ // Currently only the GraphicsContext associated with the
+ // CanvasRenderingContext for HTMLCanvasElement have shadows ignore
+ // Transforms. So with this flag set, we know this state is associated
+ // with a CanvasRenderingContext.
+ blurFlags = SkBlurDrawLooper::kIgnoreTransform_BlurFlag;
+
+ // CG uses natural orientation for Y axis, but the HTML5 canvas spec
+ // does not.
+ // So we now flip the height since it was flipped in
+ // CanvasRenderingContext in order to work with CG.
+ height = -height;
+ }
+
+ SkColor c;
+ if (color.isValid())
+ c = color.rgb();
+ else
+ c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" apple shadow color.
+
+ // TODO(tc): Should we have a max value for the blur? CG clamps at 1000.0
+ // for perf reasons.
+ SkDrawLooper* dl = new SkBlurDrawLooper(blur / 2, width, height, c, blurFlags);
+ platformContext()->setDrawLooper(dl);
+ dl->unref();
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setStrokeColor(strokecolor.rgb());
+}
+
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle stroke)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setStrokeStyle(stroke);
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setStrokeThickness(thickness);
+}
+
+void GraphicsContext::setPlatformStrokeGradient(Gradient* gradient)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setStrokeShader(gradient->platformGradient());
+}
+
+void GraphicsContext::setPlatformStrokePattern(Pattern* pattern)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setStrokeShader(pattern->platformPattern(getCTM()));
+}
+
+void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setTextDrawingMode(mode);
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setUseAntialiasing(enable);
+}
+
+void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ SkPaint paint;
+ SkRect oval = r;
+ if (strokeStyle() == NoStroke) {
+ // Stroke using the fill color.
+ // TODO(brettw) is this really correct? It seems unreasonable.
+ platformContext()->setupPaintForFilling(&paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness()));
+ } else
+ platformContext()->setupPaintForStroking(&paint, 0, 0);
+
+ // We do this before converting to scalar, so we don't overflow SkFixed.
+ startAngle = fastMod(startAngle, 360);
+ angleSpan = fastMod(angleSpan, 360);
+
+ SkPath path;
+ path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+ platformContext()->canvas()->drawPath(path, paint);
+}
+
+void GraphicsContext::strokePath(const Path& pathToStroke)
+{
+ if (paintingDisabled())
+ return;
+
+ // FIXME: Be smarter about this.
+ beginPath();
+ addPath(pathToStroke);
+
+ SkPath path = platformContext()->currentPathInLocalCoordinates();
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ SkPaint paint;
+ platformContext()->setupPaintForStroking(&paint, 0, 0);
+ platformContext()->canvas()->drawPath(path, paint);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ if (!isRectSkiaSafe(getCTM(), rect))
+ return;
+
+ platformContext()->prepareForSoftwareDraw();
+
+ SkPaint paint;
+ platformContext()->setupPaintForStroking(&paint, 0, 0);
+ paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
+ platformContext()->canvas()->drawRect(rect, paint);
+}
+
+void GraphicsContext::rotate(float angleInRadians)
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU())
+ platformContext()->gpuCanvas()->rotate(angleInRadians);
+
+ platformContext()->canvas()->rotate(WebCoreFloatToSkScalar(
+ angleInRadians * (180.0f / 3.14159265f)));
+}
+
+void GraphicsContext::translate(float w, float h)
+{
+ if (paintingDisabled())
+ return;
+
+ if (platformContext()->useGPU())
+ platformContext()->gpuCanvas()->translate(w, h);
+
+ platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w),
+ WebCoreFloatToSkScalar(h));
+}
+
+void GraphicsContext::syncSoftwareCanvas()
+{
+ platformContext()->syncSoftwareCanvas();
+}
+
+void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D* context, DrawingBuffer* framebuffer, const IntSize& size)
+{
+ platformContext()->setSharedGraphicsContext3D(context, framebuffer, size);
+}
+
+void GraphicsContext::markDirtyRect(const IntRect& rect)
+{
+ platformContext()->markDirtyRect(rect);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
new file mode 100644
index 0000000..a9f6d3c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. 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.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "Base64.h"
+#include "BitmapImage.h"
+#include "BitmapImageSingleFrameSkia.h"
+#include "DrawingBuffer.h"
+#include "GLES2Canvas.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "JPEGImageEncoder.h"
+#include "MIMETypeRegistry.h"
+#include "PNGImageEncoder.h"
+#include "PlatformContextSkia.h"
+#include "SkColorPriv.h"
+#include "SkiaUtils.h"
+
+#include <wtf/text/StringConcatenate.h>
+
+using namespace std;
+
+namespace WebCore {
+
+// We pass a technically-uninitialized canvas to the platform context here since
+// the canvas initialization completes in ImageBuffer::ImageBuffer. But
+// PlatformContext doesn't actually need to use the object, and this makes all
+// the ownership easier to manage.
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_platformContext(0) // Canvas is set in ImageBuffer constructor.
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ if (!m_data.m_canvas.initialize(size.width(), size.height(), false)) {
+ success = false;
+ return;
+ }
+
+ m_data.m_platformContext.setCanvas(&m_data.m_canvas);
+ m_context.set(new GraphicsContext(&m_data.m_platformContext));
+ m_context->platformContext()->setDrawingToImageBuffer(true);
+
+ // Make the background transparent. It would be nice if this wasn't
+ // required, but the canvas is currently filled with the magic transparency
+ // color. Can we have another way to manage this?
+ m_data.m_canvas.drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+bool ImageBuffer::drawsUsingCopy() const
+{
+ return false;
+}
+
+PassRefPtr<Image> ImageBuffer::copyImage() const
+{
+ m_context->platformContext()->syncSoftwareCanvas();
+ return BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), true);
+}
+
+void ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const
+{
+ context->platformContext()->beginLayerClippedToImage(rect, this);
+}
+
+void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
+ CompositeOperator op, bool useLowQualityScale)
+{
+ if (m_data.m_platformContext.useGPU() && context->platformContext()->useGPU()) {
+ if (context->platformContext()->canAccelerate()) {
+ DrawingBuffer* sourceDrawingBuffer = m_data.m_platformContext.gpuCanvas()->drawingBuffer();
+ unsigned sourceTexture = static_cast<unsigned>(sourceDrawingBuffer->platformColorBuffer());
+ FloatRect destRectFlipped(destRect);
+ destRectFlipped.setY(destRect.y() + destRect.height());
+ destRectFlipped.setHeight(-destRect.height());
+ context->platformContext()->prepareForHardwareDraw();
+ context->platformContext()->gpuCanvas()->drawTexturedRect(sourceTexture, m_size, srcRect, destRectFlipped, styleColorSpace, op);
+ return;
+ }
+ m_data.m_platformContext.syncSoftwareCanvas();
+ }
+
+ RefPtr<Image> image = BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), context == m_context);
+ context->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
+}
+
+void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ RefPtr<Image> image = BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), context == m_context);
+ image->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ const SkBitmap& bitmap = *context()->platformContext()->bitmap();
+ if (bitmap.isNull())
+ return;
+
+ ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ SkAutoLockPixels bitmapLock(bitmap);
+ for (int y = 0; y < m_size.height(); ++y) {
+ uint32_t* srcRow = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_size.width(); ++x) {
+ SkColor color = SkPMColorToColor(srcRow[x]);
+ srcRow[x] = SkPreMultiplyARGB(SkColorGetA(color),
+ lookUpTable[SkColorGetR(color)],
+ lookUpTable[SkColorGetG(color)],
+ lookUpTable[SkColorGetB(color)]);
+ }
+ }
+}
+
+template <Multiply multiplied>
+PassRefPtr<ByteArray> getImageData(const IntRect& rect, const SkBitmap& bitmap,
+ const IntSize& size)
+{
+ RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4);
+
+ if (bitmap.config() == SkBitmap::kNo_Config) {
+ // This is an empty SkBitmap that could not be configured.
+ ASSERT(!size.width() || !size.height());
+ return result.release();
+ }
+
+ unsigned char* data = result->data();
+
+ if (rect.x() < 0
+ || rect.y() < 0
+ || rect.right() > size.width()
+ || rect.bottom() > size.height())
+ memset(data, 0, result->length());
+
+ int originX = rect.x();
+ int destX = 0;
+ if (originX < 0) {
+ destX = -originX;
+ originX = 0;
+ }
+ int endX = rect.right();
+ if (endX > size.width())
+ endX = size.width();
+ int numColumns = endX - originX;
+
+ if (numColumns <= 0)
+ return result.release();
+
+ int originY = rect.y();
+ int destY = 0;
+ if (originY < 0) {
+ destY = -originY;
+ originY = 0;
+ }
+ int endY = rect.bottom();
+ if (endY > size.height())
+ endY = size.height();
+ int numRows = endY - originY;
+
+ if (numRows <= 0)
+ return result.release();
+
+ ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ SkAutoLockPixels bitmapLock(bitmap);
+
+ unsigned destBytesPerRow = 4 * rect.width();
+ unsigned char* destRow = data + destY * destBytesPerRow + destX * 4;
+
+ for (int y = 0; y < numRows; ++y) {
+ uint32_t* srcRow = bitmap.getAddr32(originX, originY + y);
+ for (int x = 0; x < numColumns; ++x) {
+ unsigned char* destPixel = &destRow[x * 4];
+ if (multiplied == Unmultiplied) {
+ SkColor color = srcRow[x];
+ unsigned a = SkColorGetA(color);
+ destPixel[0] = a ? SkColorGetR(color) * 255 / a : 0;
+ destPixel[1] = a ? SkColorGetG(color) * 255 / a : 0;
+ destPixel[2] = a ? SkColorGetB(color) * 255 / a : 0;
+ destPixel[3] = a;
+ } else {
+ // Input and output are both pre-multiplied, we just need to re-arrange the
+ // bytes from the bitmap format to RGBA.
+ destPixel[0] = SkGetPackedR32(srcRow[x]);
+ destPixel[1] = SkGetPackedG32(srcRow[x]);
+ destPixel[2] = SkGetPackedB32(srcRow[x]);
+ destPixel[3] = SkGetPackedA32(srcRow[x]);
+ }
+ }
+ destRow += destBytesPerRow;
+ }
+
+ return result.release();
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ context()->platformContext()->syncSoftwareCanvas();
+ return getImageData<Unmultiplied>(rect, *context()->platformContext()->bitmap(), m_size);
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ context()->platformContext()->syncSoftwareCanvas();
+ return getImageData<Premultiplied>(rect, *context()->platformContext()->bitmap(), m_size);
+}
+
+template <Multiply multiplied>
+void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint,
+ const SkBitmap& bitmap, const IntSize& size)
+{
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originX = sourceRect.x();
+ int destX = destPoint.x() + sourceRect.x();
+ ASSERT(destX >= 0);
+ ASSERT(destX < size.width());
+ ASSERT(originX >= 0);
+ ASSERT(originX < sourceRect.right());
+
+ int endX = destPoint.x() + sourceRect.right();
+ ASSERT(endX <= size.width());
+
+ int numColumns = endX - destX;
+
+ int originY = sourceRect.y();
+ int destY = destPoint.y() + sourceRect.y();
+ ASSERT(destY >= 0);
+ ASSERT(destY < size.height());
+ ASSERT(originY >= 0);
+ ASSERT(originY < sourceRect.bottom());
+
+ int endY = destPoint.y() + sourceRect.bottom();
+ ASSERT(endY <= size.height());
+ int numRows = endY - destY;
+
+ ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ SkAutoLockPixels bitmapLock(bitmap);
+
+ unsigned srcBytesPerRow = 4 * sourceSize.width();
+
+ const unsigned char* srcRow = source->data() + originY * srcBytesPerRow + originX * 4;
+
+ for (int y = 0; y < numRows; ++y) {
+ uint32_t* destRow = bitmap.getAddr32(destX, destY + y);
+ for (int x = 0; x < numColumns; ++x) {
+ const unsigned char* srcPixel = &srcRow[x * 4];
+ if (multiplied == Unmultiplied) {
+ unsigned char alpha = srcPixel[3];
+ unsigned char r = SkMulDiv255Ceiling(srcPixel[0], alpha);
+ unsigned char g = SkMulDiv255Ceiling(srcPixel[1], alpha);
+ unsigned char b = SkMulDiv255Ceiling(srcPixel[2], alpha);
+ destRow[x] = SkPackARGB32(alpha, r, g, b);
+ } else
+ destRow[x] = SkPackARGB32(srcPixel[3], srcPixel[0],
+ srcPixel[1], srcPixel[2]);
+ }
+ srcRow += srcBytesPerRow;
+ }
+}
+
+void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ context()->platformContext()->prepareForSoftwareDraw();
+ putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size);
+}
+
+void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size);
+}
+
+String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const
+{
+ ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+
+ Vector<unsigned char> encodedImage;
+ if (mimeType == "image/jpeg") {
+ int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality;
+ if (quality && *quality >= 0.0 && *quality <= 1.0)
+ compressionQuality = static_cast<int>(*quality * 100 + 0.5);
+ if (!JPEGImageEncoder::encode(*context()->platformContext()->bitmap(), compressionQuality, &encodedImage))
+ return "data:,";
+ } else {
+ if (!PNGImageEncoder::encode(*context()->platformContext()->bitmap(), &encodedImage))
+ return "data:,";
+ ASSERT(mimeType == "image/png");
+ }
+
+ Vector<char> base64Data;
+ base64Encode(*reinterpret_cast<Vector<char>*>(&encodedImage), base64Data);
+
+ return makeString("data:", mimeType, ";base64,", base64Data);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/ImageSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp
new file mode 100644
index 0000000..c7fa6f4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "BitmapImageSingleFrameSkia.h"
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "GLES2Canvas.h"
+#include "GraphicsContext.h"
+#include "Logging.h"
+#include "NativeImageSkia.h"
+#include "PlatformContextSkia.h"
+#include "PlatformString.h"
+#include "SkPixelRef.h"
+#include "SkRect.h"
+#include "SkShader.h"
+#include "SkiaUtils.h"
+#include "Texture.h"
+
+#include "skia/ext/image_operations.h"
+#include "skia/ext/platform_canvas.h"
+
+namespace WebCore {
+
+// Used by computeResamplingMode to tell how bitmaps should be resampled.
+enum ResamplingMode {
+ // Nearest neighbor resampling. Used when we detect that the page is
+ // trying to make a pattern by stretching a small bitmap very large.
+ RESAMPLE_NONE,
+
+ // Default skia resampling. Used for large growing of images where high
+ // quality resampling doesn't get us very much except a slowdown.
+ RESAMPLE_LINEAR,
+
+ // High quality resampling.
+ RESAMPLE_AWESOME,
+};
+
+static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight)
+{
+ if (platformContext->hasImageResamplingHint()) {
+ IntSize srcSize;
+ FloatSize dstSize;
+ platformContext->getImageResamplingHint(&srcSize, &dstSize);
+ srcWidth = srcSize.width();
+ srcHeight = srcSize.height();
+ destWidth = dstSize.width();
+ destHeight = dstSize.height();
+ }
+
+ int destIWidth = static_cast<int>(destWidth);
+ int destIHeight = static_cast<int>(destHeight);
+
+ // The percent change below which we will not resample. This usually means
+ // an off-by-one error on the web page, and just doing nearest neighbor
+ // sampling is usually good enough.
+ const float kFractionalChangeThreshold = 0.025f;
+
+ // Images smaller than this in either direction are considered "small" and
+ // are not resampled ever (see below).
+ const int kSmallImageSizeThreshold = 8;
+
+ // The amount an image can be stretched in a single direction before we
+ // say that it is being stretched so much that it must be a line or
+ // background that doesn't need resampling.
+ const float kLargeStretch = 3.0f;
+
+ // Figure out if we should resample this image. We try to prune out some
+ // common cases where resampling won't give us anything, since it is much
+ // slower than drawing stretched.
+ if (srcWidth == destIWidth && srcHeight == destIHeight) {
+ // We don't need to resample if the source and destination are the same.
+ return RESAMPLE_NONE;
+ }
+
+ if (srcWidth <= kSmallImageSizeThreshold
+ || srcHeight <= kSmallImageSizeThreshold
+ || destWidth <= kSmallImageSizeThreshold
+ || destHeight <= kSmallImageSizeThreshold) {
+ // Never resample small images. These are often used for borders and
+ // rules (think 1x1 images used to make lines).
+ return RESAMPLE_NONE;
+ }
+
+ if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) {
+ // Large image detected.
+
+ // Don't resample if it is being stretched a lot in only one direction.
+ // This is trying to catch cases where somebody has created a border
+ // (which might be large) and then is stretching it to fill some part
+ // of the page.
+ if (srcWidth == destWidth || srcHeight == destHeight)
+ return RESAMPLE_NONE;
+
+ // The image is growing a lot and in more than one direction. Resampling
+ // is slow and doesn't give us very much when growing a lot.
+ return RESAMPLE_LINEAR;
+ }
+
+ if ((fabs(destWidth - srcWidth) / srcWidth < kFractionalChangeThreshold)
+ && (fabs(destHeight - srcHeight) / srcHeight < kFractionalChangeThreshold)) {
+ // It is disappointingly common on the web for image sizes to be off by
+ // one or two pixels. We don't bother resampling if the size difference
+ // is a small fraction of the original size.
+ return RESAMPLE_NONE;
+ }
+
+ // When the image is not yet done loading, use linear. We don't cache the
+ // partially resampled images, and as they come in incrementally, it causes
+ // us to have to resample the whole thing every time.
+ if (!bitmap.isDataComplete())
+ return RESAMPLE_LINEAR;
+
+ // Everything else gets resampled.
+ // If the platform context permits high quality interpolation, use it.
+ // High quality interpolation only enabled for scaling and translation.
+ if (platformContext->interpolationQuality() == InterpolationHigh
+ && !(platformContext->canvas()->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)))
+ return RESAMPLE_AWESOME;
+
+ return RESAMPLE_LINEAR;
+}
+
+// Draws the given bitmap to the given canvas. The subset of the source bitmap
+// identified by src_rect is drawn to the given destination rect. The bitmap
+// will be resampled to resample_width * resample_height (this is the size of
+// the whole image, not the subset). See shouldResampleBitmap for more.
+//
+// This does a lot of computation to resample only the portion of the bitmap
+// that will only be drawn. This is critical for performance since when we are
+// scrolling, for example, we are only drawing a small strip of the image.
+// Resampling the whole image every time is very slow, so this speeds up things
+// dramatically.
+static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect)
+{
+ // First get the subset we need. This is efficient and does not copy pixels.
+ SkBitmap subset;
+ bitmap.extractSubset(&subset, srcIRect);
+ SkRect srcRect;
+ srcRect.set(srcIRect);
+
+ // Whether we're doing a subset or using the full source image.
+ bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0
+ && srcIRect.width() == bitmap.width()
+ && srcIRect.height() == bitmap.height();
+
+ // We will always draw in integer sizes, so round the destination rect.
+ SkIRect destRectRounded;
+ destRect.round(&destRectRounded);
+ SkIRect resizedImageRect = // Represents the size of the resized image.
+ { 0, 0, destRectRounded.width(), destRectRounded.height() };
+
+ // Apply forward transform to destRect to estimate required size of
+ // re-sampled bitmap, and use only in calls required to resize, or that
+ // check for the required size.
+ SkRect destRectTransformed;
+ canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect);
+ SkIRect destRectTransformedRounded;
+ destRectTransformed.round(&destRectTransformedRounded);
+
+ if (srcIsFull && bitmap.hasResizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height())) {
+ // Yay, this bitmap frame already has a resized version.
+ SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height());
+ canvas.drawBitmapRect(resampled, 0, destRect, &paint);
+ return;
+ }
+
+ // Compute the visible portion of our rect.
+ // We also need to compute the transformed portion of the
+ // visible portion for use below.
+ SkRect destBitmapSubsetSk;
+ ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk);
+ SkRect destBitmapSubsetTransformed;
+ canvas.getTotalMatrix().mapRect(&destBitmapSubsetTransformed, destBitmapSubsetSk);
+ destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop);
+ SkIRect destBitmapSubsetTransformedRounded;
+ destBitmapSubsetTransformed.round(&destBitmapSubsetTransformedRounded);
+ destBitmapSubsetTransformedRounded.offset(-destRectTransformedRounded.fLeft, -destRectTransformedRounded.fTop);
+
+ // The matrix inverting, etc. could have introduced rounding error which
+ // causes the bounds to be outside of the resized bitmap. We round outward
+ // so we always lean toward it being larger rather than smaller than we
+ // need, and then clamp to the bitmap bounds so we don't get any invalid
+ // data.
+ SkIRect destBitmapSubsetSkI;
+ destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI);
+ if (!destBitmapSubsetSkI.intersect(resizedImageRect))
+ return; // Resized image does not intersect.
+
+ if (srcIsFull && bitmap.shouldCacheResampling(
+ resizedImageRect.width(),
+ resizedImageRect.height(),
+ destBitmapSubsetSkI.width(),
+ destBitmapSubsetSkI.height())) {
+ // We're supposed to resize the entire image and cache it, even though
+ // we don't need all of it.
+ SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(),
+ destRectTransformedRounded.height());
+ canvas.drawBitmapRect(resampled, 0, destRect, &paint);
+ } else {
+ // We should only resize the exposed part of the bitmap to do the
+ // minimal possible work.
+
+ // Resample the needed part of the image.
+ // Transforms above plus rounding may cause destBitmapSubsetTransformedRounded
+ // to go outside the image, so need to clip to avoid problems.
+ if (destBitmapSubsetTransformedRounded.intersect(0, 0,
+ destRectTransformedRounded.width(), destRectTransformedRounded.height())) {
+
+ SkBitmap resampled = skia::ImageOperations::Resize(subset,
+ skia::ImageOperations::RESIZE_LANCZOS3,
+ destRectTransformedRounded.width(), destRectTransformedRounded.height(),
+ destBitmapSubsetTransformedRounded);
+
+ // Compute where the new bitmap should be drawn. Since our new bitmap
+ // may be smaller than the original, we have to shift it over by the
+ // same amount that we cut off the top and left.
+ destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop);
+ SkRect offsetDestRect;
+ offsetDestRect.set(destBitmapSubsetSkI);
+
+ canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint);
+ }
+ }
+}
+
+static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp)
+{
+ SkPaint paint;
+ paint.setXfermodeMode(compOp);
+ paint.setFilterBitmap(true);
+ paint.setAlpha(platformContext->getNormalizedAlpha());
+
+ skia::PlatformCanvas* canvas = platformContext->canvas();
+
+ ResamplingMode resampling = platformContext->isPrinting() ? RESAMPLE_NONE :
+ computeResamplingMode(platformContext, bitmap, srcRect.width(), srcRect.height(),
+ SkScalarToFloat(destRect.width()),
+ SkScalarToFloat(destRect.height()));
+ if (resampling == RESAMPLE_AWESOME) {
+ drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect);
+ } else {
+ // No resampling necessary, we can just draw the bitmap. We want to
+ // filter it if we decided to do linear interpolation above, or if there
+ // is something interesting going on with the matrix (like a rotation).
+ // Note: for serialization, we will want to subset the bitmap first so
+ // we don't send extra pixels.
+ canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint);
+ }
+}
+
+// Transforms the given dimensions with the given matrix. Used to see how big
+// images will be once transformed.
+static void TransformDimensions(const SkMatrix& matrix, float srcWidth, float srcHeight, float* destWidth, float* destHeight) {
+ // Transform 3 points to see how long each side of the bitmap will be.
+ SkPoint src_points[3]; // (0, 0), (width, 0), (0, height).
+ src_points[0].set(0, 0);
+ src_points[1].set(SkFloatToScalar(srcWidth), 0);
+ src_points[2].set(0, SkFloatToScalar(srcHeight));
+
+ // Now measure the length of the two transformed vectors relative to the
+ // transformed origin to see how big the bitmap will be. Note: for skews,
+ // this isn't the best thing, but we don't have skews.
+ SkPoint dest_points[3];
+ matrix.mapPoints(dest_points, src_points, 3);
+ *destWidth = SkScalarToFloat((dest_points[1] - dest_points[0]).length());
+ *destHeight = SkScalarToFloat((dest_points[2] - dest_points[0]).length());
+}
+
+// A helper method for translating negative width and height values.
+static FloatRect normalizeRect(const FloatRect& rect)
+{
+ FloatRect norm = rect;
+ if (norm.width() < 0) {
+ norm.setX(norm.x() + norm.width());
+ norm.setWidth(-norm.width());
+ }
+ if (norm.height() < 0) {
+ norm.setY(norm.y() + norm.height());
+ norm.setHeight(-norm.height());
+ }
+ return norm;
+}
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ // ImageSource::createFrameAtIndex() allocated |m_frame| and passed
+ // ownership to BitmapImage; we must delete it here.
+ delete m_frame;
+ m_frame = 0;
+ return true;
+ }
+ return false;
+}
+
+void Image::drawPattern(GraphicsContext* context,
+ const FloatRect& floatSrcRect,
+ const AffineTransform& patternTransform,
+ const FloatPoint& phase,
+ ColorSpace styleColorSpace,
+ CompositeOperator compositeOp,
+ const FloatRect& destRect)
+{
+ FloatRect normSrcRect = normalizeRect(floatSrcRect);
+ if (destRect.isEmpty() || normSrcRect.isEmpty())
+ return; // nothing to draw
+
+ NativeImageSkia* bitmap = nativeImageForCurrentFrame();
+ if (!bitmap)
+ return;
+
+ // This is a very inexpensive operation. It will generate a new bitmap but
+ // it will internally reference the old bitmap's pixels, adjusting the row
+ // stride so the extra pixels appear as padding to the subsetted bitmap.
+ SkBitmap srcSubset;
+ SkIRect srcRect = enclosingIntRect(normSrcRect);
+ bitmap->extractSubset(&srcSubset, srcRect);
+
+ SkBitmap resampled;
+ SkShader* shader;
+
+ // Figure out what size the bitmap will be in the destination. The
+ // destination rect is the bounds of the pattern, we need to use the
+ // matrix to see how bit it will be.
+ float destBitmapWidth, destBitmapHeight;
+ TransformDimensions(patternTransform, srcRect.width(), srcRect.height(),
+ &destBitmapWidth, &destBitmapHeight);
+
+ // Compute the resampling mode.
+ ResamplingMode resampling;
+ if (context->platformContext()->isPrinting())
+ resampling = RESAMPLE_LINEAR;
+ else {
+ resampling = computeResamplingMode(context->platformContext(), *bitmap,
+ srcRect.width(), srcRect.height(),
+ destBitmapWidth, destBitmapHeight);
+ }
+
+ // Load the transform WebKit requested.
+ SkMatrix matrix(patternTransform);
+
+ if (resampling == RESAMPLE_AWESOME) {
+ // Do nice resampling.
+ SkBitmap resampled;
+ int width = static_cast<int>(destBitmapWidth);
+ int height = static_cast<int>(destBitmapHeight);
+ if (!srcRect.fLeft && !srcRect.fTop
+ && srcRect.fRight == bitmap->width() && srcRect.fBottom == bitmap->height()
+ && (bitmap->hasResizedBitmap(width, height)
+ || bitmap->shouldCacheResampling(width, height, width, height))) {
+ // resizedBitmap() caches resized image.
+ resampled = bitmap->resizedBitmap(width, height);
+ } else {
+ resampled = skia::ImageOperations::Resize(srcSubset,
+ skia::ImageOperations::RESIZE_LANCZOS3, width, height);
+ }
+ shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
+
+ // Since we just resized the bitmap, we need to undo the scale set in
+ // the image transform.
+ matrix.setScaleX(SkIntToScalar(1));
+ matrix.setScaleY(SkIntToScalar(1));
+ } else {
+ // No need to do nice resampling.
+ shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
+ }
+
+ // We also need to translate it such that the origin of the pattern is the
+ // origin of the destination rect, which is what WebKit expects. Skia uses
+ // the coordinate system origin as the base for the patter. If WebKit wants
+ // a shifted image, it will shift it from there using the patternTransform.
+ float adjustedX = phase.x() + normSrcRect.x() *
+ narrowPrecisionToFloat(patternTransform.a());
+ float adjustedY = phase.y() + normSrcRect.y() *
+ narrowPrecisionToFloat(patternTransform.d());
+ matrix.postTranslate(SkFloatToScalar(adjustedX),
+ SkFloatToScalar(adjustedY));
+ shader->setLocalMatrix(matrix);
+
+ SkPaint paint;
+ paint.setShader(shader)->unref();
+ paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
+ paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
+
+ context->platformContext()->paintSkPaint(destRect, paint);
+}
+
+static void drawBitmapGLES2(GraphicsContext* ctxt, NativeImageSkia* bitmap, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ ctxt->platformContext()->prepareForHardwareDraw();
+ GLES2Canvas* gpuCanvas = ctxt->platformContext()->gpuCanvas();
+ Texture* texture = gpuCanvas->getTexture(bitmap);
+ if (!texture) {
+ ASSERT(bitmap->config() == SkBitmap::kARGB_8888_Config);
+ ASSERT(bitmap->rowBytes() == bitmap->width() * 4);
+ texture = gpuCanvas->createTexture(bitmap, Texture::BGRA8, bitmap->width(), bitmap->height());
+ SkAutoLockPixels lock(*bitmap);
+ ASSERT(bitmap->getPixels());
+ texture->load(bitmap->getPixels());
+ }
+ gpuCanvas->drawTexturedRect(texture, srcRect, dstRect, styleColorSpace, compositeOp);
+}
+
+// ================================================
+// BitmapImage Class
+// ================================================
+
+// FIXME: These should go to BitmapImageSkia.cpp
+
+void BitmapImage::initPlatformData()
+{
+ // This is not used. On Mac, the "platform" data is a cache of some OS
+ // specific versions of the image that are created is some cases. These
+ // aren't normally used, it is equivalent to getHBITMAP on Windows, and
+ // the platform data is the cache.
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+ // See initPlatformData above.
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_checkedForSolidColor = true;
+}
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
+ const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp)
+{
+ if (!m_source.initialized())
+ return;
+
+ // Spin the animation to the correct frame before we try to draw it, so we
+ // don't draw an old frame and then immediately need to draw a newer one,
+ // causing flicker and wasting CPU.
+ startAnimation();
+
+ NativeImageSkia* bm = nativeImageForCurrentFrame();
+ if (!bm)
+ return; // It's too early and we don't have an image yet.
+
+ FloatRect normDstRect = normalizeRect(dstRect);
+ FloatRect normSrcRect = normalizeRect(srcRect);
+
+ if (normSrcRect.isEmpty() || normDstRect.isEmpty())
+ return; // Nothing to draw.
+
+ if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) {
+ drawBitmapGLES2(ctxt, bm, normSrcRect, normDstRect, colorSpace, compositeOp);
+ return;
+ }
+
+ ctxt->platformContext()->prepareForSoftwareDraw();
+
+ paintSkBitmap(ctxt->platformContext(),
+ *bm,
+ enclosingIntRect(normSrcRect),
+ normDstRect,
+ WebCoreCompositeToSkiaComposite(compositeOp));
+}
+
+// FIXME: These should go into BitmapImageSingleFrameSkia.cpp
+
+void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
+ const FloatRect& dstRect,
+ const FloatRect& srcRect,
+ ColorSpace styleColorSpace,
+ CompositeOperator compositeOp)
+{
+ FloatRect normDstRect = normalizeRect(dstRect);
+ FloatRect normSrcRect = normalizeRect(srcRect);
+
+ if (normSrcRect.isEmpty() || normDstRect.isEmpty())
+ return; // Nothing to draw.
+
+ if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) {
+ drawBitmapGLES2(ctxt, &m_nativeImage, srcRect, dstRect, styleColorSpace, compositeOp);
+ return;
+ }
+
+ ctxt->platformContext()->prepareForSoftwareDraw();
+
+ paintSkBitmap(ctxt->platformContext(),
+ m_nativeImage,
+ enclosingIntRect(normSrcRect),
+ normDstRect,
+ WebCoreCompositeToSkiaComposite(compositeOp));
+}
+
+BitmapImageSingleFrameSkia::BitmapImageSingleFrameSkia(const SkBitmap& bitmap)
+ : m_nativeImage(bitmap)
+{
+}
+
+PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap, bool copyPixels)
+{
+ if (copyPixels) {
+ SkBitmap temp;
+ bitmap.copyTo(&temp, bitmap.config());
+ return adoptRef(new BitmapImageSingleFrameSkia(temp));
+ }
+ return adoptRef(new BitmapImageSingleFrameSkia(bitmap));
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/IntPointSkia.cpp b/Source/WebCore/platform/graphics/skia/IntPointSkia.cpp
new file mode 100644
index 0000000..fd9a6fd
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/IntPointSkia.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include "SkPoint.h"
+
+namespace WebCore {
+
+IntPoint::IntPoint(const SkIPoint& p)
+ : m_x(p.fX)
+ , m_y(p.fY)
+{
+}
+
+IntPoint::operator SkIPoint() const
+{
+ SkIPoint p = { m_x, m_y };
+ return p;
+}
+
+IntPoint::operator SkPoint() const
+{
+ SkPoint p = { SkIntToScalar(m_x), SkIntToScalar(m_y) };
+ return p;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/IntRectSkia.cpp b/Source/WebCore/platform/graphics/skia/IntRectSkia.cpp
new file mode 100644
index 0000000..ea138ee
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/IntRectSkia.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include "SkRect.h"
+
+namespace WebCore {
+
+IntRect::operator SkIRect() const
+{
+ SkIRect rect = { x(), y(), right(), bottom() };
+ return rect;
+}
+
+IntRect::operator SkRect() const
+{
+ SkRect rect;
+ rect.set(SkIntToScalar(x()), SkIntToScalar(y()), SkIntToScalar(right()), SkIntToScalar(bottom()));
+ return rect;
+}
+
+IntRect::IntRect(const SkIRect& r)
+ : m_location(r.fLeft, r.fTop)
+ , m_size(r.width(), r.height())
+{
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/NativeImageSkia.cpp b/Source/WebCore/platform/graphics/skia/NativeImageSkia.cpp
new file mode 100644
index 0000000..94f9b75
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/NativeImageSkia.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+
+#if !PLATFORM(ANDROID)
+#include "skia/ext/image_operations.h"
+#endif
+
+#include "NativeImageSkia.h"
+#include "SharedGraphicsContext3D.h"
+#include "SkiaUtils.h"
+
+namespace WebCore {
+
+NativeImageSkia::NativeImageSkia()
+ : m_isDataComplete(false),
+ m_lastRequestSize(0, 0),
+ m_resizeRequests(0)
+{
+}
+
+NativeImageSkia::NativeImageSkia(const SkBitmap& other)
+ : SkBitmap(other),
+ m_isDataComplete(false),
+ m_lastRequestSize(0, 0),
+ m_resizeRequests(0)
+{
+}
+
+
+NativeImageSkia::~NativeImageSkia()
+{
+#if PLATFORM(ANDROID)
+ // SharedGraphicsContext3D::removeTexturesFor() takes a NativeImagePtr. On
+ // Chromium, this is NativeImageSkia, which inherits from SkBitmap. On
+ // Android, NativeImagePtr is a SkBitmapRef, which is a wrapper around
+ // SkBitmap. Failing to call removeTexturesFor() probably causes a leak.
+ // TODO: Fix this. See http://b/3047425
+#else
+ SharedGraphicsContext3D::removeTexturesFor(this);
+#endif
+}
+
+int NativeImageSkia::decodedSize() const
+{
+ return getSize() + m_resizedImage.getSize();
+}
+
+bool NativeImageSkia::hasResizedBitmap(int w, int h) const
+{
+ if (m_lastRequestSize.width() == w && m_lastRequestSize.height() == h)
+ m_resizeRequests++;
+ else {
+ m_lastRequestSize = IntSize(w, h);
+ m_resizeRequests = 0;
+ }
+
+ return m_resizedImage.width() == w && m_resizedImage.height() == h;
+}
+
+// FIXME: don't cache when image is in-progress.
+
+SkBitmap NativeImageSkia::resizedBitmap(int w, int h) const
+{
+#if !PLATFORM(ANDROID)
+ if (m_resizedImage.width() != w || m_resizedImage.height() != h)
+ m_resizedImage = skia::ImageOperations::Resize(*this, skia::ImageOperations::RESIZE_LANCZOS3, w, h);
+#endif
+
+ return m_resizedImage;
+}
+
+bool NativeImageSkia::shouldCacheResampling(int destWidth,
+ int destHeight,
+ int destSubsetWidth,
+ int destSubsetHeight) const
+{
+ // We can not cache incomplete frames. This might be a good optimization in
+ // the future, were we know how much of the frame has been decoded, so when
+ // we incrementally draw more of the image, we only have to resample the
+ // parts that are changed.
+ if (!m_isDataComplete)
+ return false;
+
+ // If the destination bitmap is small, we'll always allow caching, since
+ // there is not very much penalty for computing it and it may come in handy.
+ static const int kSmallBitmapSize = 4096;
+ if (destWidth * destHeight <= kSmallBitmapSize)
+ return true;
+
+ // If "too many" requests have been made for this bitmap, we assume that
+ // many more will be made as well, and we'll go ahead and cache it.
+ static const int kManyRequestThreshold = 4;
+ if (m_lastRequestSize.width() == destWidth &&
+ m_lastRequestSize.height() == destHeight) {
+ if (m_resizeRequests >= kManyRequestThreshold)
+ return true;
+ } else {
+ // When a different size is being requested, count this as a query
+ // (hasResizedBitmap) and reset the counter.
+ m_lastRequestSize = IntSize(destWidth, destHeight);
+ m_resizeRequests = 0;
+ }
+
+ // Otherwise, use the heuristic that if more than 1/4 of the image is
+ // requested, it's worth caching.
+ int destSize = destWidth * destHeight;
+ int destSubsetSize = destSubsetWidth * destSubsetHeight;
+ return destSize / 4 < destSubsetSize;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/NativeImageSkia.h b/Source/WebCore/platform/graphics/skia/NativeImageSkia.h
new file mode 100644
index 0000000..00b0a68
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/NativeImageSkia.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2008, 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 NativeImageSkia_h
+#define NativeImageSkia_h
+
+#include "SkBitmap.h"
+#include "IntSize.h"
+
+namespace WebCore {
+
+// This object is used as the "native image" in our port. When WebKit uses
+// "NativeImagePtr", it is a pointer to this type. It is an SkBitmap, but also
+// stores a cached resized image.
+class NativeImageSkia : public SkBitmap {
+public:
+ NativeImageSkia();
+ ~NativeImageSkia();
+
+ // This constructor does a shallow copy of the passed-in SkBitmap (ie., it
+ // references the same pixel data and bumps the refcount). Use only when
+ // you want sharing semantics.
+ explicit NativeImageSkia(const SkBitmap&);
+
+ // Returns the number of bytes of image data. This includes the cached
+ // resized version if there is one.
+ int decodedSize() const;
+
+ // Sets the data complete flag. This is called by the image decoder when
+ // all data is complete, and used by us to know whether we can cache
+ // resized images.
+ void setDataComplete() { m_isDataComplete = true; }
+
+ // Returns true if the entire image has been decoded.
+ bool isDataComplete() const { return m_isDataComplete; }
+
+ // We can keep a resized version of the bitmap cached on this object.
+ // This function will return true if there is a cached version of the
+ // given image subset with the given dimensions.
+ bool hasResizedBitmap(int width, int height) const;
+
+ // This will return an existing resized image, or generate a new one of
+ // the specified size and store it in the cache. Subsetted images can not
+ // be cached unless the subset is the entire bitmap.
+ SkBitmap resizedBitmap(int width, int height) const;
+
+ // Returns true if the given resize operation should either resize the whole
+ // image and cache it, or resize just the part it needs and throw the result
+ // away.
+ //
+ // On the one hand, if only a small subset is desired, then we will waste a
+ // lot of time resampling the entire thing, so we only want to do exactly
+ // what's required. On the other hand, resampling the entire bitmap is
+ // better if we're going to be using it more than once (like a bitmap
+ // scrolling on and off the screen. Since we only cache when doing the
+ // entire thing, it's best to just do it up front.
+ bool shouldCacheResampling(int destWidth,
+ int destHeight,
+ int destSubsetWidth,
+ int destSubsetHeight) const;
+
+private:
+ // Set to true when the data is complete. Before the entire image has
+ // loaded, we do not want to cache a resize.
+ bool m_isDataComplete;
+
+ // The cached bitmap. This will be empty() if there is no cached image.
+ mutable SkBitmap m_resizedImage;
+
+ // References how many times that the image size has been requested for
+ // the last size.
+ //
+ // Every time we get a request, if it matches the m_lastRequestSize, we'll
+ // increment the counter, and if not, we'll reset the counter and save the
+ // size.
+ //
+ // This allows us to see if many requests have been made for the same
+ // resized image, we know that we should probably cache it, even if all of
+ // those requests individually are small and would not otherwise be cached.
+ mutable IntSize m_lastRequestSize;
+ mutable int m_resizeRequests;
+};
+
+}
+#endif // NativeImageSkia_h
+
diff --git a/Source/WebCore/platform/graphics/skia/PathSkia.cpp b/Source/WebCore/platform/graphics/skia/PathSkia.cpp
new file mode 100644
index 0000000..89323c4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/PathSkia.cpp
@@ -0,0 +1,274 @@
+// Copyright (c) 2008, 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.
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "ImageBuffer.h"
+#include "StrokeStyleApplier.h"
+
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkiaUtils.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+Path::Path()
+{
+ m_path = new SkPath;
+}
+
+Path::Path(const Path& other)
+{
+ m_path = new SkPath(*other.m_path);
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path& Path::operator=(const Path& other)
+{
+ *m_path = *other.m_path;
+ return *this;
+}
+
+bool Path::isEmpty() const
+{
+ return m_path->isEmpty();
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return m_path->getPoints(NULL, 0) != 0;
+}
+
+FloatPoint Path::currentPoint() const
+{
+ // FIXME: return current point of subpath.
+ float quietNaN = std::numeric_limits<float>::quiet_NaN();
+ return FloatPoint(quietNaN, quietNaN);
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ return SkPathContainsPoint(m_path, point,
+ rule == RULE_NONZERO ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType);
+}
+
+void Path::translate(const FloatSize& size)
+{
+ m_path->offset(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height()));
+}
+
+FloatRect Path::boundingRect() const
+{
+ return m_path->getBounds();
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ m_path->moveTo(point);
+}
+
+void Path::addLineTo(const FloatPoint& point)
+{
+ m_path->lineTo(point);
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep)
+{
+ m_path->quadTo(cp, ep);
+}
+
+void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& ep)
+{
+ m_path->cubicTo(p1, p2, ep);
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ m_path->arcTo(p1, p2, WebCoreFloatToSkScalar(radius));
+}
+
+void Path::closeSubpath()
+{
+ m_path->close();
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlockwise) {
+ SkScalar cx = WebCoreFloatToSkScalar(p.x());
+ SkScalar cy = WebCoreFloatToSkScalar(p.y());
+ SkScalar radius = WebCoreFloatToSkScalar(r);
+ SkScalar s360 = SkIntToScalar(360);
+
+ SkRect oval;
+ oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
+
+ float sweep = ea - sa;
+ SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat);
+ SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat);
+ // Check for a circle.
+ if (sweepDegrees >= s360 || sweepDegrees <= -s360) {
+ // Move to the start position (0 sweep means we add a single point).
+ m_path->arcTo(oval, startDegrees, 0, false);
+ // Draw the circle.
+ m_path->addOval(oval);
+ // Force a moveTo the end position.
+ m_path->arcTo(oval, startDegrees + sweepDegrees, 0, true);
+ } else {
+ // Counterclockwise arcs should be drawn with negative sweeps, while
+ // clockwise arcs should be drawn with positive sweeps. Check to see
+ // if the situation is reversed and correct it by adding or subtracting
+ // a full circle
+ if (anticlockwise && sweepDegrees > 0) {
+ sweepDegrees -= s360;
+ } else if (!anticlockwise && sweepDegrees < 0) {
+ sweepDegrees += s360;
+ }
+
+ m_path->arcTo(oval, startDegrees, sweepDegrees, false);
+ }
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+ m_path->addRect(rect);
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+ m_path->addOval(rect);
+}
+
+void Path::clear()
+{
+ m_path->reset();
+}
+
+static FloatPoint* convertPathPoints(FloatPoint dst[], const SkPoint src[], int count)
+{
+ for (int i = 0; i < count; i++) {
+ dst[i].setX(SkScalarToFloat(src[i].fX));
+ dst[i].setY(SkScalarToFloat(src[i].fY));
+ }
+ return dst;
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ SkPath::Iter iter(*m_path, false);
+ SkPoint pts[4];
+ PathElement pathElement;
+ FloatPoint pathPoints[3];
+
+ for (;;) {
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ pathElement.type = PathElementMoveToPoint;
+ pathElement.points = convertPathPoints(pathPoints, &pts[0], 1);
+ break;
+ case SkPath::kLine_Verb:
+ pathElement.type = PathElementAddLineToPoint;
+ pathElement.points = convertPathPoints(pathPoints, &pts[1], 1);
+ break;
+ case SkPath::kQuad_Verb:
+ pathElement.type = PathElementAddQuadCurveToPoint;
+ pathElement.points = convertPathPoints(pathPoints, &pts[1], 2);
+ break;
+ case SkPath::kCubic_Verb:
+ pathElement.type = PathElementAddCurveToPoint;
+ pathElement.points = convertPathPoints(pathPoints, &pts[1], 3);
+ break;
+ case SkPath::kClose_Verb:
+ pathElement.type = PathElementCloseSubpath;
+ pathElement.points = convertPathPoints(pathPoints, 0, 0);
+ break;
+ case SkPath::kDone_Verb:
+ return;
+ }
+ function(info, &pathElement);
+ }
+}
+
+void Path::transform(const AffineTransform& xform)
+{
+ m_path->transform(xform);
+}
+
+// Computes the bounding box for the stroke and style currently selected into
+// the given bounding box. This also takes into account the stroke width.
+static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context)
+{
+ SkPaint paint;
+ context->platformContext()->setupPaintForStroking(&paint, 0, 0);
+ SkPath boundingPath;
+ paint.getFillPath(context->platformContext()->currentPathInLocalCoordinates(), &boundingPath);
+ return boundingPath.getBounds();
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ GraphicsContext* scratch = scratchContext();
+ scratch->save();
+ scratch->beginPath();
+ scratch->addPath(*this);
+
+ if (applier)
+ applier->strokeStyle(scratch);
+
+ FloatRect r = boundingBoxForCurrentStroke(scratch);
+ scratch->restore();
+ return r;
+}
+
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+ GraphicsContext* scratch = scratchContext();
+ scratch->save();
+
+ applier->strokeStyle(scratch);
+
+ SkPaint paint;
+ scratch->platformContext()->setupPaintForStroking(&paint, 0, 0);
+ SkPath strokePath;
+ paint.getFillPath(*platformPath(), &strokePath);
+ bool contains = SkPathContainsPoint(&strokePath, point,
+ SkPath::kWinding_FillType);
+
+ scratch->restore();
+ return contains;
+}
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/PatternSkia.cpp b/Source/WebCore/platform/graphics/skia/PatternSkia.cpp
new file mode 100644
index 0000000..72fac77
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/PatternSkia.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2008 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "Pattern.h"
+
+#include "AffineTransform.h"
+#include "Image.h"
+#include "NativeImageSkia.h"
+
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkColorShader.h"
+#include "SkShader.h"
+
+namespace WebCore {
+
+void Pattern::platformDestroy()
+{
+ SkSafeUnref(m_pattern);
+ m_pattern = 0;
+}
+
+PlatformPatternPtr Pattern::platformPattern(const AffineTransform& patternTransform)
+{
+ if (m_pattern)
+ return m_pattern;
+
+ // Note: patternTransform is ignored since it seems to be applied elsewhere
+ // (when the pattern is used?). Applying it to the pattern (i.e.
+ // shader->setLocalMatrix) results in a double transformation. This can be
+ // seen, for instance, as an extra offset in:
+ // LayoutTests/fast/canvas/patternfill-repeat.html
+ // and expanded scale and skew in:
+ // LayoutTests/svg/W3C-SVG-1.1/pservers-grad-06-b.svg
+
+ SkBitmap* bm = m_tileImage->nativeImageForCurrentFrame();
+ // If we don't have a bitmap, return a transparent shader.
+ if (!bm)
+ m_pattern = new SkColorShader(SkColorSetARGB(0, 0, 0, 0));
+
+ else if (m_repeatX && m_repeatY)
+ m_pattern = SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
+
+ else {
+
+ // Skia does not have a "draw the tile only once" option. Clamp_TileMode
+ // repeats the last line of the image after drawing one tile. To avoid
+ // filling the space with arbitrary pixels, this workaround forces the
+ // image to have a line of transparent pixels on the "repeated" edge(s),
+ // thus causing extra space to be transparent filled.
+ SkShader::TileMode tileModeX = m_repeatX ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
+ SkShader::TileMode tileModeY = m_repeatY ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
+ int expandW = m_repeatX ? 0 : 1;
+ int expandH = m_repeatY ? 0 : 1;
+
+ // Create a transparent bitmap 1 pixel wider and/or taller than the
+ // original, then copy the orignal into it.
+ // FIXME: Is there a better way to pad (not scale) an image in skia?
+ SkBitmap bm2;
+ bm2.setConfig(bm->config(), bm->width() + expandW, bm->height() + expandH);
+ bm2.allocPixels();
+ bm2.eraseARGB(0x00, 0x00, 0x00, 0x00);
+ SkCanvas canvas(bm2);
+ canvas.drawBitmap(*bm, 0, 0);
+ m_pattern = SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY);
+ }
+ m_pattern->setLocalMatrix(m_patternSpaceTransformation);
+ return m_pattern;
+}
+
+void Pattern::setPlatformPatternSpaceTransform()
+{
+ if (m_pattern)
+ m_pattern->setLocalMatrix(m_patternSpaceTransformation);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
new file mode 100644
index 0000000..d3c0e00
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -0,0 +1,890 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+
+#include "PlatformContextSkia.h"
+
+#include "AffineTransform.h"
+#include "DrawingBuffer.h"
+#include "Extensions3D.h"
+#include "GraphicsContext.h"
+#include "GraphicsContext3D.h"
+#include "ImageBuffer.h"
+#include "NativeImageSkia.h"
+#include "SkiaUtils.h"
+#include "Texture.h"
+#include "TilingData.h"
+
+#include "skia/ext/image_operations.h"
+#include "skia/ext/platform_canvas.h"
+
+#include "SkBitmap.h"
+#include "SkColorPriv.h"
+#include "SkDashPathEffect.h"
+#include "SkShader.h"
+
+#include <wtf/MathExtras.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/Vector.h>
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+#include "GLES2Canvas.h"
+#include "SharedGraphicsContext3D.h"
+#endif
+
+namespace WebCore {
+
+extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path);
+
+// State -----------------------------------------------------------------------
+
+// Encapsulates the additional painting state information we store for each
+// pushed graphics state.
+struct PlatformContextSkia::State {
+ State();
+ State(const State&);
+ ~State();
+
+ // Common shader state.
+ float m_alpha;
+ SkXfermode::Mode m_xferMode;
+ bool m_useAntialiasing;
+ SkDrawLooper* m_looper;
+
+ // Fill.
+ SkColor m_fillColor;
+ SkShader* m_fillShader;
+
+ // Stroke.
+ StrokeStyle m_strokeStyle;
+ SkColor m_strokeColor;
+ SkShader* m_strokeShader;
+ float m_strokeThickness;
+ int m_dashRatio; // Ratio of the length of a dash to its width.
+ float m_miterLimit;
+ SkPaint::Cap m_lineCap;
+ SkPaint::Join m_lineJoin;
+ SkDashPathEffect* m_dash;
+
+ // Text. (See TextModeFill & friends in GraphicsContext.h.)
+ TextDrawingModeFlags m_textDrawingMode;
+
+ // Helper function for applying the state's alpha value to the given input
+ // color to produce a new output color.
+ SkColor applyAlpha(SkColor) const;
+
+ // If non-empty, the current State is clipped to this image.
+ SkBitmap m_imageBufferClip;
+ // If m_imageBufferClip is non-empty, this is the region the image is clipped to.
+ FloatRect m_clip;
+
+ // This is a list of clipping paths which are currently active, in the
+ // order in which they were pushed.
+ WTF::Vector<SkPath> m_antiAliasClipPaths;
+ InterpolationQuality m_interpolationQuality;
+
+ // If we currently have a canvas (non-antialiased path) clip applied.
+ bool m_canvasClipApplied;
+
+ PlatformContextSkia::State cloneInheritedProperties();
+private:
+ // Not supported.
+ void operator=(const State&);
+};
+
+// Note: Keep theses default values in sync with GraphicsContextState.
+PlatformContextSkia::State::State()
+ : m_alpha(1)
+ , m_xferMode(SkXfermode::kSrcOver_Mode)
+ , m_useAntialiasing(true)
+ , m_looper(0)
+ , m_fillColor(0xFF000000)
+ , m_fillShader(0)
+ , m_strokeStyle(SolidStroke)
+ , m_strokeColor(Color::black)
+ , m_strokeShader(0)
+ , m_strokeThickness(0)
+ , m_dashRatio(3)
+ , m_miterLimit(4)
+ , m_lineCap(SkPaint::kDefault_Cap)
+ , m_lineJoin(SkPaint::kDefault_Join)
+ , m_dash(0)
+ , m_textDrawingMode(TextModeFill)
+ , m_interpolationQuality(InterpolationHigh)
+ , m_canvasClipApplied(false)
+{
+}
+
+PlatformContextSkia::State::State(const State& other)
+ : m_alpha(other.m_alpha)
+ , m_xferMode(other.m_xferMode)
+ , m_useAntialiasing(other.m_useAntialiasing)
+ , m_looper(other.m_looper)
+ , m_fillColor(other.m_fillColor)
+ , m_fillShader(other.m_fillShader)
+ , m_strokeStyle(other.m_strokeStyle)
+ , m_strokeColor(other.m_strokeColor)
+ , m_strokeShader(other.m_strokeShader)
+ , m_strokeThickness(other.m_strokeThickness)
+ , m_dashRatio(other.m_dashRatio)
+ , m_miterLimit(other.m_miterLimit)
+ , m_lineCap(other.m_lineCap)
+ , m_lineJoin(other.m_lineJoin)
+ , m_dash(other.m_dash)
+ , m_textDrawingMode(other.m_textDrawingMode)
+ , m_imageBufferClip(other.m_imageBufferClip)
+ , m_clip(other.m_clip)
+ , m_antiAliasClipPaths(other.m_antiAliasClipPaths)
+ , m_interpolationQuality(other.m_interpolationQuality)
+ , m_canvasClipApplied(other.m_canvasClipApplied)
+{
+ // Up the ref count of these. SkSafeRef does nothing if its argument is 0.
+ SkSafeRef(m_looper);
+ SkSafeRef(m_dash);
+ SkSafeRef(m_fillShader);
+ SkSafeRef(m_strokeShader);
+}
+
+PlatformContextSkia::State::~State()
+{
+ SkSafeUnref(m_looper);
+ SkSafeUnref(m_dash);
+ SkSafeUnref(m_fillShader);
+ SkSafeUnref(m_strokeShader);
+}
+
+// Returns a new State with all of this object's inherited properties copied.
+PlatformContextSkia::State PlatformContextSkia::State::cloneInheritedProperties()
+{
+ PlatformContextSkia::State state(*this);
+
+ // Everything is inherited except for the clip paths.
+ state.m_antiAliasClipPaths.clear();
+
+ return state;
+}
+
+SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
+{
+ int s = roundf(m_alpha * 256);
+ if (s >= 256)
+ return c;
+ if (s < 0)
+ return 0;
+
+ int a = SkAlphaMul(SkColorGetA(c), s);
+ return (c & 0x00FFFFFF) | (a << 24);
+}
+
+// PlatformContextSkia ---------------------------------------------------------
+
+// Danger: canvas can be NULL.
+PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
+ : m_canvas(canvas)
+ , m_drawingToImageBuffer(false)
+ , m_useGPU(false)
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ , m_gpuCanvas(0)
+#endif
+ , m_backingStoreState(None)
+{
+ m_stateStack.append(State());
+ m_state = &m_stateStack.last();
+}
+
+PlatformContextSkia::~PlatformContextSkia()
+{
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ if (m_gpuCanvas)
+ m_gpuCanvas->drawingBuffer()->setWillPublishCallback(0);
+#endif
+}
+
+void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
+{
+ m_canvas = canvas;
+}
+
+void PlatformContextSkia::setDrawingToImageBuffer(bool value)
+{
+ m_drawingToImageBuffer = value;
+}
+
+bool PlatformContextSkia::isDrawingToImageBuffer() const
+{
+ return m_drawingToImageBuffer;
+}
+
+void PlatformContextSkia::save()
+{
+ ASSERT(!hasImageResamplingHint());
+
+ m_stateStack.append(m_state->cloneInheritedProperties());
+ m_state = &m_stateStack.last();
+
+ // The clip image only needs to be applied once. Reset the image so that we
+ // don't attempt to clip multiple times.
+ m_state->m_imageBufferClip.reset();
+
+ // Save our native canvas.
+ canvas()->save();
+}
+
+void PlatformContextSkia::beginLayerClippedToImage(const FloatRect& rect,
+ const ImageBuffer* imageBuffer)
+{
+ // Skia doesn't support clipping to an image, so we create a layer. The next
+ // time restore is invoked the layer and |imageBuffer| are combined to
+ // create the resulting image.
+ m_state->m_clip = rect;
+ SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
+ SkFloatToScalar(rect.right()), SkFloatToScalar(rect.bottom()) };
+
+ canvas()->clipRect(bounds);
+ canvas()->saveLayerAlpha(&bounds, 255,
+ static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+ // Copy off the image as |imageBuffer| may be deleted before restore is invoked.
+ const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap();
+ if (!bitmap->pixelRef()) {
+ // The bitmap owns it's pixels. This happens when we've allocated the
+ // pixels in some way and assigned them directly to the bitmap (as
+ // happens when we allocate a DIB). In this case the assignment operator
+ // does not copy the pixels, rather the copied bitmap ends up
+ // referencing the same pixels. As the pixels may not live as long as we
+ // need it to, we copy the image.
+ bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config);
+ } else {
+ // If there is a pixel ref, we can safely use the assignment operator.
+ m_state->m_imageBufferClip = *bitmap;
+ }
+}
+
+void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath)
+{
+ // If we are currently tracking any anti-alias clip paths, then we already
+ // have a layer in place and don't need to add another.
+ bool haveLayerOutstanding = m_state->m_antiAliasClipPaths.size();
+
+ // See comments in applyAntiAliasedClipPaths about how this works.
+ m_state->m_antiAliasClipPaths.append(clipPath);
+
+ if (!haveLayerOutstanding) {
+ SkRect bounds = clipPath.getBounds();
+ canvas()->saveLayerAlpha(&bounds, 255, static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag));
+ // Guards state modification during clipped operations.
+ // The state is popped in applyAntiAliasedClipPaths().
+ canvas()->save();
+ }
+}
+
+void PlatformContextSkia::restore()
+{
+ if (!m_state->m_imageBufferClip.empty()) {
+ applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip);
+ canvas()->restore();
+ }
+
+ if (!m_state->m_antiAliasClipPaths.isEmpty())
+ applyAntiAliasedClipPaths(m_state->m_antiAliasClipPaths);
+
+ m_stateStack.removeLast();
+ m_state = &m_stateStack.last();
+
+ // Restore our native canvas.
+ canvas()->restore();
+}
+
+void PlatformContextSkia::drawRect(SkRect rect)
+{
+ SkPaint paint;
+ int fillcolorNotTransparent = m_state->m_fillColor & 0xFF000000;
+ if (fillcolorNotTransparent) {
+ setupPaintForFilling(&paint);
+ canvas()->drawRect(rect, paint);
+ }
+
+ if (m_state->m_strokeStyle != NoStroke
+ && (m_state->m_strokeColor & 0xFF000000)) {
+ // We do a fill of four rects to simulate the stroke of a border.
+ SkColor oldFillColor = m_state->m_fillColor;
+
+ // setFillColor() will set the shader to NULL, so save a ref to it now.
+ SkShader* oldFillShader = m_state->m_fillShader;
+ SkSafeRef(oldFillShader);
+ setFillColor(m_state->m_strokeColor);
+ paint.reset();
+ setupPaintForFilling(&paint);
+ SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 };
+ canvas()->drawRect(topBorder, paint);
+ SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.fRight, rect.fBottom };
+ canvas()->drawRect(bottomBorder, paint);
+ SkRect leftBorder = { rect.fLeft, rect.fTop + 1, rect.fLeft + 1, rect.fBottom - 1 };
+ canvas()->drawRect(leftBorder, paint);
+ SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, rect.fRight, rect.fBottom - 1 };
+ canvas()->drawRect(rightBorder, paint);
+ setFillColor(oldFillColor);
+ setFillShader(oldFillShader);
+ SkSafeUnref(oldFillShader);
+ }
+}
+
+void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const
+{
+#if defined(SK_DEBUG)
+ {
+ SkPaint defaultPaint;
+ SkASSERT(*paint == defaultPaint);
+ }
+#endif
+
+ paint->setAntiAlias(m_state->m_useAntialiasing);
+ paint->setXfermodeMode(m_state->m_xferMode);
+ paint->setLooper(m_state->m_looper);
+}
+
+void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const
+{
+ setupPaintCommon(paint);
+ paint->setColor(m_state->applyAlpha(m_state->m_fillColor));
+ paint->setShader(m_state->m_fillShader);
+}
+
+float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
+{
+ setupPaintCommon(paint);
+ float width = m_state->m_strokeThickness;
+
+ paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
+ paint->setShader(m_state->m_strokeShader);
+ paint->setStyle(SkPaint::kStroke_Style);
+ paint->setStrokeWidth(SkFloatToScalar(width));
+ paint->setStrokeCap(m_state->m_lineCap);
+ paint->setStrokeJoin(m_state->m_lineJoin);
+ paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
+
+ if (m_state->m_dash)
+ paint->setPathEffect(m_state->m_dash);
+ else {
+ switch (m_state->m_strokeStyle) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DashedStroke:
+ width = m_state->m_dashRatio * width;
+ // Fall through.
+ case DottedStroke:
+ // Truncate the width, since we don't want fuzzy dots or dashes.
+ int dashLength = static_cast<int>(width);
+ // Subtract off the endcaps, since they're rendered separately.
+ int distance = length - 2 * static_cast<int>(m_state->m_strokeThickness);
+ int phase = 1;
+ if (dashLength > 1) {
+ // Determine how many dashes or dots we should have.
+ int numDashes = distance / dashLength;
+ int remainder = distance % dashLength;
+ // Adjust the phase to center the dashes within the line.
+ if (numDashes % 2 == 0) {
+ // Even: shift right half a dash, minus half the remainder
+ phase = (dashLength - remainder) / 2;
+ } else {
+ // Odd: shift right a full dash, minus half the remainder
+ phase = dashLength - remainder / 2;
+ }
+ }
+ SkScalar dashLengthSk = SkIntToScalar(dashLength);
+ SkScalar intervals[2] = { dashLengthSk, dashLengthSk };
+ paint->setPathEffect(new SkDashPathEffect(intervals, 2, SkIntToScalar(phase)))->unref();
+ }
+ }
+
+ return width;
+}
+
+void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl)
+{
+ SkRefCnt_SafeAssign(m_state->m_looper, dl);
+}
+
+void PlatformContextSkia::setMiterLimit(float ml)
+{
+ m_state->m_miterLimit = ml;
+}
+
+void PlatformContextSkia::setAlpha(float alpha)
+{
+ m_state->m_alpha = alpha;
+}
+
+void PlatformContextSkia::setLineCap(SkPaint::Cap lc)
+{
+ m_state->m_lineCap = lc;
+}
+
+void PlatformContextSkia::setLineJoin(SkPaint::Join lj)
+{
+ m_state->m_lineJoin = lj;
+}
+
+void PlatformContextSkia::setXfermodeMode(SkXfermode::Mode pdm)
+{
+ m_state->m_xferMode = pdm;
+}
+
+void PlatformContextSkia::setFillColor(SkColor color)
+{
+ m_state->m_fillColor = color;
+ setFillShader(0);
+}
+
+SkDrawLooper* PlatformContextSkia::getDrawLooper() const
+{
+ return m_state->m_looper;
+}
+
+StrokeStyle PlatformContextSkia::getStrokeStyle() const
+{
+ return m_state->m_strokeStyle;
+}
+
+void PlatformContextSkia::setStrokeStyle(StrokeStyle strokeStyle)
+{
+ m_state->m_strokeStyle = strokeStyle;
+}
+
+void PlatformContextSkia::setStrokeColor(SkColor strokeColor)
+{
+ m_state->m_strokeColor = strokeColor;
+ setStrokeShader(0);
+}
+
+float PlatformContextSkia::getStrokeThickness() const
+{
+ return m_state->m_strokeThickness;
+}
+
+void PlatformContextSkia::setStrokeThickness(float thickness)
+{
+ m_state->m_strokeThickness = thickness;
+}
+
+void PlatformContextSkia::setStrokeShader(SkShader* strokeShader)
+{
+ if (strokeShader)
+ m_state->m_strokeColor = Color::black;
+
+ if (strokeShader != m_state->m_strokeShader) {
+ SkSafeUnref(m_state->m_strokeShader);
+ m_state->m_strokeShader = strokeShader;
+ SkSafeRef(m_state->m_strokeShader);
+ }
+}
+
+TextDrawingModeFlags PlatformContextSkia::getTextDrawingMode() const
+{
+ return m_state->m_textDrawingMode;
+}
+
+float PlatformContextSkia::getAlpha() const
+{
+ return m_state->m_alpha;
+}
+
+int PlatformContextSkia::getNormalizedAlpha() const
+{
+ int alpha = roundf(m_state->m_alpha * 256);
+ if (alpha > 255)
+ alpha = 255;
+ else if (alpha < 0)
+ alpha = 0;
+ return alpha;
+}
+
+void PlatformContextSkia::setTextDrawingMode(TextDrawingModeFlags mode)
+{
+ // TextModeClip is never used, so we assert that it isn't set:
+ // https://bugs.webkit.org/show_bug.cgi?id=21898
+ ASSERT(!(mode & TextModeClip));
+ m_state->m_textDrawingMode = mode;
+}
+
+void PlatformContextSkia::setUseAntialiasing(bool enable)
+{
+ m_state->m_useAntialiasing = enable;
+}
+
+SkColor PlatformContextSkia::effectiveFillColor() const
+{
+ return m_state->applyAlpha(m_state->m_fillColor);
+}
+
+SkColor PlatformContextSkia::effectiveStrokeColor() const
+{
+ return m_state->applyAlpha(m_state->m_strokeColor);
+}
+
+void PlatformContextSkia::beginPath()
+{
+ m_path.reset();
+}
+
+void PlatformContextSkia::addPath(const SkPath& path)
+{
+ m_path.addPath(path, m_canvas->getTotalMatrix());
+}
+
+SkPath PlatformContextSkia::currentPathInLocalCoordinates() const
+{
+ SkPath localPath = m_path;
+ const SkMatrix& matrix = m_canvas->getTotalMatrix();
+ SkMatrix inverseMatrix;
+ if (!matrix.invert(&inverseMatrix))
+ return SkPath();
+ localPath.transform(inverseMatrix);
+ return localPath;
+}
+
+void PlatformContextSkia::canvasClipPath(const SkPath& path)
+{
+ m_state->m_canvasClipApplied = true;
+ m_canvas->clipPath(path);
+}
+
+void PlatformContextSkia::setFillRule(SkPath::FillType fr)
+{
+ m_path.setFillType(fr);
+}
+
+void PlatformContextSkia::setFillShader(SkShader* fillShader)
+{
+ if (fillShader)
+ m_state->m_fillColor = Color::black;
+
+ if (fillShader != m_state->m_fillShader) {
+ SkSafeUnref(m_state->m_fillShader);
+ m_state->m_fillShader = fillShader;
+ SkSafeRef(m_state->m_fillShader);
+ }
+}
+
+InterpolationQuality PlatformContextSkia::interpolationQuality() const
+{
+ return m_state->m_interpolationQuality;
+}
+
+void PlatformContextSkia::setInterpolationQuality(InterpolationQuality interpolationQuality)
+{
+ m_state->m_interpolationQuality = interpolationQuality;
+}
+
+void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash)
+{
+ if (dash != m_state->m_dash) {
+ SkSafeUnref(m_state->m_dash);
+ m_state->m_dash = dash;
+ }
+}
+
+void PlatformContextSkia::paintSkPaint(const SkRect& rect,
+ const SkPaint& paint)
+{
+ m_canvas->drawRect(rect, paint);
+}
+
+const SkBitmap* PlatformContextSkia::bitmap() const
+{
+ return &m_canvas->getDevice()->accessBitmap(false);
+}
+
+bool PlatformContextSkia::isPrinting()
+{
+ return m_canvas->getTopPlatformDevice().IsVectorial();
+}
+
+void PlatformContextSkia::getImageResamplingHint(IntSize* srcSize, FloatSize* dstSize) const
+{
+ *srcSize = m_imageResamplingHintSrcSize;
+ *dstSize = m_imageResamplingHintDstSize;
+}
+
+void PlatformContextSkia::setImageResamplingHint(const IntSize& srcSize, const FloatSize& dstSize)
+{
+ m_imageResamplingHintSrcSize = srcSize;
+ m_imageResamplingHintDstSize = dstSize;
+}
+
+void PlatformContextSkia::clearImageResamplingHint()
+{
+ m_imageResamplingHintSrcSize = IntSize();
+ m_imageResamplingHintDstSize = FloatSize();
+}
+
+bool PlatformContextSkia::hasImageResamplingHint() const
+{
+ return !m_imageResamplingHintSrcSize.isEmpty() && !m_imageResamplingHintDstSize.isEmpty();
+}
+
+void PlatformContextSkia::applyClipFromImage(const FloatRect& rect, const SkBitmap& imageBuffer)
+{
+ // NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we
+ // only look at the alpha when compositing. I'm not 100% sure this is what WebKit expects for image clipping.
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
+ m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint);
+}
+
+void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths)
+{
+ // Anti-aliased clipping:
+ //
+ // Skia's clipping is 1-bit only. Consider what would happen if it were 8-bit:
+ // We have a square canvas, filled with white and we declare a circular
+ // clipping path. Then we fill twice with a black rectangle. The fractional
+ // pixels would first get the correct color (white * alpha + black * (1 -
+ // alpha)), but the second fill would apply the alpha to the already
+ // modified color and the result would be too dark.
+ //
+ // This, anti-aliased clipping needs to be performed after the drawing has
+ // been done. In order to do this, we create a new layer of the canvas in
+ // clipPathAntiAliased and store the clipping path. All drawing is done to
+ // the layer's bitmap while it's in effect. When WebKit calls restore() to
+ // undo the clipping, this function is called.
+ //
+ // Here, we walk the list of clipping paths backwards and, for each, we
+ // clear outside of the clipping path. We only need a single extra layer
+ // for any number of clipping paths.
+ //
+ // When we call restore on the SkCanvas, the layer's bitmap is composed
+ // into the layer below and we end up with correct, anti-aliased clipping.
+
+ m_canvas->restore();
+
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kClear_Mode);
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kFill_Style);
+
+ for (size_t i = paths.size() - 1; i < paths.size(); --i) {
+ paths[i].setFillType(SkPath::kInverseWinding_FillType);
+ m_canvas->drawPath(paths[i], paint);
+ }
+
+ m_canvas->restore();
+}
+
+bool PlatformContextSkia::canAccelerate() const
+{
+ return !m_state->m_fillShader // Can't accelerate with a fill gradient or pattern.
+ && !m_state->m_looper // Can't accelerate with a shadow.
+ && !m_state->m_canvasClipApplied; // Can't accelerate with a clip to path applied.
+}
+
+bool PlatformContextSkia::canvasClipApplied() const
+{
+ return m_state->m_canvasClipApplied;
+}
+
+class WillPublishCallbackImpl : public DrawingBuffer::WillPublishCallback {
+public:
+ static PassOwnPtr<WillPublishCallback> create(PlatformContextSkia* pcs)
+ {
+ return adoptPtr(new WillPublishCallbackImpl(pcs));
+ }
+
+ virtual void willPublish()
+ {
+ m_pcs->prepareForHardwareDraw();
+ }
+
+private:
+ explicit WillPublishCallbackImpl(PlatformContextSkia* pcs)
+ : m_pcs(pcs)
+ {
+ }
+
+ PlatformContextSkia* m_pcs;
+};
+
+void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* context, DrawingBuffer* drawingBuffer, const WebCore::IntSize& size)
+{
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ if (context && drawingBuffer) {
+ m_useGPU = true;
+ m_gpuCanvas = new GLES2Canvas(context, drawingBuffer, size);
+ m_uploadTexture.clear();
+ drawingBuffer->setWillPublishCallback(WillPublishCallbackImpl::create(this));
+ } else {
+ syncSoftwareCanvas();
+ m_uploadTexture.clear();
+ m_gpuCanvas.clear();
+ m_useGPU = false;
+ }
+#endif
+}
+
+void PlatformContextSkia::prepareForSoftwareDraw() const
+{
+ if (!m_useGPU)
+ return;
+
+ if (m_backingStoreState == Hardware) {
+ // Depending on the blend mode we need to do one of a few things:
+
+ // * For associative blend modes, we can draw into an initially empty
+ // canvas and then composite the results on top of the hardware drawn
+ // results before the next hardware draw or swapBuffers().
+
+ // * For non-associative blend modes we have to do a readback and then
+ // software draw. When we re-upload in this mode we have to blow
+ // away whatever is in the hardware backing store (do a copy instead
+ // of a compositing operation).
+
+ if (m_state->m_xferMode == SkXfermode::kSrcOver_Mode) {
+ // Note that we have rendering results in both the hardware and software backing stores.
+ m_backingStoreState = Mixed;
+ } else {
+ readbackHardwareToSoftware();
+ // When we switch back to hardware copy the results, don't composite.
+ m_backingStoreState = Software;
+ }
+ } else if (m_backingStoreState == Mixed) {
+ if (m_state->m_xferMode != SkXfermode::kSrcOver_Mode) {
+ // Have to composite our currently software drawn data...
+ uploadSoftwareToHardware(CompositeSourceOver);
+ // then do a readback so we can hardware draw stuff.
+ readbackHardwareToSoftware();
+ m_backingStoreState = Software;
+ }
+ } else if (m_backingStoreState == None) {
+ m_backingStoreState = Software;
+ }
+}
+
+void PlatformContextSkia::prepareForHardwareDraw() const
+{
+ if (!m_useGPU)
+ return;
+
+ if (m_backingStoreState == Software) {
+ // Last drawn in software; upload everything we've drawn.
+ uploadSoftwareToHardware(CompositeCopy);
+ } else if (m_backingStoreState == Mixed) {
+ // Stuff in software/hardware, composite the software stuff on top of
+ // the hardware stuff.
+ uploadSoftwareToHardware(CompositeSourceOver);
+ }
+ m_backingStoreState = Hardware;
+}
+
+void PlatformContextSkia::syncSoftwareCanvas() const
+{
+ if (!m_useGPU)
+ return;
+
+ if (m_backingStoreState == Hardware)
+ readbackHardwareToSoftware();
+ else if (m_backingStoreState == Mixed) {
+ // Have to composite our currently software drawn data..
+ uploadSoftwareToHardware(CompositeSourceOver);
+ // then do a readback.
+ readbackHardwareToSoftware();
+ m_backingStoreState = Software;
+ }
+ m_backingStoreState = Software;
+}
+
+void PlatformContextSkia::markDirtyRect(const IntRect& rect)
+{
+ if (!m_useGPU)
+ return;
+
+ switch (m_backingStoreState) {
+ case Software:
+ case Mixed:
+ m_softwareDirtyRect.unite(rect);
+ return;
+ case Hardware:
+ return;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void PlatformContextSkia::uploadSoftwareToHardware(CompositeOperator op) const
+{
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(false);
+ SkAutoLockPixels lock(bitmap);
+ SharedGraphicsContext3D* context = m_gpuCanvas->context();
+ if (!m_uploadTexture || m_uploadTexture->tiles().totalSizeX() < bitmap.width() || m_uploadTexture->tiles().totalSizeY() < bitmap.height())
+ m_uploadTexture = context->createTexture(Texture::BGRA8, bitmap.width(), bitmap.height());
+
+ m_uploadTexture->updateSubRect(bitmap.getPixels(), m_softwareDirtyRect);
+ AffineTransform identity;
+ gpuCanvas()->drawTexturedRect(m_uploadTexture.get(), m_softwareDirtyRect, m_softwareDirtyRect, identity, 1.0, ColorSpaceDeviceRGB, op);
+ // Clear out the region of the software canvas we just uploaded.
+ m_canvas->save();
+ m_canvas->resetMatrix();
+ SkRect bounds = m_softwareDirtyRect;
+ m_canvas->clipRect(bounds, SkRegion::kReplace_Op);
+ m_canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
+ m_canvas->restore();
+ m_softwareDirtyRect.setWidth(0); // Clear dirty rect.
+#endif
+}
+
+void PlatformContextSkia::readbackHardwareToSoftware() const
+{
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(true);
+ SkAutoLockPixels lock(bitmap);
+ int width = bitmap.width(), height = bitmap.height();
+ OwnArrayPtr<uint32_t> buf(new uint32_t[width]);
+ SharedGraphicsContext3D* context = m_gpuCanvas->context();
+ m_gpuCanvas->bindFramebuffer();
+ // Flips the image vertically.
+ for (int y = 0; y < height; ++y) {
+ uint32_t* pixels = bitmap.getAddr32(0, y);
+ if (context->supportsBGRA())
+ context->readPixels(0, height - 1 - y, width, 1, Extensions3D::BGRA_EXT, GraphicsContext3D::UNSIGNED_BYTE, pixels);
+ else {
+ context->readPixels(0, height - 1 - y, width, 1, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels);
+ for (int i = 0; i < width; ++i) {
+ uint32_t pixel = pixels[i];
+ // Swizzles from RGBA -> BGRA.
+ pixels[i] = (pixel & 0xFF00FF00) | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16);
+ }
+ }
+ }
+ m_softwareDirtyRect.unite(IntRect(0, 0, width, height)); // Mark everything as dirty.
+#endif
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h
new file mode 100644
index 0000000..11b311a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2008, 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 PlatformContextSkia_h
+#define PlatformContextSkia_h
+
+#include "GraphicsContext.h"
+#include "Noncopyable.h"
+
+#include "SkDashPathEffect.h"
+#include "SkDrawLooper.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "skia/ext/platform_canvas.h"
+
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+enum CompositeOperator;
+class DrawingBuffer;
+class GLES2Canvas;
+class GraphicsContext3D;
+class Texture;
+
+// This class holds the platform-specific state for GraphicsContext. We put
+// most of our Skia wrappers on this class. In theory, a lot of this stuff could
+// be moved to GraphicsContext directly, except that some code external to this
+// would like to poke at our graphics layer as well (like the Image and Font
+// stuff, which needs some amount of our wrappers and state around SkCanvas).
+//
+// So in general, this class uses just Skia types except when there's no easy
+// conversion. GraphicsContext is responsible for converting the WebKit types to
+// Skia types and setting up the eventual call to the Skia functions.
+//
+// This class then keeps track of all the current Skia state. WebKit expects
+// that the graphics state that is pushed and popped by save() and restore()
+// includes things like colors and pen styles. Skia does this differently, where
+// push and pop only includes transforms and bitmaps, and the application is
+// responsible for managing the painting state which is store in separate
+// SkPaint objects. This class provides the adaptor that allows the painting
+// state to be pushed and popped along with the bitmap.
+class PlatformContextSkia : public Noncopyable {
+public:
+ // For printing, there shouldn't be any canvas. canvas can be NULL. If you
+ // supply a NULL canvas, you can also call setCanvas later.
+ PlatformContextSkia(skia::PlatformCanvas*);
+ ~PlatformContextSkia();
+
+ // Sets the canvas associated with this context. Use when supplying NULL
+ // to the constructor.
+ void setCanvas(skia::PlatformCanvas*);
+
+ // If false we're rendering to a GraphicsContext for a web page, if false
+ // we're not (as is the case when rendering to a canvas object).
+ // If this is true the contents have not been marked up with the magic
+ // color and all text drawing needs to go to a layer so that the alpha is
+ // correctly updated.
+ void setDrawingToImageBuffer(bool);
+ bool isDrawingToImageBuffer() const;
+
+ void save();
+ void restore();
+
+ // Begins a layer that is clipped to the image |imageBuffer| at the location
+ // |rect|. This layer is implicitly restored when the next restore is
+ // invoked.
+ // NOTE: |imageBuffer| may be deleted before the |restore| is invoked.
+ void beginLayerClippedToImage(const FloatRect&, const ImageBuffer*);
+ void clipPathAntiAliased(const SkPath&);
+
+ // Sets up the common flags on a paint for antialiasing, effects, etc.
+ // This is implicitly called by setupPaintFill and setupPaintStroke, but
+ // you may wish to call it directly sometimes if you don't want that other
+ // behavior.
+ void setupPaintCommon(SkPaint*) const;
+
+ // Sets up the paint for the current fill style.
+ void setupPaintForFilling(SkPaint*) const;
+
+ // Sets up the paint for stroking. Returns an int representing the width of
+ // the pen, or 1 if the pen's width is 0 if a non-zero length is provided,
+ // the number of dashes/dots on a dashed/dotted line will be adjusted to
+ // start and end that length with a dash/dot.
+ float setupPaintForStroking(SkPaint*, SkRect*, int length) const;
+
+ // State setting functions.
+ void setDrawLooper(SkDrawLooper*); // Note: takes an additional ref.
+ void setMiterLimit(float);
+ void setAlpha(float);
+ void setLineCap(SkPaint::Cap);
+ void setLineJoin(SkPaint::Join);
+ void setFillRule(SkPath::FillType);
+ void setXfermodeMode(SkXfermode::Mode);
+ void setFillColor(SkColor);
+ void setFillShader(SkShader*);
+ void setStrokeStyle(StrokeStyle);
+ void setStrokeColor(SkColor);
+ void setStrokeThickness(float thickness);
+ void setStrokeShader(SkShader*);
+ void setTextDrawingMode(TextDrawingModeFlags mode);
+ void setUseAntialiasing(bool enable);
+ void setDashPathEffect(SkDashPathEffect*);
+
+ SkDrawLooper* getDrawLooper() const;
+ StrokeStyle getStrokeStyle() const;
+ float getStrokeThickness() const;
+ TextDrawingModeFlags getTextDrawingMode() const;
+ float getAlpha() const;
+ int getNormalizedAlpha() const;
+
+ void beginPath();
+ void addPath(const SkPath&);
+ SkPath currentPathInLocalCoordinates() const;
+
+ void canvasClipPath(const SkPath&);
+
+ // Returns the fill color. The returned color has it's alpha adjusted
+ // by the current alpha.
+ SkColor effectiveFillColor() const;
+
+ // Returns the stroke color. The returned color has it's alpha adjusted
+ // by the current alpha.
+ SkColor effectiveStrokeColor() const;
+
+ skia::PlatformCanvas* canvas() { return m_canvas; }
+
+ InterpolationQuality interpolationQuality() const;
+ void setInterpolationQuality(InterpolationQuality interpolationQuality);
+
+ // FIXME: This should be pushed down to GraphicsContext.
+ void drawRect(SkRect rect);
+
+ // FIXME: I'm still unsure how I will serialize this call.
+ void paintSkPaint(const SkRect&, const SkPaint&);
+
+ const SkBitmap* bitmap() const;
+
+ // Returns the canvas used for painting, NOT guaranteed to be non-NULL.
+ //
+ // Warning: This function is deprecated so the users are reminded that they
+ // should use this layer of indirection instead of using the canvas
+ // directly. This is to help with the eventual serialization.
+ skia::PlatformCanvas* canvas() const;
+
+ // Returns if the context is a printing context instead of a display
+ // context. Bitmap shouldn't be resampled when printing to keep the best
+ // possible quality.
+ bool isPrinting();
+
+ void getImageResamplingHint(IntSize* srcSize, FloatSize* dstSize) const;
+ void setImageResamplingHint(const IntSize& srcSize, const FloatSize& dstSize);
+ void clearImageResamplingHint();
+ bool hasImageResamplingHint() const;
+
+ bool canAccelerate() const;
+ bool canvasClipApplied() const;
+ bool useGPU() { return m_useGPU; }
+ void setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&);
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ GLES2Canvas* gpuCanvas() const { return m_gpuCanvas.get(); }
+#else
+ GLES2Canvas* gpuCanvas() const { return 0; }
+#endif
+ // Call these before making a call that manipulates the underlying
+ // skia::PlatformCanvas or WebCore::GLES2Canvas
+ void prepareForSoftwareDraw() const;
+ void prepareForHardwareDraw() const;
+ // Call to force the skia::PlatformCanvas to contain all rendering results.
+ void syncSoftwareCanvas() const;
+ void markDirtyRect(const IntRect& rect);
+
+private:
+ // Used when restoring and the state has an image clip. Only shows the pixels in
+ // m_canvas that are also in imageBuffer.
+ void applyClipFromImage(const FloatRect&, const SkBitmap&);
+ void applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths);
+
+ void uploadSoftwareToHardware(CompositeOperator) const;
+ void readbackHardwareToSoftware() const;
+
+ // Defines drawing style.
+ struct State;
+
+ // NULL indicates painting is disabled. Never delete this object.
+ skia::PlatformCanvas* m_canvas;
+
+ // States stack. Enables local drawing state change with save()/restore()
+ // calls.
+ WTF::Vector<State> m_stateStack;
+ // Pointer to the current drawing state. This is a cached value of
+ // mStateStack.back().
+ State* m_state;
+
+ // Current path in global coordinates.
+ SkPath m_path;
+
+ // Stores image sizes for a hint to compute image resampling modes.
+ // Values are used in ImageSkia.cpp
+ IntSize m_imageResamplingHintSrcSize;
+ FloatSize m_imageResamplingHintDstSize;
+ bool m_drawingToImageBuffer;
+ bool m_useGPU;
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ OwnPtr<GLES2Canvas> m_gpuCanvas;
+ mutable RefPtr<Texture> m_uploadTexture;
+#endif
+ mutable enum { None, Software, Mixed, Hardware } m_backingStoreState;
+ mutable IntRect m_softwareDirtyRect;
+};
+
+}
+#endif // PlatformContextSkia_h
diff --git a/Source/WebCore/platform/graphics/skia/PlatformGraphics.h b/Source/WebCore/platform/graphics/skia/PlatformGraphics.h
new file mode 100644
index 0000000..4ae8835
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/PlatformGraphics.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2008, 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 PlatformGraphics_h
+#define PlatformGraphics_h
+
+typedef class SkShader* PlatformGradient;
+typedef class SkShader* PlatformPattern;
+
+#endif // PlatformGraphics_h
diff --git a/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp
new file mode 100644
index 0000000..5046c50
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2008, 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.
+ */
+
+#include "config.h"
+#include "SkiaFontWin.h"
+
+#include "AffineTransform.h"
+#include "PlatformContextSkia.h"
+#include "Gradient.h"
+#include "Pattern.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkShader.h"
+
+#include <wtf/ListHashSet.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+struct CachedOutlineKey {
+ CachedOutlineKey() : font(0), glyph(0), path(0) {}
+ CachedOutlineKey(HFONT f, WORD g) : font(f), glyph(g), path(0) {}
+
+ HFONT font;
+ WORD glyph;
+
+ // The lifetime of this pointer is managed externally to this class. Be sure
+ // to call DeleteOutline to remove items.
+ SkPath* path;
+};
+
+const bool operator==(const CachedOutlineKey& a, const CachedOutlineKey& b)
+{
+ return a.font == b.font && a.glyph == b.glyph;
+}
+
+struct CachedOutlineKeyHash {
+ static unsigned hash(const CachedOutlineKey& key)
+ {
+ unsigned keyBytes;
+ memcpy(&keyBytes, &key.font, sizeof(unsigned));
+ return keyBytes + key.glyph;
+ }
+
+ static unsigned equal(const CachedOutlineKey& a, const CachedOutlineKey& b)
+ {
+ return a.font == b.font && a.glyph == b.glyph;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+// The global number of glyph outlines we'll cache.
+static const int outlineCacheSize = 256;
+
+typedef ListHashSet<CachedOutlineKey, outlineCacheSize+1, CachedOutlineKeyHash> OutlineCache;
+
+// FIXME: Convert from static constructor to accessor function. WebCore tries to
+// avoid global constructors to save on start-up time.
+static OutlineCache outlineCache;
+
+static SkScalar FIXEDToSkScalar(FIXED fixed)
+{
+ SkFixed skFixed;
+ memcpy(&skFixed, &fixed, sizeof(SkFixed));
+ return SkFixedToScalar(skFixed);
+}
+
+// Removes the given key from the cached outlines, also deleting the path.
+static void deleteOutline(OutlineCache::iterator deleteMe)
+{
+ delete deleteMe->path;
+ outlineCache.remove(deleteMe);
+}
+
+static void addPolyCurveToPath(const TTPOLYCURVE* polyCurve, SkPath* path)
+{
+ switch (polyCurve->wType) {
+ case TT_PRIM_LINE:
+ for (WORD i = 0; i < polyCurve->cpfx; i++) {
+ path->lineTo(FIXEDToSkScalar(polyCurve->apfx[i].x), -FIXEDToSkScalar(polyCurve->apfx[i].y));
+ }
+ break;
+
+ case TT_PRIM_QSPLINE:
+ // FIXME: doesn't this duplicate points if we do the loop > once?
+ for (WORD i = 0; i < polyCurve->cpfx - 1; i++) {
+ SkScalar bx = FIXEDToSkScalar(polyCurve->apfx[i].x);
+ SkScalar by = FIXEDToSkScalar(polyCurve->apfx[i].y);
+
+ SkScalar cx = FIXEDToSkScalar(polyCurve->apfx[i + 1].x);
+ SkScalar cy = FIXEDToSkScalar(polyCurve->apfx[i + 1].y);
+ if (i < polyCurve->cpfx - 2) {
+ // We're not the last point, compute C.
+ cx = SkScalarAve(bx, cx);
+ cy = SkScalarAve(by, cy);
+ }
+
+ // Need to flip the y coordinates since the font's coordinate system is
+ // flipped from ours vertically.
+ path->quadTo(bx, -by, cx, -cy);
+ }
+ break;
+
+ case TT_PRIM_CSPLINE:
+ // FIXME
+ break;
+ }
+}
+
+// The size of the glyph path buffer.
+static const int glyphPathBufferSize = 4096;
+
+// Fills the given SkPath with the outline for the given glyph index. The font
+// currently selected into the given DC is used. Returns true on success.
+static bool getPathForGlyph(HDC dc, WORD glyph, SkPath* path)
+{
+ char buffer[glyphPathBufferSize];
+ GLYPHMETRICS gm;
+ MAT2 mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; // Each one is (fract,value).
+
+ DWORD totalSize = GetGlyphOutlineW(dc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE,
+ &gm, glyphPathBufferSize, buffer, &mat);
+ if (totalSize == GDI_ERROR)
+ return false;
+
+ const char* curGlyph = buffer;
+ const char* endGlyph = &buffer[totalSize];
+ while (curGlyph < endGlyph) {
+ const TTPOLYGONHEADER* polyHeader =
+ reinterpret_cast<const TTPOLYGONHEADER*>(curGlyph);
+ path->moveTo(FIXEDToSkScalar(polyHeader->pfxStart.x),
+ -FIXEDToSkScalar(polyHeader->pfxStart.y));
+
+ const char* curPoly = curGlyph + sizeof(TTPOLYGONHEADER);
+ const char* endPoly = curGlyph + polyHeader->cb;
+ while (curPoly < endPoly) {
+ const TTPOLYCURVE* polyCurve =
+ reinterpret_cast<const TTPOLYCURVE*>(curPoly);
+ addPolyCurveToPath(polyCurve, path);
+ curPoly += sizeof(WORD) * 2 + sizeof(POINTFX) * polyCurve->cpfx;
+ }
+ path->close();
+ curGlyph += polyHeader->cb;
+ }
+
+ return true;
+}
+
+// Returns a SkPath corresponding to the give glyph in the given font. The font
+// should be selected into the given DC. The returned path is owned by the
+// hashtable. Returns 0 on error.
+const SkPath* SkiaWinOutlineCache::lookupOrCreatePathForGlyph(HDC hdc, HFONT font, WORD glyph)
+{
+ CachedOutlineKey key(font, glyph);
+ OutlineCache::iterator found = outlineCache.find(key);
+ if (found != outlineCache.end()) {
+ // Keep in MRU order by removing & reinserting the value.
+ key = *found;
+ outlineCache.remove(found);
+ outlineCache.add(key);
+ return key.path;
+ }
+
+ key.path = new SkPath;
+ if (!getPathForGlyph(hdc, glyph, key.path))
+ return 0;
+
+ if (outlineCache.size() > outlineCacheSize)
+ // The cache is too big, find the oldest value (first in the list).
+ deleteOutline(outlineCache.begin());
+
+ outlineCache.add(key);
+ return key.path;
+}
+
+
+void SkiaWinOutlineCache::removePathsForFont(HFONT hfont)
+{
+ // ListHashSet isn't the greatest structure for deleting stuff out of, but
+ // removing entries will be relatively rare (we don't remove fonts much, nor
+ // do we draw out own glyphs using these routines much either).
+ //
+ // We keep a list of all glyphs we're removing which we do in a separate
+ // pass.
+ Vector<CachedOutlineKey> outlinesToDelete;
+ for (OutlineCache::iterator i = outlineCache.begin();
+ i != outlineCache.end(); ++i)
+ outlinesToDelete.append(*i);
+
+ for (Vector<CachedOutlineKey>::iterator i = outlinesToDelete.begin();
+ i != outlinesToDelete.end(); ++i)
+ deleteOutline(outlineCache.find(*i));
+}
+
+bool windowsCanHandleDrawTextShadow(GraphicsContext *context)
+{
+ FloatSize shadowOffset;
+ float shadowBlur;
+ Color shadowColor;
+ ColorSpace shadowColorSpace;
+
+ bool hasShadow = context->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
+ return (hasShadow && (shadowBlur == 0) && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255));
+}
+
+bool windowsCanHandleTextDrawing(GraphicsContext* context)
+{
+ // Check for non-translation transforms. Sometimes zooms will look better in
+ // Skia, and sometimes better in Windows. The main problem is that zooming
+ // in using Skia will show you the hinted outlines for the smaller size,
+ // which look weird. All else being equal, it's better to use Windows' text
+ // drawing, so we don't check for zooms.
+ const AffineTransform& matrix = context->getCTM();
+ if (matrix.b() != 0 || matrix.c() != 0) // Check for skew.
+ return false;
+
+ // Check for stroke effects.
+ if (context->platformContext()->getTextDrawingMode() != TextModeFill)
+ return false;
+
+ // Check for gradients.
+ if (context->fillGradient() || context->strokeGradient())
+ return false;
+
+ // Check for patterns.
+ if (context->fillPattern() || context->strokePattern())
+ return false;
+
+ // Check for shadow effects.
+ if (context->platformContext()->getDrawLooper() && (!windowsCanHandleDrawTextShadow(context)))
+ return false;
+
+ return true;
+}
+
+// Draws the given text string using skia. Note that gradient or
+// pattern may be NULL, in which case a solid colour is used.
+static bool skiaDrawText(HFONT hfont,
+ HDC dc,
+ SkCanvas* canvas,
+ const SkPoint& point,
+ SkPaint* paint,
+ const WORD* glyphs,
+ const int* advances,
+ const GOFFSET* offsets,
+ int numGlyphs)
+{
+ float x = point.fX, y = point.fY;
+
+ for (int i = 0; i < numGlyphs; i++) {
+ const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]);
+ if (!path)
+ return false;
+
+ float offsetX = 0.0f, offsetY = 0.0f;
+ if (offsets && (offsets[i].du != 0 || offsets[i].dv != 0)) {
+ offsetX = offsets[i].du;
+ offsetY = offsets[i].dv;
+ }
+
+ SkPath newPath;
+ newPath.addPath(*path, x + offsetX, y + offsetY);
+ canvas->drawPath(newPath, *paint);
+
+ x += advances[i];
+ }
+
+ return true;
+}
+
+bool paintSkiaText(GraphicsContext* context,
+ HFONT hfont,
+ int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ const GOFFSET* offsets,
+ const SkPoint* origin)
+{
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, hfont);
+
+ PlatformContextSkia* platformContext = context->platformContext();
+ TextDrawingModeFlags textMode = platformContext->getTextDrawingMode();
+
+ // Filling (if necessary). This is the common case.
+ SkPaint paint;
+ platformContext->setupPaintForFilling(&paint);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ bool didFill = false;
+
+ if ((textMode & TextModeFill) && SkColorGetA(paint.getColor())) {
+ if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,
+ &glyphs[0], &advances[0], &offsets[0], numGlyphs))
+ return false;
+ didFill = true;
+ }
+
+ // Stroking on top (if necessary).
+ if ((textMode & TextModeStroke)
+ && platformContext->getStrokeStyle() != NoStroke
+ && platformContext->getStrokeThickness() > 0) {
+
+ paint.reset();
+ platformContext->setupPaintForStroking(&paint, 0, 0);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ if (didFill) {
+ // If there is a shadow and we filled above, there will already be
+ // a shadow. We don't want to draw it again or it will be too dark
+ // and it will go on top of the fill.
+ //
+ // Note that this isn't strictly correct, since the stroke could be
+ // very thick and the shadow wouldn't account for this. The "right"
+ // thing would be to draw to a new layer and then draw that layer
+ // with a shadow. But this is a lot of extra work for something
+ // that isn't normally an issue.
+ SkSafeUnref(paint.setLooper(0));
+ }
+
+ if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,
+ &glyphs[0], &advances[0], &offsets[0], numGlyphs))
+ return false;
+ }
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ return true;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/SkiaFontWin.h b/Source/WebCore/platform/graphics/skia/SkiaFontWin.h
new file mode 100644
index 0000000..40bee62
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/SkiaFontWin.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2008, 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 SkiaFontWin_h
+#define SkiaFontWin_h
+
+#include <windows.h>
+#include <usp10.h>
+
+class SkPath;
+class SkPoint;
+
+namespace WebCore {
+
+class GraphicsContext;
+class PlatformContextSkia;
+
+// FIXME: Rename file to SkiaWinOutlineCache
+class SkiaWinOutlineCache {
+public:
+ static const SkPath* lookupOrCreatePathForGlyph(HDC, HFONT, WORD);
+ // Removes any cached glyphs from the outline cache corresponding to the
+ // given font handle.
+ static void removePathsForFont(HFONT);
+
+private:
+ SkiaWinOutlineCache();
+};
+
+// The functions below are used for more complex font drawing (effects such as
+// stroking and more complex transforms) than Windows supports directly. Since
+// Windows drawing is faster you should use windowsCanHandleTextDrawing first to
+// check if using Skia is required at all.
+// Note that the text will look different (no ClearType) so this should only be
+// used when necessary.
+//
+// When you call a Skia* text drawing function, various glyph outlines will be
+// cached. As a result, you should call SkiaWinOutlineCache::removePathsForFont
+// when the font is destroyed so that the cache does not outlive the font (since
+// the HFONTs are recycled).
+//
+// Remember that Skia's text drawing origin is the baseline, like WebKit, not
+// the top, like Windows.
+
+// Returns true if the fillColor and shadowColor are opaque and the text-shadow
+// is not blurred.
+bool windowsCanHandleDrawTextShadow(GraphicsContext*);
+
+// Returns true if advanced font rendering is recommended.
+bool windowsCanHandleTextDrawing(GraphicsContext*);
+
+// Note that the offsets parameter is optional. If not NULL it represents a
+// per glyph offset (such as returned by ScriptPlace Windows API function).
+//
+// Returns true of the text was drawn successfully. False indicates an error
+// from Windows.
+bool paintSkiaText(GraphicsContext* graphicsContext,
+ HFONT hfont,
+ int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ const GOFFSET* offsets,
+ const SkPoint* origin);
+
+} // namespace WebCore
+
+#endif // SkiaFontWin_h
diff --git a/Source/WebCore/platform/graphics/skia/SkiaUtils.cpp b/Source/WebCore/platform/graphics/skia/SkiaUtils.cpp
new file mode 100644
index 0000000..da83793
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/SkiaUtils.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2006,2007,2008, 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.
+ */
+
+#include "config.h"
+
+#include "SkiaUtils.h"
+
+#include "ImageBuffer.h"
+#include "SharedBuffer.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkMatrix.h"
+#include "SkRegion.h"
+#include "SkUnPreMultiply.h"
+
+namespace WebCore {
+
+#if PLATFORM(ANDROID)
+static const struct CompositOpToSkiaMode {
+ uint8_t mCompositOp;
+ uint8_t mMode;
+} gMapCompositOpsToSkiaModes[] = {
+ { CompositeClear, SkXfermode::kClear_Mode },
+ { CompositeCopy, SkXfermode::kSrc_Mode },
+ { CompositeSourceOver, SkXfermode::kSrcOver_Mode },
+ { CompositeSourceIn, SkXfermode::kSrcIn_Mode },
+ { CompositeSourceOut, SkXfermode::kSrcOut_Mode },
+ { CompositeSourceAtop, SkXfermode::kSrcATop_Mode },
+ { CompositeDestinationOver, SkXfermode::kDstOver_Mode },
+ { CompositeDestinationIn, SkXfermode::kDstIn_Mode },
+ { CompositeDestinationOut, SkXfermode::kDstOut_Mode },
+ { CompositeDestinationAtop, SkXfermode::kDstATop_Mode },
+ { CompositeXOR, SkXfermode::kXor_Mode },
+ // need more details on the composite modes to be sure these are right
+ { CompositePlusDarker, SkXfermode::kDarken_Mode },
+ { CompositeHighlight, SkXfermode::kSrcOver_Mode }, // TODO
+ { CompositePlusLighter, SkXfermode::kPlus_Mode }
+};
+
+SkXfermode::Mode WebCoreCompositeToSkiaCOmposite(CompositeOperator op)
+{
+ const CompositOpToSkiaMode* table = gMapCompositOpsToSkiaModes;
+
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToSkiaModes); i++) {
+ if (table[i].mCompositOp == op)
+ return (SkXfermode::Mode)table[i].mMode;
+ }
+
+ SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositeOperator %d\n", op));
+ return SkXfermode::kSrcOver_Mode; // fall-back
+}
+
+#endif
+
+static const struct CompositOpToXfermodeMode {
+ uint8_t mCompositOp;
+ uint8_t m_xfermodeMode;
+} gMapCompositOpsToXfermodeModes[] = {
+ { CompositeClear, SkXfermode::kClear_Mode },
+ { CompositeCopy, SkXfermode::kSrc_Mode },
+ { CompositeSourceOver, SkXfermode::kSrcOver_Mode },
+ { CompositeSourceIn, SkXfermode::kSrcIn_Mode },
+ { CompositeSourceOut, SkXfermode::kSrcOut_Mode },
+ { CompositeSourceAtop, SkXfermode::kSrcATop_Mode },
+ { CompositeDestinationOver, SkXfermode::kDstOver_Mode },
+ { CompositeDestinationIn, SkXfermode::kDstIn_Mode },
+ { CompositeDestinationOut, SkXfermode::kDstOut_Mode },
+ { CompositeDestinationAtop, SkXfermode::kDstATop_Mode },
+ { CompositeXOR, SkXfermode::kXor_Mode },
+ { CompositePlusDarker, SkXfermode::kDarken_Mode },
+ { CompositeHighlight, SkXfermode::kSrcOver_Mode }, // TODO
+ { CompositePlusLighter, SkXfermode::kPlus_Mode }
+};
+
+SkXfermode::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op)
+{
+ const CompositOpToXfermodeMode* table = gMapCompositOpsToXfermodeModes;
+
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToXfermodeModes); i++) {
+ if (table[i].mCompositOp == op)
+ return (SkXfermode::Mode)table[i].m_xfermodeMode;
+ }
+
+ SkDEBUGF(("GraphicsContext::setPlatformCompositeOperation unknown CompositeOperator %d\n", op));
+ return SkXfermode::kSrcOver_Mode; // fall-back
+}
+
+#if PLATFORM(ANDROID)
+Color SkPMColorToWebCoreColor(SkPMColor pm)
+{
+ SkColor c = SkUnPreMultiply::PMColorToColor(pm);
+ // need the cast to find the right constructor
+ return WebCore::Color((int)SkColorGetR(c), (int)SkColorGetG(c),
+ (int)SkColorGetB(c), (int)SkColorGetA(c));
+}
+#else
+static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
+{
+ SkASSERT(component == (uint8_t)component);
+ return (component * scale + 0x8000) >> 16;
+}
+
+SkColor SkPMColorToColor(SkPMColor pm)
+{
+ if (!pm)
+ return 0;
+ unsigned a = SkGetPackedA32(pm);
+ if (!a) {
+ // A zero alpha value when there are non-zero R, G, or B channels is an
+ // invalid premultiplied color (since all channels should have been
+ // multiplied by 0 if a=0).
+ SkASSERT(false);
+ // In production, return 0 to protect against division by zero.
+ return 0;
+ }
+
+ uint32_t scale = (255 << 16) / a;
+
+ return SkColorSetARGB(a,
+ InvScaleByte(SkGetPackedR32(pm), scale),
+ InvScaleByte(SkGetPackedG32(pm), scale),
+ InvScaleByte(SkGetPackedB32(pm), scale));
+}
+
+Color SkPMColorToWebCoreColor(SkPMColor pm)
+{
+ return SkPMColorToColor(pm);
+}
+#endif
+
+void IntersectRectAndRegion(const SkRegion& region, const SkRect& srcRect, SkRect* destRect) {
+ // The cliperator requires an int rect, so we round out.
+ SkIRect srcRectRounded;
+ srcRect.roundOut(&srcRectRounded);
+
+ // The Cliperator will iterate over a bunch of rects where our transformed
+ // rect and the clipping region (which may be non-square) overlap.
+ SkRegion::Cliperator cliperator(region, srcRectRounded);
+ if (cliperator.done()) {
+ destRect->setEmpty();
+ return;
+ }
+
+ // Get the union of all visible rects in the clip that overlap our bitmap.
+ SkIRect currentVisibleRect = cliperator.rect();
+ cliperator.next();
+ while (!cliperator.done()) {
+ currentVisibleRect.join(cliperator.rect());
+ cliperator.next();
+ }
+
+ destRect->set(currentVisibleRect);
+}
+
+void ClipRectToCanvas(const SkCanvas& canvas, const SkRect& srcRect, SkRect* destRect) {
+ // Translate into the canvas' coordinate space. This is where the clipping
+ // region applies.
+ SkRect transformedSrc;
+ canvas.getTotalMatrix().mapRect(&transformedSrc, srcRect);
+
+ // Do the intersection.
+ SkRect transformedDest;
+ IntersectRectAndRegion(canvas.getTotalClip(), transformedSrc, &transformedDest);
+
+ // Now transform it back into world space.
+ SkMatrix inverseTransform;
+ canvas.getTotalMatrix().invert(&inverseTransform);
+ inverseTransform.mapRect(destRect, transformedDest);
+}
+
+bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft)
+{
+ SkRegion rgn;
+ SkRegion clip;
+
+ SkPath::FillType originalFillType = originalPath->getFillType();
+
+ const SkPath* path = originalPath;
+ SkPath scaledPath;
+ int scale = 1;
+
+ SkRect bounds = originalPath->getBounds();
+
+ // We can immediately return false if the point is outside the bounding
+ // rect. We don't use bounds.contains() here, since it would exclude
+ // points on the right and bottom edges of the bounding rect, and we want
+ // to include them.
+ SkScalar fX = SkFloatToScalar(point.x());
+ SkScalar fY = SkFloatToScalar(point.y());
+ if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom)
+ return false;
+
+ originalPath->setFillType(ft);
+
+ // Skia has trouble with coordinates close to the max signed 16-bit values
+ // If we have those, we need to scale.
+ //
+ // TODO: remove this code once Skia is patched to work properly with large
+ // values
+ const SkScalar kMaxCoordinate = SkIntToScalar(1<<15);
+ SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop);
+
+ if (biggestCoord > kMaxCoordinate) {
+ scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate));
+
+ SkMatrix m;
+ m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale)));
+ originalPath->transform(m, &scaledPath);
+ path = &scaledPath;
+ }
+
+ int x = static_cast<int>(floorf(point.x() / scale));
+ int y = static_cast<int>(floorf(point.y() / scale));
+ clip.setRect(x - 1, y - 1, x + 1, y + 1);
+
+ bool contains = rgn.setPath(*path, clip);
+
+ originalPath->setFillType(originalFillType);
+ return contains;
+}
+
+GraphicsContext* scratchContext()
+{
+ static ImageBuffer* scratch = ImageBuffer::create(IntSize(1, 1)).leakPtr();
+ // We don't bother checking for failure creating the ImageBuffer, since our
+ // ImageBuffer initializer won't fail.
+ return scratch->context();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/skia/SkiaUtils.h b/Source/WebCore/platform/graphics/skia/SkiaUtils.h
new file mode 100644
index 0000000..681dcd5
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/SkiaUtils.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2006,2007,2008, 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.
+ */
+
+// All of the functions in this file should move to new homes and this file should be deleted.
+
+#ifndef SkiaUtils_h
+#define SkiaUtils_h
+
+#include <wtf/MathExtras.h>
+#include "GraphicsContext.h"
+#include "SkPath.h"
+#include "SkXfermode.h"
+
+class SkCanvas;
+class SkRegion;
+
+namespace WebCore {
+
+SkXfermode::Mode WebCoreCompositeToSkiaComposite(CompositeOperator);
+
+// move this guy into SkColor.h
+SkColor SkPMColorToColor(SkPMColor);
+
+// This should be an operator on Color
+Color SkPMColorToWebCoreColor(SkPMColor);
+
+// Skia has problems when passed infinite, etc floats, filter them to 0.
+inline SkScalar WebCoreFloatToSkScalar(float f)
+{
+ return SkFloatToScalar(isfinite(f) ? f : 0);
+}
+
+inline SkScalar WebCoreDoubleToSkScalar(double d)
+{
+ return SkDoubleToScalar(isfinite(d) ? d : 0);
+}
+
+// Computes the smallest rectangle that, which when drawn to the given canvas,
+// will cover the same area as the source rectangle. It will clip to the canvas'
+// clip, doing the necessary coordinate transforms.
+//
+// srcRect and destRect can be the same.
+void ClipRectToCanvas(const SkCanvas&, const SkRect& srcRect, SkRect* destRect);
+
+// Determine if a given WebKit point is contained in a path
+bool SkPathContainsPoint(SkPath*, const FloatPoint&, SkPath::FillType);
+
+// Returns a statically allocated 1x1 GraphicsContext intended for temporary
+// operations. Please save() the state and restore() it when you're done with
+// the context.
+GraphicsContext* scratchContext();
+
+} // namespace WebCore
+
+#endif // SkiaUtils_h
diff --git a/Source/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp b/Source/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
new file mode 100644
index 0000000..dc610d7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
@@ -0,0 +1,78 @@
+// Copyright (c) 2008, 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.
+
+#include "config.h"
+#include "AffineTransform.h"
+#include "TransformationMatrix.h"
+
+#include "SkiaUtils.h"
+
+namespace WebCore {
+
+TransformationMatrix::operator SkMatrix() const
+{
+ SkMatrix result;
+
+ result.setScaleX(WebCoreDoubleToSkScalar(a()));
+ result.setSkewX(WebCoreDoubleToSkScalar(c()));
+ result.setTranslateX(WebCoreDoubleToSkScalar(e()));
+
+ result.setScaleY(WebCoreDoubleToSkScalar(d()));
+ result.setSkewY(WebCoreDoubleToSkScalar(b()));
+ result.setTranslateY(WebCoreDoubleToSkScalar(f()));
+
+ // FIXME: Set perspective properly.
+ result.setPerspX(0);
+ result.setPerspY(0);
+ result.set(SkMatrix::kMPersp2, SK_Scalar1);
+
+ return result;
+}
+
+AffineTransform::operator SkMatrix() const
+{
+ SkMatrix result;
+
+ result.setScaleX(WebCoreDoubleToSkScalar(a()));
+ result.setSkewX(WebCoreDoubleToSkScalar(c()));
+ result.setTranslateX(WebCoreDoubleToSkScalar(e()));
+
+ result.setScaleY(WebCoreDoubleToSkScalar(d()));
+ result.setSkewY(WebCoreDoubleToSkScalar(b()));
+ result.setTranslateY(WebCoreDoubleToSkScalar(f()));
+
+ // FIXME: Set perspective properly.
+ result.setPerspX(0);
+ result.setPerspY(0);
+ result.set(SkMatrix::kMPersp2, SK_Scalar1);
+
+ return result;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp
new file mode 100644
index 0000000..4698239
--- /dev/null
+++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp
@@ -0,0 +1,387 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "GraphicsLayerTextureMapper.h"
+
+#include "TextureMapperNode.h"
+
+namespace WebCore {
+
+GraphicsLayerTextureMapper::GraphicsLayerTextureMapper(GraphicsLayerClient* client)
+ : GraphicsLayer(client)
+ , m_node(new TextureMapperNode())
+ , m_changeMask(0)
+{
+}
+
+void GraphicsLayerTextureMapper::notifyChange(TextureMapperNode::ChangeMask changeMask)
+{
+ m_changeMask |= changeMask;
+ if (!client())
+ return;
+ client()->notifySyncRequired(this);
+}
+
+void GraphicsLayerTextureMapper::didSynchronize()
+{
+ m_syncQueued = false;
+ m_changeMask = 0;
+ m_pendingContent.needsDisplay = false;
+ m_pendingContent.needsDisplayRect = IntRect();
+}
+
+void GraphicsLayerTextureMapper::setName(const String& name)
+{
+ GraphicsLayer::setName(name);
+}
+
+GraphicsLayerTextureMapper::~GraphicsLayerTextureMapper()
+{
+}
+
+/* \reimp (GraphicsLayer.h): The current size might change, thus we need to update the whole display.
+*/
+void GraphicsLayerTextureMapper::setNeedsDisplay()
+{
+ m_pendingContent.needsDisplay = true;
+ notifyChange(TextureMapperNode::DisplayChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ if (m_pendingContent.needsDisplay)
+ return;
+ m_pendingContent.needsDisplayRect.unite(IntRect(rect));
+ notifyChange(TextureMapperNode::DisplayChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setParent(GraphicsLayer* layer)
+{
+ notifyChange(TextureMapperNode::ParentChange);
+ GraphicsLayer::setParent(layer);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+bool GraphicsLayerTextureMapper::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ notifyChange(TextureMapperNode::ChildrenChange);
+ return GraphicsLayer::setChildren(children);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::addChild(GraphicsLayer* layer)
+{
+ notifyChange(TextureMapperNode::ChildrenChange);
+ GraphicsLayer::addChild(layer);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::addChildAtIndex(GraphicsLayer* layer, int index)
+{
+ GraphicsLayer::addChildAtIndex(layer, index);
+ notifyChange(TextureMapperNode::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildAbove(layer, sibling);
+ notifyChange(TextureMapperNode::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+
+ GraphicsLayer::addChildBelow(layer, sibling);
+ notifyChange(TextureMapperNode::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+bool GraphicsLayerTextureMapper::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ notifyChange(TextureMapperNode::ChildrenChange);
+ return true;
+ }
+ return false;
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::removeFromParent()
+{
+ if (!parent())
+ return;
+ notifyChange(TextureMapperNode::ParentChange);
+ GraphicsLayer::removeFromParent();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setMaskLayer(GraphicsLayer* value)
+{
+ if (value == maskLayer())
+ return;
+ GraphicsLayer::setMaskLayer(value);
+ notifyChange(TextureMapperNode::MaskLayerChange);
+}
+
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setReplicatedByLayer(GraphicsLayer* value)
+{
+ if (value == replicaLayer())
+ return;
+ GraphicsLayer::setReplicatedByLayer(value);
+ notifyChange(TextureMapperNode::ReplicaLayerChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setPosition(const FloatPoint& value)
+{
+ if (value == position())
+ return;
+ GraphicsLayer::setPosition(value);
+ notifyChange(TextureMapperNode::PositionChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setAnchorPoint(const FloatPoint3D& value)
+{
+ if (value == anchorPoint())
+ return;
+ GraphicsLayer::setAnchorPoint(value);
+ notifyChange(TextureMapperNode::AnchorPointChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setSize(const FloatSize& value)
+{
+ if (value == size())
+ return;
+
+ GraphicsLayer::setSize(value);
+ notifyChange(TextureMapperNode::SizeChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setTransform(const TransformationMatrix& value)
+{
+ if (value == transform())
+ return;
+
+ GraphicsLayer::setTransform(value);
+ notifyChange(TextureMapperNode::TransformChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setChildrenTransform(const TransformationMatrix& value)
+{
+ if (value == childrenTransform())
+ return;
+ GraphicsLayer::setChildrenTransform(value);
+ notifyChange(TextureMapperNode::ChildrenTransformChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setPreserves3D(bool value)
+{
+ if (value == preserves3D())
+ return;
+ GraphicsLayer::setPreserves3D(value);
+ notifyChange(TextureMapperNode::Preserves3DChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setMasksToBounds(bool value)
+{
+ if (value == masksToBounds())
+ return;
+ GraphicsLayer::setMasksToBounds(value);
+ notifyChange(TextureMapperNode::MasksToBoundsChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setDrawsContent(bool value)
+{
+ if (value == drawsContent())
+ return;
+ notifyChange(TextureMapperNode::DrawsContentChange);
+ GraphicsLayer::setDrawsContent(value);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setBackgroundColor(const Color& value)
+{
+ if (value == m_pendingContent.backgroundColor)
+ return;
+ m_pendingContent.backgroundColor = value;
+ GraphicsLayer::setBackgroundColor(value);
+ notifyChange(TextureMapperNode::BackgroundColorChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::clearBackgroundColor()
+{
+ if (!m_pendingContent.backgroundColor.isValid())
+ return;
+ m_pendingContent.backgroundColor = Color();
+ GraphicsLayer::clearBackgroundColor();
+ notifyChange(TextureMapperNode::BackgroundColorChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsOpaque(bool value)
+{
+ if (value == contentsOpaque())
+ return;
+ notifyChange(TextureMapperNode::ContentsOpaqueChange);
+ GraphicsLayer::setContentsOpaque(value);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setBackfaceVisibility(bool value)
+{
+ if (value == backfaceVisibility())
+ return;
+ GraphicsLayer::setBackfaceVisibility(value);
+ notifyChange(TextureMapperNode::BackfaceVisibilityChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setOpacity(float value)
+{
+ if (value == opacity())
+ return;
+ GraphicsLayer::setOpacity(value);
+ notifyChange(TextureMapperNode::OpacityChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsRect(const IntRect& value)
+{
+ if (value == contentsRect())
+ return;
+ GraphicsLayer::setContentsRect(value);
+ notifyChange(TextureMapperNode::ContentsRectChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsToImage(Image* image)
+{
+ notifyChange(TextureMapperNode::ContentChange);
+ m_pendingContent.contentType = image ? TextureMapperNode::DirectImageContentType : TextureMapperNode::HTMLContentType;
+ m_pendingContent.image = image;
+ GraphicsLayer::setContentsToImage(image);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsBackgroundColor(const Color& color)
+{
+ notifyChange(TextureMapperNode::ContentChange);
+ m_pendingContent.contentType = TextureMapperNode::ColorContentType;
+ m_pendingContent.backgroundColor = color;
+ GraphicsLayer::setContentsBackgroundColor(color);
+}
+
+
+void GraphicsLayerTextureMapper::setContentsToMedia(PlatformLayer* media)
+{
+ GraphicsLayer::setContentsToMedia(media);
+ notifyChange(TextureMapperNode::ContentChange);
+ m_pendingContent.contentType = media ? TextureMapperNode::MediaContentType : TextureMapperNode::HTMLContentType;
+ if (media)
+ m_pendingContent.media = static_cast<TextureMapperVideoLayer*>(media);
+ else
+ m_pendingContent.media = 0;
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsOrientation(CompositingCoordinatesOrientation orientation)
+{
+ if (contentsOrientation() == orientation)
+ return;
+ notifyChange(TextureMapperNode::ContentsOrientationChange);
+ GraphicsLayer::setContentsOrientation(orientation);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::syncCompositingStateForThisLayerOnly()
+{
+ m_node->syncCompositingState(this, false);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::syncCompositingState()
+{
+ m_node->syncCompositingState(this, true);
+}
+
+/* \reimp (GraphicsLayer.h)
+ */
+NativeLayer GraphicsLayerTextureMapper::nativeLayer() const
+{
+ return m_node.get();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+PlatformLayer* GraphicsLayerTextureMapper::platformLayer() const
+{
+ return m_node.get();
+}
+
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerTextureMapper(client);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h
new file mode 100644
index 0000000..85fa3ee
--- /dev/null
+++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef GraphicsLayerTextureMapper_h
+#define GraphicsLayerTextureMapper_h
+
+#include "GraphicsContext.h"
+#include "GraphicsLayer.h"
+#include "GraphicsLayerClient.h"
+#include "Image.h"
+#include "TextureMapperNode.h"
+
+#if ENABLE(3D_CANVAS)
+#include "GraphicsContext3D.h"
+#endif
+
+namespace WebCore {
+
+class TextureMapperNode;
+class BitmapTexture;
+class TextureMapper;
+
+class GraphicsLayerTextureMapper : public GraphicsLayer {
+ friend class TextureMapperNode;
+
+public:
+ GraphicsLayerTextureMapper(GraphicsLayerClient*);
+ virtual ~GraphicsLayerTextureMapper();
+
+ // reimps from GraphicsLayer.h
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+ virtual void setParent(GraphicsLayer* layer);
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
+ virtual void addChild(GraphicsLayer*);
+ virtual void addChildAtIndex(GraphicsLayer*, int index);
+ virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+ virtual void removeFromParent();
+ virtual void setMaskLayer(GraphicsLayer* layer);
+ virtual void setPosition(const FloatPoint& p);
+ virtual void setAnchorPoint(const FloatPoint3D& p);
+ virtual void setSize(const FloatSize& size);
+ virtual void setTransform(const TransformationMatrix& t);
+ virtual void setChildrenTransform(const TransformationMatrix& t);
+ virtual void setPreserves3D(bool b);
+ virtual void setMasksToBounds(bool b);
+ virtual void setDrawsContent(bool b);
+ virtual void setBackgroundColor(const Color&);
+ virtual void clearBackgroundColor();
+ virtual void setContentsOpaque(bool b);
+ virtual void setBackfaceVisibility(bool b);
+ virtual void setOpacity(float opacity);
+ virtual void setContentsRect(const IntRect& r);
+ virtual void setReplicatedByLayer(GraphicsLayer*);
+ virtual void setContentsToImage(Image*);
+ virtual void setContentsToMedia(PlatformLayer*);
+ virtual void setContentsBackgroundColor(const Color&);
+#if ENABLE(3D_CANVAS)
+ virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*);
+ virtual void setGraphicsContext3DNeedsDisplay();
+#endif
+ virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation);
+ virtual void syncCompositingState();
+ virtual void syncCompositingStateForThisLayerOnly();
+ virtual void setName(const String& name);
+ virtual NativeLayer nativeLayer() const;
+ virtual PlatformLayer* platformLayer() const;
+
+ virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, const String& /*keyframesName*/, double /*timeOffset*/) { return false; }
+
+ void notifyChange(TextureMapperNode::ChangeMask changeMask);
+ inline TextureMapperNode::ContentData& pendingContent() { return m_pendingContent; }
+ inline int changeMask() const { return m_changeMask; }
+ void didSynchronize();
+
+private:
+ OwnPtr<TextureMapperNode> m_node;
+ bool m_syncQueued;
+ int m_changeMask;
+ TextureMapperNode::ContentData m_pendingContent;
+};
+
+inline static GraphicsLayerTextureMapper* toGraphicsLayerTextureMapper(GraphicsLayer* layer)
+{
+ return static_cast<GraphicsLayerTextureMapper*>(layer);
+}
+
+}
+#endif // GraphicsLayerTextureMapper_h
diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.h b/Source/WebCore/platform/graphics/texmap/TextureMapper.h
new file mode 100644
index 0000000..589fda1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.h
@@ -0,0 +1,135 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TextureMapper_h
+#define TextureMapper_h
+
+#if USE(ACCELERATED_COMPOSITING)
+#if (defined(QT_OPENGL_LIB))
+ #if defined(QT_OPENGL_ES_2) && !defined(TEXMAP_OPENGL_ES_2)
+ #define TEXMAP_OPENGL_ES_2
+ #endif
+#endif
+
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "IntSize.h"
+#include "TransformationMatrix.h"
+
+/*
+ TextureMapper is a mechanism that enables hardware acceleration of CSS animations (accelerated compositing) without
+ a need for a platform specific scene-graph library like CoreAnimations or QGraphicsView.
+*/
+
+namespace WebCore {
+
+class TextureMapper;
+
+// A 2D texture that can be the target of software or GL rendering.
+class BitmapTexture : public RefCounted<BitmapTexture> {
+public:
+ BitmapTexture() : m_lockCount(0) {}
+ virtual ~BitmapTexture() { }
+
+ virtual bool allowOfflineTextureUpload() const { return false; }
+ virtual void destroy() = 0;
+ virtual IntSize size() const = 0;
+ virtual bool isValid() const = 0;
+ virtual void reset(const IntSize& size, bool opaque = false)
+ {
+ m_isOpaque = opaque;
+ m_contentSize = size;
+ }
+
+ virtual void pack() { }
+ virtual void unpack() { }
+ virtual bool isPacked() const { return false; }
+
+ virtual PlatformGraphicsContext* beginPaint(const IntRect& dirtyRect) = 0;
+ virtual void endPaint() = 0;
+ virtual PlatformGraphicsContext* beginPaintMedia()
+ {
+ return beginPaint(IntRect(0, 0, size().width(), size().height()));
+ }
+ virtual void setContentsToImage(Image*) = 0;
+ virtual bool save(const String& filename) { return false; }
+
+ inline void lock() { ++m_lockCount; }
+ inline void unlock() { --m_lockCount; }
+ inline bool isLocked() { return m_lockCount; }
+ inline IntSize contentSize() const { return m_contentSize; }
+ inline void setOffset(const IntPoint& o) { m_offset = o; }
+ inline IntPoint offset() const { return m_offset; }
+
+protected:
+
+private:
+ int m_lockCount;
+ IntSize m_contentSize;
+ bool m_isOpaque;
+ IntPoint m_offset;
+};
+
+// A "context" class used to encapsulate accelerated texture mapping functions: i.e. drawing a texture
+// onto the screen or into another texture with a specified transform, opacity and mask.
+class TextureMapper {
+ friend class BitmapTexture;
+
+public:
+ static PassOwnPtr<TextureMapper> create(GraphicsContext* graphicsContext = 0);
+ virtual ~TextureMapper() { }
+
+ virtual void drawTexture(const BitmapTexture& texture, const IntRect& target, const TransformationMatrix& matrix = TransformationMatrix(), float opacity = 1.0f, const BitmapTexture* maskTexture = 0) = 0;
+
+ // makes a surface the target for the following drawTexture calls.
+ virtual void bindSurface(BitmapTexture* surface) = 0;
+ virtual void paintToTarget(const BitmapTexture& texture, const IntSize&, const TransformationMatrix& matrix, float opacity, const IntRect& visibleRect)
+ {
+ drawTexture(texture, IntRect(0, 0, texture.contentSize().width(), texture.contentSize().height()), matrix, opacity, 0);
+ }
+
+ virtual void setGraphicsContext(GraphicsContext*) { }
+ virtual void setClip(const IntRect&) = 0;
+ virtual bool allowSurfaceForRoot() const = 0;
+ virtual PassRefPtr<BitmapTexture> createTexture() = 0;
+
+ void setImageInterpolationQuality(InterpolationQuality quality) { m_interpolationQuality = quality; }
+ void setTextDrawingMode(TextDrawingModeFlags mode) { m_textDrawingMode = mode; }
+
+ InterpolationQuality imageInterpolationQuality() const { return m_interpolationQuality; }
+ TextDrawingModeFlags textDrawingMode() const { return m_textDrawingMode; }
+
+ void setViewportSize(const IntSize&);
+
+protected:
+ TextureMapper()
+ : m_interpolationQuality(InterpolationDefault)
+ , m_textDrawingMode(TextModeFill)
+ {}
+
+private:
+ InterpolationQuality m_interpolationQuality;
+ TextDrawingModeFlags m_textDrawingMode;
+};
+
+};
+
+#endif
+
+#endif
diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp
new file mode 100644
index 0000000..09051f9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp
@@ -0,0 +1,877 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "TextureMapperNode.h"
+
+#include "GraphicsLayerTextureMapper.h"
+
+namespace WebCore {
+
+class TextureMapperCache {
+public:
+ void mark(BitmapTexture* texture);
+
+ class Entry {
+ public:
+ RefPtr<BitmapTexture> texture;
+ Entry() : previousCost(0) { }
+ inline int computeCost() const
+ {
+ if (!texture || !texture->isValid() || texture->isPacked())
+ return 0;
+ const IntSize textureSize = texture->size();
+ // An image's cost in bytes is width * height * bytes per pixel (4).
+ return textureSize.width() * textureSize.height() * 4;
+ }
+ Entry(BitmapTexture* newTexture)
+ : texture(newTexture)
+ {
+ }
+ bool operator==(const Entry& other) const { return texture == other.texture; }
+ int previousCost;
+ };
+
+ TextureMapperCache()
+ : m_totalCost(0)
+ {
+ }
+
+ void purge();
+ Vector<Entry> m_data;
+ int m_totalCost;
+#ifndef TEXMAP_TEXTURE_CACHE_KBS
+#define TEXMAP_TEXTURE_CACHE_KBS 24 * 1024
+#endif
+ static const int MaxCost = TEXMAP_TEXTURE_CACHE_KBS * 1024;
+ static const int PurgeAmount = MaxCost / 4;
+};
+
+
+void TextureMapperCache::purge()
+{
+ const int size = m_data.size();
+
+ if (m_totalCost <= TextureMapperCache::MaxCost)
+ return;
+
+ // Ensure that we have the right count. It might be inaccurate if content changed size.
+ // We only do this when we're actually ready to purge.
+ m_totalCost = 0;
+ for (int i = 0; i < size; ++i)
+ m_totalCost += m_data[i].computeCost();
+
+ for (int i = size-1; i >= 0 && m_totalCost > TextureMapperCache::MaxCost - TextureMapperCache::PurgeAmount; --i) {
+ Entry& entry = m_data[i];
+ if (entry.texture->isLocked() || !entry.texture->isValid() || entry.texture->isPacked())
+ continue;
+ m_totalCost -= entry.previousCost;
+ entry.texture->pack();
+ m_data.remove(i);
+ }
+}
+
+void TextureMapperCache::mark(BitmapTexture* texture)
+{
+ if (!texture || !texture->isValid())
+ return;
+
+ Entry entry(texture);
+ size_t index = m_data.find(entry);
+ if (!index)
+ return;
+
+ int previousCost = 0;
+
+ if (index < m_data.size()) {
+ previousCost = m_data[index].previousCost;
+ m_data.remove(index);
+ }
+ const int cost = entry.computeCost();
+ m_totalCost -= previousCost;
+ m_totalCost += (entry.previousCost = cost);
+ m_data.prepend(entry);
+}
+
+class TextureMapperCacheLock {
+public:
+ TextureMapperCacheLock(BitmapTexture* texture) : m_texture(texture)
+ {
+ if (m_texture)
+ m_texture->lock();
+ }
+ ~TextureMapperCacheLock()
+ {
+ if (m_texture)
+ m_texture->unlock();
+ }
+
+private:
+ RefPtr<BitmapTexture> m_texture;
+};
+
+
+TextureMapperCache* TextureMapperNode::cache()
+{
+ TextureMapperNode* root = rootLayer();
+ if (!root)
+ return 0;
+ if (!root->m_cache)
+ root->m_cache = new TextureMapperCache;
+ return root->m_cache;
+}
+
+void TextureMapperNode::setNeedsDisplayInRect(IntRect rect)
+{
+ if (m_platformClient) {
+ if (m_state.hasSurfaceDescendants) {
+ m_platformClient->setNeedsDisplay();
+ return;
+ }
+ rect.intersect(IntRect(0, 0, m_size.width(), m_size.height()));
+ if (rect.isEmpty())
+ return;
+ m_platformClient->setNeedsDisplayInRect(rect);
+ return;
+ }
+
+ if (!m_parent)
+ return;
+
+ m_parent->setNeedsDisplayInRect(rect);
+}
+
+void TextureMapperNode::setNeedsDisplay()
+{
+ if (m_effectTarget)
+ m_effectTarget->setNeedsDisplay();
+ if (m_transforms.targetBoundingRect.isEmpty())
+ return;
+ if (m_state.drawsContent || m_currentContent.contentType != HTMLContentType)
+ setNeedsDisplayInRect(m_transforms.targetBoundingRect);
+}
+
+void TextureMapperNode::setPlatformLayerClient(TextureMapperLayerClient* client)
+{
+ m_platformClient = client;
+}
+
+int TextureMapperNode::compareGraphicsLayersZValue(const void* a, const void* b)
+{
+ typedef const TextureMapperNode* NodePtr;
+ const NodePtr* nodeA = static_cast<const NodePtr*>(a);
+ const NodePtr* nodeB = static_cast<const NodePtr*>(b);
+ return int(((*nodeA)->m_transforms.centerZ - (*nodeB)->m_transforms.centerZ) * 1000);
+}
+
+void TextureMapperNode::sortByZOrder(Vector<TextureMapperNode* >& array, int first, int last)
+{
+ qsort(array.data(), array.size(), sizeof(TextureMapperNode*), TextureMapperNode::compareGraphicsLayersZValue);
+}
+
+bool TextureMapperNode::hasSurfaceDescendants() const
+{
+ if (m_layerType == ClipLayer || m_layerType == TransparencyLayer || m_state.replicaLayer)
+ return true;
+
+ const int size = m_children.size();
+ for (int i = 0; i < size; ++i) {
+ if (TextureMapperNode* child = m_children[i]) {
+ if (child->hasSurfaceDescendants())
+ return true;
+ }
+ }
+ return false;
+}
+
+int TextureMapperNode::countDescendantsWithContent() const
+{
+ if (!m_state.visible || m_state.opacity < 0.001)
+ return 0;
+
+ int descendantsWithContent = (m_state.drawsContent || m_currentContent.contentType != HTMLContentType) ? 1 : 0;
+
+ const int size = m_children.size();
+ for (int i = 0; i < size; ++i) {
+ if (TextureMapperNode* child = m_children[i])
+ descendantsWithContent += child->countDescendantsWithContent();
+ }
+
+ return descendantsWithContent;
+}
+
+TextureMapperNode* TextureMapperNode::toTextureMapperNode(GraphicsLayer* layer)
+{
+ return layer ? static_cast<TextureMapperNode*>(layer->platformLayer()) : 0;
+}
+
+void TextureMapperNode::computeLayerType()
+{
+ const bool selfHasContent = m_state.drawsContent || (m_currentContent.contentType != HTMLContentType);
+ const bool hasDescendantsWithContent = m_state.descendantsWithContent - (selfHasContent ? 1 : 0);
+ const bool hasTransparency = m_state.opacity < 0.99 || m_state.maskLayer;
+ const bool hasReplica = m_state.replicaLayer;
+
+ // DefaultLayer: draws itself and its children directly to the current framebuffer.
+ // any layer that doesn't conform to the other rules is a DefaultLayer.
+ m_layerType = DefaultLayer;
+
+ // RootLayer: the top level. Draws to a framebuffer, and the target texture draws into the viewport.
+ // only one layer is the root layer.
+ if (!m_parent && !m_effectTarget) {
+ m_layerType = RootLayer;
+ return;
+ }
+
+ // A layer with no contents is always a default layer.
+ if (!m_state.descendantsWithContent)
+ return;
+
+ // ClipLayer: creates a new framebuffer, the size of the layer, and then paints it to the enclosing BitmapTexture with the layer's transform/opacity.
+ // A clip layer is a layer that masks to bounds, doesn't preserve 3D, has children, and has a transparency/mask or a non-rectangular transform.
+ if (hasDescendantsWithContent && m_state.maskLayer) {
+ m_layerType = ClipLayer;
+ return;
+ }
+
+ // ScissorLayer: draws to the current framebuffer, and applies an extra scissor before drawing its children.
+ // A scissor layer is a layer with children that masks to bounds, is not a transparency layer, and has a rectangular clip.
+ if (m_state.masksToBounds && hasDescendantsWithContent) {
+ if (hasTransparency || !m_state.transform.isIdentityOrTranslation() || m_parent->m_state.preserves3D)
+ m_layerType = ClipLayer;
+ else
+ m_layerType = ScissorLayer;
+ return;
+ }
+
+ // TransparencyLayer: creates a new framebuffer idetical in size to the current framebuffer. Then draws the fb's texture to the current framebuffer with identity transform.
+ // Used for layers with children and transparency/mask that preserve 3D or don't mask to bounds.
+ if ((hasReplica && hasDescendantsWithContent) || (hasReplica && hasTransparency) || (hasTransparency && m_state.descendantsWithContent > 1))
+ m_layerType = TransparencyLayer;
+}
+
+void TextureMapperNode::initializeTextureMapper(TextureMapper* textureMapper)
+{
+ if (m_texture)
+ return;
+ m_surface = textureMapper->createTexture();
+ m_replicaSurface = textureMapper->createTexture();
+ m_texture = textureMapper->createTexture();
+ cache()->mark(m_texture.get());
+}
+
+TextureMapperNode::TextureMapperNode()
+ : m_layerType(DefaultLayer)
+ , m_surface(0)
+ , m_parent(0)
+ , m_effectTarget(0)
+ , m_platformClient(0)
+ , m_cache(0)
+{
+}
+
+TextureMapperNode* TextureMapperNode::rootLayer()
+{
+ if (m_effectTarget)
+ return m_effectTarget->rootLayer();
+ if (m_parent)
+ return m_parent->rootLayer();
+ return this;
+}
+
+void TextureMapperNode::invalidateTransform()
+{
+ m_transforms.dirty = true;
+ if (m_layerType != ClipLayer)
+ m_state.dirty = true;
+ if (m_state.replicaLayer)
+ m_state.replicaLayer->invalidateTransform();
+ const int size = m_children.size();
+ for (int i = 0; i < size; ++i) {
+ if (TextureMapperNode* layer = m_children[i])
+ layer->invalidateTransform();
+ }
+}
+
+void TextureMapperNode::computeLocalTransform()
+{
+ if (!m_transforms.localDirty)
+ return;
+ const float originX = m_state.anchorPoint.x() * m_size.width();
+ const float originY = m_state.anchorPoint.y() * m_size.height();
+ m_transforms.local =
+ TransformationMatrix()
+ .translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z())
+ .multLeft(m_state.transform)
+ .translate3d(-originX, -originY, -m_state.anchorPoint.z());
+ m_transforms.localDirty = false;
+}
+
+void TextureMapperNode::flattenTo2DSpaceIfNecessary()
+{
+ if (m_state.preserves3D)
+ return;
+
+ m_transforms.forDescendants.setM13(0);
+ m_transforms.forDescendants.setM23(0);
+ m_transforms.forDescendants.setM31(0);
+ m_transforms.forDescendants.setM32(0);
+ m_transforms.forDescendants.setM33(1);
+ m_transforms.forDescendants.setM34(0);
+ m_transforms.forDescendants.setM43(0);
+}
+
+IntSize TextureMapperNode::nearestSurfaceSize() const
+{
+ if (m_layerType == ClipLayer || m_layerType == RootLayer)
+ return m_surface && !m_surface->size().isEmpty() ? m_surface->size() : m_size;
+ return m_parent->nearestSurfaceSize();
+}
+
+void TextureMapperNode::computeReplicaTransform()
+{
+ if (!m_state.replicaLayer)
+ return;
+
+ m_nearestSurfaceSize = nearestSurfaceSize();
+
+ if (m_layerType != TransparencyLayer) {
+ m_transforms.replica = TransformationMatrix(m_transforms.target).multLeft(m_state.replicaLayer->m_transforms.local);
+ return;
+ }
+
+ const float originX = m_transforms.target.m41();
+ const float originY = m_transforms.target.m42();
+ m_transforms.replica =
+ TransformationMatrix()
+ .translate(originX, originY)
+ .multLeft(m_state.replicaLayer->m_transforms.local)
+ .translate(-originX, -originY);
+}
+
+void TextureMapperNode::computeTransformations()
+{
+ if (!m_transforms.dirty)
+ return;
+
+ m_transforms.dirty = false;
+ if ((m_size.isEmpty() && m_state.masksToBounds))
+ return;
+
+ TextureMapperNode* parent = m_parent;
+ computeLocalTransform();
+
+ m_transforms.target = TransformationMatrix(parent ? parent->m_transforms.forDescendants : TransformationMatrix()).multLeft(m_transforms.local);
+ m_transforms.forDescendants = (m_layerType == ClipLayer ? TransformationMatrix() : m_transforms.target);
+
+ if (m_effectTarget)
+ return;
+
+ m_transforms.targetBoundingRect = IntRect(m_transforms.target.mapRect(entireRect()));
+ if (m_state.replicaLayer)
+ m_state.replicaLayer->computeTransformations();
+
+ flattenTo2DSpaceIfNecessary();
+
+ if (!m_state.backfaceVisibility && m_transforms.target.inverse().m33() < 0) {
+ m_state.visible = false;
+ return;
+ }
+ m_state.visible = true;
+
+ if (parent && parent->m_state.preserves3D)
+ m_transforms.centerZ = m_transforms.target.mapPoint(FloatPoint3D(m_size.width() / 2, m_size.height() / 2, 0)).z();
+
+ if (!m_children.size())
+ return;
+
+ if (m_state.childrenTransform.isIdentity())
+ return;
+
+ const FloatPoint centerPoint = FloatPoint(m_size.width() / 2, m_size.height() / 2);
+ if (m_transforms.perspectiveDirty)
+ m_transforms.perspective = TransformationMatrix()
+ .translate(centerPoint.x(), centerPoint.y())
+ .multLeft(m_state.childrenTransform)
+ .translate(-centerPoint.x(), -centerPoint.y());
+ m_transforms.perspectiveDirty = false;
+ m_transforms.forDescendants.multLeft(m_transforms.perspective);
+}
+
+void TextureMapperNode::uploadTextureFromContent(TextureMapper* textureMapper, const IntRect& visibleRect, GraphicsLayer* layer)
+{
+ if (m_size.isEmpty() || !layer) {
+ m_texture->destroy();
+ return;
+ }
+
+ if (m_currentContent.contentType == DirectImageContentType) {
+ if (m_currentContent.image)
+ m_texture->setContentsToImage(m_currentContent.image.get());
+ return;
+ }
+
+ if (m_currentContent.contentType == MediaContentType) {
+ if (!m_currentContent.media)
+ return;
+ m_texture->reset(m_size, true);
+ PlatformGraphicsContext* platformContext = m_texture->beginPaintMedia();
+ GraphicsContext context(platformContext);
+ m_currentContent.media->paint(&context);
+ m_texture->endPaint();
+ return;
+ }
+
+ const bool needsReset = (m_texture->contentSize() != m_size) || !m_texture->isValid();
+ if ((m_currentContent.contentType != HTMLContentType)
+ || (!m_currentContent.needsDisplay && m_currentContent.needsDisplayRect.isEmpty() && !needsReset))
+ return;
+
+ IntRect dirtyRect = IntRect(0, 0, m_size.width(), m_size.height());
+ if (!needsReset && !m_currentContent.needsDisplay)
+ dirtyRect.intersect(m_currentContent.needsDisplayRect);
+
+ if (needsReset)
+ m_texture->reset(m_size, m_state.contentsOpaque);
+
+ {
+ GraphicsContext context(m_texture->beginPaint(dirtyRect));
+ if (textureMapper) {
+ context.setImageInterpolationQuality(textureMapper->imageInterpolationQuality());
+ context.setTextDrawingMode(textureMapper->textDrawingMode());
+ }
+ layer->paintGraphicsLayerContents(context, dirtyRect);
+ }
+ m_texture->endPaint();
+ m_currentContent.needsDisplay = false;
+}
+
+
+void TextureMapperNode::paint(TextureMapper* textureMapper, const TextureMapperContentLayer::PaintOptions& options)
+{
+ ASSERT(m_layerType == RootLayer);
+ if (m_size.isEmpty())
+ return;
+
+ TexmapPaintOptions opt;
+ opt.opacity = 1;
+ opt.rootLayer = this;
+ opt.scissorRect = options.targetRect;
+ opt.visibleRect = options.visibleRect;
+ opt.textureMapper = textureMapper;
+ opt.surface = 0;
+ opt.cache = m_cache;
+ paintRecursive(opt);
+
+ if (textureMapper->allowSurfaceForRoot() || m_state.hasSurfaceDescendants) {
+ textureMapper->bindSurface(0);
+ textureMapper->paintToTarget(*m_surface.get(), options.viewportSize, options.transform, options.opacity * m_state.opacity, options.targetRect);
+ }
+ m_cache->purge();
+}
+
+void TextureMapperNode::paintSelf(const TexmapPaintOptions& options)
+{
+ if (m_size.isEmpty() || (!m_state.drawsContent && m_currentContent.contentType == HTMLContentType))
+ return;
+
+ RefPtr<BitmapTexture> replicaMaskTexture;
+ m_texture->unpack();
+
+ RefPtr<BitmapTexture> maskTexture = m_state.maskLayer ? m_state.maskLayer->m_texture : 0;
+ if (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer)
+ replicaMaskTexture = m_state.replicaLayer->m_state.maskLayer->m_texture;
+
+ if (maskTexture)
+ maskTexture->unpack();
+
+ if (replicaMaskTexture)
+ replicaMaskTexture->unpack();
+
+ const float opacity = options.isSurface ? 1 : options.opacity;
+
+ if (m_state.replicaLayer && !options.isSurface)
+ options.textureMapper->drawTexture(*m_texture.get(), replicaRect(), m_transforms.replica,
+ opacity * m_state.replicaLayer->m_state.opacity,
+ replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get());
+
+ const IntRect rect = m_layerType == ClipLayer ? entireRect() : targetRect();
+ const TransformationMatrix transform = m_layerType == ClipLayer ? TransformationMatrix() : m_transforms.target;
+ options.textureMapper->drawTexture(*m_texture.get(), rect, transform, opacity, options.isSurface ? 0 : maskTexture.get());
+ options.cache->mark(m_texture.get());
+}
+
+bool TextureMapperNode::paintReplica(const TexmapPaintOptions& options)
+{
+ BitmapTexture& texture = *m_surface.get();
+ TextureMapperNode* replica = m_state.replicaLayer;
+ RefPtr<BitmapTexture> maskTexture;
+ if (TextureMapperNode* mask = m_state.maskLayer)
+ maskTexture = mask->m_texture;
+ RefPtr<BitmapTexture> replicaMaskTexture;
+ if (!replica)
+ return false;
+
+ if (replica && replica->m_state.maskLayer)
+ replicaMaskTexture = replica->m_state.maskLayer->m_texture;
+
+ if (replicaMaskTexture)
+ replicaMaskTexture->unpack();
+ ASSERT(m_replicaSurface);
+ m_replicaSurface->reset(options.surface->size());
+ m_replicaSurface->setOffset(options.surface->offset());
+ options.cache->mark(m_replicaSurface.get());
+ options.textureMapper->bindSurface(m_replicaSurface.get());
+ options.textureMapper->drawTexture(texture, replicaRect(), m_transforms.replica, replica->m_state.opacity, replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get());
+ options.textureMapper->drawTexture(texture, IntRect(IntPoint(0, 0), options.surface->size()), TransformationMatrix(), 1.0f, maskTexture.get());
+ options.textureMapper->bindSurface(options.surface);
+ options.cache->mark(options.surface);
+ options.textureMapper->drawTexture(*m_replicaSurface.get(), IntRect(IntPoint(0, 0), options.surface->size()), TransformationMatrix(), options.opacity, 0);
+ return true;
+}
+
+void TextureMapperNode::paintSurface(const TexmapPaintOptions& options)
+{
+ if (m_layerType == RootLayer || m_layerType == DefaultLayer || m_layerType == ScissorLayer)
+ return;
+
+ RefPtr<BitmapTexture> maskTexture;
+ if (TextureMapperNode* mask = m_state.maskLayer)
+ maskTexture = mask->m_texture;
+
+ ASSERT(m_surface);
+ BitmapTexture& texture = *m_surface.get();
+ if (maskTexture)
+ maskTexture->unpack();
+ texture.unpack();
+
+ if (paintReplica(options))
+ return;
+
+ options.textureMapper->bindSurface(options.surface);
+ options.textureMapper->drawTexture(texture,
+ m_layerType == TransparencyLayer ? IntRect(IntPoint(0, 0), options.surface->size()) :
+ targetRect(),
+ m_layerType == TransparencyLayer ? TransformationMatrix() : m_transforms.target,
+ options.opacity, maskTexture.get());
+ options.cache->mark(&texture);
+}
+
+void TextureMapperNode::paintSelfAndChildren(const TexmapPaintOptions& options, TexmapPaintOptions& optionsForDescendants)
+{
+ bool didPaintSelf = false;
+ if (!m_state.preserves3D || m_children.isEmpty()) {
+ paintSelf(options);
+ didPaintSelf = true;
+ }
+
+ if (m_children.isEmpty() && !options.isSurface)
+ return;
+
+ if (m_layerType == ScissorLayer)
+ optionsForDescendants.scissorRect.intersect(m_transforms.target.mapRect(IntRect(0, 0, m_size.width(), m_size.height())));
+
+ for (int i = 0; i < m_children.size(); ++i) {
+ TextureMapperNode* layer = m_children[i];
+ if (!layer)
+ continue;
+
+ if (!didPaintSelf && layer->m_transforms.centerZ >= 0) {
+ paintSelf(options);
+ didPaintSelf = true;
+ }
+ layer->paintRecursive(optionsForDescendants);
+ if (options.isSurface) {
+ ASSERT(m_surface);
+ options.cache->mark(m_surface.get());
+ options.textureMapper->bindSurface(m_surface.get());
+ }
+ }
+ if (!didPaintSelf) {
+ paintSelf(options);
+ didPaintSelf = true;
+ }
+}
+
+void TextureMapperNode::paintRecursive(TexmapPaintOptions options)
+{
+ bool isDirty = m_state.dirty;
+ m_state.dirty = false;
+
+ if ((m_size.isEmpty() && (m_state.masksToBounds
+ || m_children.isEmpty())) || !m_state.visible || options.opacity < 0.01 || m_state.opacity < 0.01)
+ return;
+
+ computeReplicaTransform();
+
+ if (m_state.maskLayer)
+ m_state.maskLayer->m_state.dirty = false;
+
+ if (m_state.replicaLayer) {
+ m_state.replicaLayer->m_state.dirty = false;
+ if (m_state.replicaLayer->m_state.maskLayer)
+ m_state.replicaLayer->m_state.maskLayer->m_state.dirty = false;
+ }
+
+ const bool isSurface = (m_layerType == ClipLayer
+ || m_layerType == TransparencyLayer
+ || (m_layerType == RootLayer
+ && (options.textureMapper->allowSurfaceForRoot() || m_state.hasSurfaceDescendants)
+ ));
+
+ const IntRect boundingRectfromNearestSurface = m_transforms.targetBoundingRect;
+
+ options.opacity *= m_state.opacity;
+
+ TexmapPaintOptions optionsForDescendants(options);
+ optionsForDescendants.opacity = isSurface ? 1 : options.opacity;
+ options.isSurface = isSurface;
+
+ if (m_layerType == ClipLayer) {
+ optionsForDescendants.visibleRect = TransformationMatrix().translate(-boundingRectfromNearestSurface.x(), -boundingRectfromNearestSurface.y()).mapRect(options.visibleRect);
+ optionsForDescendants.scissorRect = IntRect(0, 0, m_size.width(), m_size.height());
+ }
+
+ if (m_layerType == ScissorLayer)
+ optionsForDescendants.scissorRect.intersect(m_transforms.targetBoundingRect);
+ options.textureMapper->setClip(optionsForDescendants.scissorRect);
+
+ TextureMapperCacheLock(m_texture.get());
+ TextureMapperCacheLock(m_surface.get());
+ TextureMapperCacheLock(m_replicaSurface.get());
+
+ options.cache->purge();
+
+ if (isSurface) {
+ ASSERT(m_surface);
+ if (!m_surface->isValid())
+ isDirty = true;
+ if (m_state.tiled) {
+ m_surface->reset(options.visibleRect.size());
+ m_surface->setOffset(options.visibleRect.location());
+ } else if (isDirty)
+ m_surface->reset(m_layerType == TransparencyLayer ? options.surface->size() : m_size);
+ options.cache->mark(m_surface.get());
+ options.textureMapper->bindSurface(m_surface.get());
+ optionsForDescendants.surface = m_surface.get();
+ } else if (m_surface)
+ m_surface->destroy();
+
+ if (isDirty || !isSurface || m_state.tiled || !m_surface->isValid())
+ paintSelfAndChildren(options, optionsForDescendants);
+
+ paintSurface(options);
+}
+
+TextureMapperNode::~TextureMapperNode()
+{
+ setNeedsDisplay();
+ {
+ const int childrenSize = m_children.size();
+ for (int i = childrenSize-1; i >= 0; --i) {
+ ASSERT(m_children[i]->m_parent == this);
+ m_children[i]->m_parent = 0;
+ }
+ }
+ if (m_parent)
+ m_parent->m_children.remove(m_parent->m_children.find(this));
+ if (m_cache)
+ delete m_cache;
+}
+
+void TextureMapperNode::performPostSyncOperations()
+{
+ const LayerType prevLayerType = m_layerType;
+ computeLayerType();
+ if (prevLayerType != m_layerType)
+ m_state.dirty = true;
+ if (m_transforms.dirty)
+ setNeedsDisplay();
+
+ computeTransformations();
+ if (m_state.maskLayer && !m_state.dirty)
+ m_state.dirty = m_state.maskLayer->m_state.dirty;
+ if (m_state.replicaLayer && !m_state.dirty)
+ m_state.dirty = m_state.replicaLayer->m_state.dirty;
+
+ const int size = m_children.size();
+
+ for (int i = size - 1; i >= 0; --i) {
+ TextureMapperNode* layer = m_children[i];
+
+ layer->performPostSyncOperations();
+ if (!m_state.dirty)
+ m_state.dirty = layer->m_state.dirty;
+ }
+ m_state.hasSurfaceDescendants = hasSurfaceDescendants();
+ if (m_state.dirty)
+ m_state.descendantsWithContent = countDescendantsWithContent();
+
+ if (m_state.preserves3D)
+ sortByZOrder(m_children, 0, size);
+ if (m_state.dirty)
+ setNeedsDisplay();
+}
+
+void TextureMapperNode::syncCompositingState(GraphicsLayerTextureMapper* graphicsLayer, bool recurse)
+{
+ TextureMapper* textureMapper = rootLayer()->m_platformClient->textureMapper();
+ syncCompositingStateInternal(graphicsLayer, recurse, textureMapper);
+ performPostSyncOperations();
+}
+
+void TextureMapperNode::syncCompositingStateSelf(GraphicsLayerTextureMapper* graphicsLayer, TextureMapper* textureMapper)
+{
+ const int changeMask = graphicsLayer->changeMask();
+ initializeTextureMapper(textureMapper);
+ const TextureMapperNode::ContentData& pendingContent = graphicsLayer->pendingContent();
+ if (changeMask == NoChanges && pendingContent.needsDisplayRect.isEmpty() && !pendingContent.needsDisplay)
+ return;
+
+ setNeedsDisplay();
+ if (m_parent)
+ m_parent->m_state.dirty = true;
+
+ if (m_currentContent.contentType == HTMLContentType && (changeMask & ParentChange)) {
+ // The WebCore compositor manages item ownership. We have to make sure graphicsview doesn't
+ // try to snatch that ownership.
+
+ if (!graphicsLayer->parent())
+ m_parent = 0;
+ else
+ m_parent = toTextureMapperNode(graphicsLayer->parent());
+
+ if (!graphicsLayer->parent() && m_parent) {
+ size_t index = m_parent->m_children.find(this);
+ m_parent->m_children.remove(index);
+ }
+ }
+
+ if (changeMask & ChildrenChange) {
+ m_children.clear();
+ for (size_t i = 0; i < graphicsLayer->children().size(); ++i) {
+ if (TextureMapperNode* child = toTextureMapperNode(graphicsLayer->children()[i])) {
+ if (!child)
+ continue;
+ m_children.append(child);
+ child->m_parent = this;
+ }
+ }
+ m_state.dirty = true;
+ }
+
+ if (changeMask & (SizeChange | ContentsRectChange)) {
+ IntSize wantedSize = IntSize(graphicsLayer->size().width(), graphicsLayer->size().height());
+ if (wantedSize.isEmpty() && pendingContent.contentType == HTMLContentType)
+ wantedSize = IntSize(graphicsLayer->contentsRect().width(), graphicsLayer->contentsRect().height());
+
+ if (wantedSize != m_size) {
+ m_size = IntSize(wantedSize.width(), wantedSize.height());
+ if (m_platformClient)
+ m_platformClient->setSizeChanged(m_size);
+ const bool needsTiling = m_size.width() > 2000 || m_size.height() > 2000;
+ if (m_state.tiled != needsTiling)
+ m_state.tiled = needsTiling;
+ m_state.dirty = true;
+ }
+ }
+
+ if (changeMask & MaskLayerChange) {
+ if (TextureMapperNode* layer = toTextureMapperNode(graphicsLayer->maskLayer()))
+ layer->m_effectTarget = this;
+ }
+
+ if (changeMask & ReplicaLayerChange) {
+ if (TextureMapperNode* layer = toTextureMapperNode(graphicsLayer->replicaLayer()))
+ layer->m_effectTarget = this;
+ }
+
+ if (changeMask & (TransformChange | SizeChange | AnchorPointChange | PositionChange))
+ m_transforms.localDirty = true;
+
+ if (changeMask & (ChildrenTransformChange | SizeChange))
+ m_transforms.perspectiveDirty = true;
+
+ if (changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | ContentsRectChange | BackfaceVisibilityChange | PositionChange | MaskLayerChange | DrawsContentChange | ContentChange | ReplicaLayerChange)) {
+ // Due to the differences between the way WebCore handles transforms and the way Qt handles transforms,
+ // all these elements affect the transforms of all the descendants.
+ invalidateTransform();
+ }
+
+ if (changeMask & DisplayChange)
+ m_state.dirty = true;
+
+ m_state.maskLayer = toTextureMapperNode(graphicsLayer->maskLayer());
+ m_state.replicaLayer = toTextureMapperNode(graphicsLayer->replicaLayer());
+ m_state.pos = graphicsLayer->position();
+ m_state.anchorPoint = graphicsLayer->anchorPoint();
+ m_state.size = graphicsLayer->size();
+ m_state.transform = graphicsLayer->transform();
+ m_state.contentsRect = graphicsLayer->contentsRect();
+ m_state.opacity = graphicsLayer->opacity();
+ m_state.contentsRect = graphicsLayer->contentsRect();
+ m_state.preserves3D = graphicsLayer->preserves3D();
+ m_state.masksToBounds = graphicsLayer->masksToBounds();
+ m_state.drawsContent = graphicsLayer->drawsContent();
+ m_state.contentsOpaque = graphicsLayer->contentsOpaque();
+ m_state.backfaceVisibility = graphicsLayer->backfaceVisibility();
+ m_state.childrenTransform = graphicsLayer->childrenTransform();
+ m_currentContent.contentType = pendingContent.contentType;
+ m_currentContent.image = pendingContent.image;
+ m_currentContent.media = pendingContent.media;
+ m_currentContent.backgroundColor = pendingContent.backgroundColor;
+ m_currentContent.needsDisplay = m_currentContent.needsDisplay || pendingContent.needsDisplay;
+ m_currentContent.needsDisplayRect.unite(pendingContent.needsDisplayRect);
+
+}
+
+void TextureMapperNode::syncCompositingStateInternal(GraphicsLayerTextureMapper* graphicsLayer, bool recurse, TextureMapper* textureMapper)
+{
+ syncCompositingStateSelf(graphicsLayer, textureMapper);
+
+ graphicsLayer->didSynchronize();
+
+ if (m_state.maskLayer) {
+ m_state.maskLayer->syncCompositingStateInternal(toGraphicsLayerTextureMapper(graphicsLayer->maskLayer()), false, textureMapper);
+ if (m_state.maskLayer->m_size.isEmpty())
+ m_state.maskLayer->m_size = m_size;
+ }
+
+ if (m_state.replicaLayer)
+ m_state.replicaLayer->syncCompositingStateInternal(toGraphicsLayerTextureMapper(graphicsLayer->replicaLayer()), false, textureMapper);
+
+ if (m_state.dirty)
+ uploadTextureFromContent(textureMapper, m_state.visibleRect, graphicsLayer);
+
+ m_currentContent.needsDisplayRect = IntRect();
+ m_currentContent.needsDisplay = false;
+
+ if (!recurse)
+ return;
+
+ Vector<GraphicsLayer*> children = graphicsLayer->children();
+ for (int i = children.size() - 1; i >= 0; --i) {
+ TextureMapperNode* node = toTextureMapperNode(children[i]);
+ if (!node)
+ continue;
+ node->syncCompositingStateInternal(toGraphicsLayerTextureMapper(children[i]), true, textureMapper);
+ }
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h
new file mode 100644
index 0000000..9694043
--- /dev/null
+++ b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h
@@ -0,0 +1,252 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TextureMapperNode_h
+#define TextureMapperNode_h
+
+#include "CurrentTime.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "GraphicsLayer.h"
+#include "HashMap.h"
+#include "Image.h"
+#include "RefCounted.h"
+#include "TextureMapper.h"
+#include "TextureMapperPlatformLayer.h"
+#include "Timer.h"
+#include "TransformOperations.h"
+#include "TranslateTransformOperation.h"
+#include "UnitBezier.h"
+
+namespace WebCore {
+
+class TextureMapperNode;
+class TextureMapperCache;
+class GraphicsLayerTextureMapper;
+
+struct TexmapPaintOptions {
+ BitmapTexture* surface;
+ TextureMapper* textureMapper;
+ TextureMapperNode* rootLayer;
+ float opacity;
+ IntRect scissorRect;
+ IntRect visibleRect;
+ bool isSurface;
+ TextureMapperCache* cache;
+};
+
+class TextureMapperNode : public TextureMapperContentLayer {
+
+public:
+ // This set of flags help us defer which properties of the layer have been
+ // modified by the compositor, so we can know what to look for in the next flush.
+ enum ChangeMask {
+ NoChanges = 0,
+
+ ParentChange = (1L << 0),
+ ChildrenChange = (1L << 1),
+ MaskLayerChange = (1L << 2),
+ PositionChange = (1L << 3),
+
+ AnchorPointChange = (1L << 4),
+ SizeChange = (1L << 5),
+ TransformChange = (1L << 6),
+ ContentChange = (1L << 7),
+
+ ContentsOrientationChange = (1L << 9),
+ OpacityChange = (1L << 10),
+ ContentsRectChange = (1L << 11),
+
+ Preserves3DChange = (1L << 12),
+ MasksToBoundsChange = (1L << 13),
+ DrawsContentChange = (1L << 14),
+ ContentsOpaqueChange = (1L << 15),
+
+ BackfaceVisibilityChange = (1L << 16),
+ ChildrenTransformChange = (1L << 17),
+ DisplayChange = (1L << 18),
+ BackgroundColorChange = (1L << 19),
+
+ ReplicaLayerChange = (1L << 20)
+ };
+ // The compositor lets us special-case images and colors, so we try to do so.
+ enum ContentType { HTMLContentType, DirectImageContentType, ColorContentType, MediaContentType, Canvas3DContentType};
+ struct ContentData {
+ IntRect needsDisplayRect;
+ bool needsDisplay;
+ Color backgroundColor;
+
+ ContentType contentType;
+ RefPtr<Image> image;
+ TextureMapperVideoLayer* media;
+
+ ContentData()
+ : needsDisplay(false)
+ , contentType(HTMLContentType)
+ , image(0)
+ , media(0)
+ {
+ }
+ };
+
+
+ TextureMapperNode();
+ virtual ~TextureMapperNode();
+
+ void syncCompositingState(GraphicsLayerTextureMapper*, bool recursive);
+
+protected:
+ // Reimps from TextureMapperContentLayer
+ virtual IntSize size() const { return m_size; }
+ virtual void setPlatformLayerClient(TextureMapperLayerClient*);
+ virtual void paint(TextureMapper*, const TextureMapperContentLayer::PaintOptions&);
+
+private:
+ TextureMapperNode* rootLayer();
+ void clearDirectImage();
+ void computeTransformations();
+ IntSize nearestSurfaceSize() const;
+ void computeReplicaTransform();
+ void computeLayerType();
+ void computeLocalTransform();
+ void flattenTo2DSpaceIfNecessary();
+ void initializeTextureMapper(TextureMapper*);
+ void invalidateTransform();
+ void notifyChange(ChangeMask);
+ void setNeedsDisplay();
+ void setNeedsDisplayInRect(IntRect);
+ void performPostSyncOperations();
+ void syncCompositingStateInternal(GraphicsLayerTextureMapper*, bool recursive, TextureMapper*);
+ void syncCompositingStateSelf(GraphicsLayerTextureMapper* graphicsLayer, TextureMapper* textureMapper);
+ TextureMapperCache* cache();
+
+ void paintRecursive(TexmapPaintOptions options);
+ bool paintReplica(const TexmapPaintOptions& options);
+ void paintSurface(const TexmapPaintOptions& options);
+ void paintSelf(const TexmapPaintOptions& options);
+ void paintSelfAndChildren(const TexmapPaintOptions& options, TexmapPaintOptions& optionsForDescendants);
+ void uploadTextureFromContent(TextureMapper* textureMapper, const IntRect& visibleRect, GraphicsLayer* layer);
+
+ int countDescendantsWithContent() const;
+ bool hasSurfaceDescendants() const;
+
+ TextureMapper* textureMapper();
+
+
+ static TextureMapperNode* toTextureMapperNode(GraphicsLayer*);
+ static int compareGraphicsLayersZValue(const void* a, const void* b);
+ static void sortByZOrder(Vector<TextureMapperNode* >& array, int first, int last);
+ struct TransformData {
+ TransformationMatrix base, target, replica, forDescendants, perspective, local;
+ IntRect targetBoundingRect;
+ float centerZ;
+ bool dirty, localDirty, perspectiveDirty;
+ IntRect boundingRectFromRoot;
+ TransformData() : dirty(true), localDirty(true), perspectiveDirty(true) { }
+ };
+
+ TransformData m_transforms;
+
+ enum LayerType {
+ DefaultLayer,
+ RootLayer,
+ ScissorLayer,
+ ClipLayer,
+ TransparencyLayer
+ };
+
+ LayerType m_layerType;
+
+ inline IntRect targetRect() const
+ {
+ return m_currentContent.contentType == HTMLContentType ? entireRect() : m_state.contentsRect;
+ }
+
+ inline IntRect entireRect() const
+ {
+ return IntRect(0, 0, m_size.width(), m_size.height());
+ }
+
+ inline IntRect replicaRect() const
+ {
+ return m_layerType == TransparencyLayer ? IntRect(0, 0, m_nearestSurfaceSize.width(), m_nearestSurfaceSize.height()) : entireRect();
+ }
+
+ RefPtr<BitmapTexture> m_texture;
+ RefPtr<BitmapTexture> m_surface, m_replicaSurface;
+
+ ContentData m_currentContent;
+
+ Vector<TextureMapperNode*> m_children;
+ TextureMapperNode* m_parent;
+ TextureMapperNode* m_effectTarget;
+ IntSize m_size, m_nearestSurfaceSize;
+ String m_name;
+ TextureMapperLayerClient* m_platformClient;
+
+ struct State {
+ FloatPoint pos;
+ FloatPoint3D anchorPoint;
+ FloatSize size;
+ TransformationMatrix transform;
+ TransformationMatrix childrenTransform;
+ Color backgroundColor;
+ Color currentColor;
+ GraphicsLayer::CompositingCoordinatesOrientation geoOrientation;
+ GraphicsLayer::CompositingCoordinatesOrientation contentsOrientation;
+ float opacity;
+ IntRect contentsRect;
+ int descendantsWithContent;
+ TextureMapperNode* maskLayer;
+ TextureMapperNode* replicaLayer;
+ bool preserves3D;
+ bool masksToBounds;
+ bool drawsContent;
+ bool contentsOpaque;
+ bool backfaceVisibility;
+ bool visible;
+ bool dirty;
+ bool tiled;
+ bool hasSurfaceDescendants;
+ IntRect visibleRect;
+
+ State()
+ : opacity(1.f)
+ , descendantsWithContent(0)
+ , maskLayer(0)
+ , replicaLayer(0)
+ , preserves3D(false)
+ , masksToBounds(false)
+ , drawsContent(false)
+ , contentsOpaque(false)
+ , backfaceVisibility(false)
+ , visible(true)
+ , dirty(true)
+ , tiled(false)
+ , hasSurfaceDescendants(false)
+ {
+ }
+ };
+
+ State m_state;
+ TextureMapperCache* m_cache;
+};
+
+}
+#endif // TextureMapperNode_h
diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h
new file mode 100644
index 0000000..2a38b90
--- /dev/null
+++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef TextureMapperPlatformLayer_h
+#define TextureMapperPlatformLayer_h
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntRect;
+class IntSize;
+class TextureMapper;
+class TransformationMatrix;
+
+
+// Glue layer to connect the texmap layer to the platform specific container.
+class TextureMapperLayerClient {
+public:
+ virtual ~TextureMapperLayerClient() {}
+ virtual void setNeedsDisplay() = 0;
+ virtual void setNeedsDisplayInRect(const IntRect& rect) = 0;
+ virtual void setSizeChanged(const IntSize&) = 0;
+ virtual TextureMapper* textureMapper() = 0;
+};
+
+class TextureMapperPlatformLayer {
+public:
+ enum Type {
+ ContentLayer,
+ VideoLayer
+ };
+
+ virtual Type layerType() const = 0;
+ virtual ~TextureMapperPlatformLayer() {}
+};
+
+class TextureMapperContentLayer : public TextureMapperPlatformLayer {
+public:
+ struct PaintOptions {
+ IntRect visibleRect;
+ IntRect targetRect;
+ IntSize viewportSize;
+ TransformationMatrix transform;
+ float opacity;
+ };
+
+ virtual void setPlatformLayerClient(TextureMapperLayerClient*) = 0;
+ virtual void paint(TextureMapper*, const PaintOptions&) {}
+ virtual IntSize size() const = 0;
+ virtual Type layerType() const { return ContentLayer; }
+};
+
+#if ENABLE(VIDEO)
+class TextureMapperVideoLayer : public TextureMapperPlatformLayer {
+public:
+ virtual void paint(GraphicsContext*) = 0;
+ virtual Type layerType() const { return VideoLayer; }
+};
+#endif
+
+}
+
+#endif // TextureMapperPlatformLayer_h
diff --git a/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp b/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp
new file mode 100644
index 0000000..f275526
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * 2010 Dirk Schulze <krit@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+
+#include "FloatConversion.h"
+#include "FloatQuad.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+static void affineTransformDecompose(const AffineTransform& matrix, double sr[9])
+{
+ AffineTransform m(matrix);
+
+ // Compute scaling factors
+ double sx = matrix.xScale();
+ double sy = matrix.yScale();
+
+ // Compute cross product of transformed unit vectors. If negative,
+ // one axis was flipped.
+ if (m.a() * m.d() - m.c() * m.b() < 0.0) {
+ // Flip axis with minimum unit vector dot product
+ if (m.a() < m.d())
+ sx = -sx;
+ else
+ sy = -sy;
+ }
+
+ // Remove scale from matrix
+ m.scale(1.0 / sx, 1.0 / sy);
+
+ // Compute rotation
+ double angle = atan2(m.b(), m.a());
+
+ // Remove rotation from matrix
+ m.rotate(rad2deg(-angle));
+
+ // Return results
+ sr[0] = sx;
+ sr[1] = sy;
+ sr[2] = angle;
+ sr[3] = m.a();
+ sr[4] = m.b();
+ sr[5] = m.c();
+ sr[6] = m.d();
+ sr[7] = m.e();
+ sr[8] = m.f();
+}
+
+static void affineTransformCompose(AffineTransform& m, const double sr[9])
+{
+ m.setA(sr[3]);
+ m.setB(sr[4]);
+ m.setC(sr[5]);
+ m.setD(sr[6]);
+ m.setE(sr[7]);
+ m.setF(sr[8]);
+ m.rotate(rad2deg(sr[2]));
+ m.scale(sr[0], sr[1]);
+}
+
+AffineTransform::AffineTransform()
+{
+ setMatrix(1, 0, 0, 1, 0, 0);
+}
+
+AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
+{
+ setMatrix(a, b, c, d, e, f);
+}
+
+void AffineTransform::makeIdentity()
+{
+ setMatrix(1, 0, 0, 1, 0, 0);
+}
+
+void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f)
+{
+ m_transform[0] = a;
+ m_transform[1] = b;
+ m_transform[2] = c;
+ m_transform[3] = d;
+ m_transform[4] = e;
+ m_transform[5] = f;
+}
+
+bool AffineTransform::isIdentity() const
+{
+ return (m_transform[0] == 1 && m_transform[1] == 0
+ && m_transform[2] == 0 && m_transform[3] == 1
+ && m_transform[4] == 0 && m_transform[5] == 0);
+}
+
+double AffineTransform::xScale() const
+{
+ return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]);
+}
+
+double AffineTransform::yScale() const
+{
+ return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]);
+}
+
+double AffineTransform::det() const
+{
+ return m_transform[0] * m_transform[3] - m_transform[1] * m_transform[2];
+}
+
+bool AffineTransform::isInvertible() const
+{
+ return det() != 0.0;
+}
+
+AffineTransform AffineTransform::inverse() const
+{
+ double determinant = det();
+ if (determinant == 0.0)
+ return AffineTransform();
+
+ AffineTransform result;
+ if (isIdentityOrTranslation()) {
+ result.m_transform[4] = -m_transform[4];
+ result.m_transform[5] = -m_transform[5];
+ return result;
+ }
+
+ result.m_transform[0] = m_transform[3] / determinant;
+ result.m_transform[1] = -m_transform[1] / determinant;
+ result.m_transform[2] = -m_transform[2] / determinant;
+ result.m_transform[3] = m_transform[0] / determinant;
+ result.m_transform[4] = (m_transform[2] * m_transform[5]
+ - m_transform[3] * m_transform[4]) / determinant;
+ result.m_transform[5] = (m_transform[1] * m_transform[4]
+ - m_transform[0] * m_transform[5]) / determinant;
+
+ return result;
+}
+
+AffineTransform& AffineTransform::multiply(const AffineTransform& other)
+{
+ return (*this) *= other;
+}
+
+AffineTransform& AffineTransform::multLeft(const AffineTransform& other)
+{
+ AffineTransform trans;
+
+ trans.m_transform[0] = other.m_transform[0] * m_transform[0] + other.m_transform[1] * m_transform[2];
+ trans.m_transform[1] = other.m_transform[0] * m_transform[1] + other.m_transform[1] * m_transform[3];
+ trans.m_transform[2] = other.m_transform[2] * m_transform[0] + other.m_transform[3] * m_transform[2];
+ trans.m_transform[3] = other.m_transform[2] * m_transform[1] + other.m_transform[3] * m_transform[3];
+ trans.m_transform[4] = other.m_transform[4] * m_transform[0] + other.m_transform[5] * m_transform[2] + m_transform[4];
+ trans.m_transform[5] = other.m_transform[4] * m_transform[1] + other.m_transform[5] * m_transform[3] + m_transform[5];
+
+ setMatrix(trans.m_transform);
+ return *this;
+}
+
+AffineTransform& AffineTransform::rotate(double a)
+{
+ // angle is in degree. Switch to radian
+ a = deg2rad(a);
+ double cosAngle = cos(a);
+ double sinAngle = sin(a);
+ AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
+
+ multLeft(rot);
+ return *this;
+}
+
+AffineTransform& AffineTransform::scale(double s)
+{
+ return scale(s, s);
+}
+
+AffineTransform& AffineTransform::scale(double sx, double sy)
+{
+ m_transform[0] *= sx;
+ m_transform[1] *= sx;
+ m_transform[2] *= sy;
+ m_transform[3] *= sy;
+ return *this;
+}
+
+// *this = *this * translation
+AffineTransform& AffineTransform::translate(double tx, double ty)
+{
+ if (isIdentityOrTranslation()) {
+ m_transform[4] += tx;
+ m_transform[5] += ty;
+ return *this;
+ }
+
+ m_transform[4] += tx * m_transform[0] + ty * m_transform[2];
+ m_transform[5] += tx * m_transform[1] + ty * m_transform[3];
+ return *this;
+}
+
+// *this = translation * *this
+AffineTransform& AffineTransform::translateRight(double tx, double ty)
+{
+ m_transform[4] += tx;
+ m_transform[5] += ty;
+ return *this;
+}
+
+AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
+{
+ return scale(sx, sy);
+}
+
+AffineTransform& AffineTransform::rotateFromVector(double x, double y)
+{
+ return rotate(rad2deg(atan2(y, x)));
+}
+
+AffineTransform& AffineTransform::flipX()
+{
+ return scale(-1, 1);
+}
+
+AffineTransform& AffineTransform::flipY()
+{
+ return scale(1, -1);
+}
+
+AffineTransform& AffineTransform::shear(double sx, double sy)
+{
+ double a = m_transform[0];
+ double b = m_transform[1];
+
+ m_transform[0] += sy * m_transform[2];
+ m_transform[1] += sy * m_transform[3];
+ m_transform[2] += sx * a;
+ m_transform[3] += sx * b;
+
+ return *this;
+}
+
+AffineTransform& AffineTransform::skew(double angleX, double angleY)
+{
+ return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
+}
+
+AffineTransform& AffineTransform::skewX(double angle)
+{
+ return shear(tan(deg2rad(angle)), 0);
+}
+
+AffineTransform& AffineTransform::skewY(double angle)
+{
+ return shear(0, tan(deg2rad(angle)));
+}
+
+AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
+{
+ AffineTransform transform;
+ transform.translate(dest.x() - source.x(), dest.y() - source.y());
+ transform.scale(dest.width() / source.width(), dest.height() / source.height());
+ return transform;
+}
+
+void AffineTransform::map(double x, double y, double& x2, double& y2) const
+{
+ x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]);
+ y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]);
+}
+
+IntPoint AffineTransform::mapPoint(const IntPoint& point) const
+{
+ double x2, y2;
+ map(point.x(), point.y(), x2, y2);
+
+ // Round the point.
+ return IntPoint(lround(x2), lround(y2));
+}
+
+FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
+{
+ double x2, y2;
+ map(point.x(), point.y(), x2, y2);
+
+ return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
+}
+
+IntRect AffineTransform::mapRect(const IntRect &rect) const
+{
+ return enclosingIntRect(mapRect(FloatRect(rect)));
+}
+
+FloatRect AffineTransform::mapRect(const FloatRect& rect) const
+{
+ if (isIdentityOrTranslation()) {
+ FloatRect mappedRect(rect);
+ mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
+ return mappedRect;
+ }
+
+ FloatQuad result;
+ result.setP1(mapPoint(rect.location()));
+ result.setP2(mapPoint(FloatPoint(rect.right(), rect.y())));
+ result.setP3(mapPoint(FloatPoint(rect.right(), rect.bottom())));
+ result.setP4(mapPoint(FloatPoint(rect.x(), rect.bottom())));
+ return result.boundingBox();
+}
+
+FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const
+{
+ if (isIdentityOrTranslation()) {
+ FloatQuad mappedQuad(q);
+ mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
+ return mappedQuad;
+ }
+
+ FloatQuad result;
+ result.setP1(mapPoint(q.p1()));
+ result.setP2(mapPoint(q.p2()));
+ result.setP3(mapPoint(q.p3()));
+ result.setP4(mapPoint(q.p4()));
+ return result;
+}
+
+void AffineTransform::blend(const AffineTransform& from, double progress)
+{
+ double srA[9], srB[9];
+
+ affineTransformDecompose(from, srA);
+ affineTransformDecompose(*this, srB);
+
+ // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
+ if ((srA[0] < 0 && srB[1] < 0) || (srA[1] < 0 && srB[0] < 0)) {
+ srA[0] = -srA[0];
+ srA[1] = -srA[1];
+ srA[2] += srA[2] < 0 ? piDouble : -piDouble;
+ }
+
+ // Don't rotate the long way around.
+ srA[2] = fmod(srA[2], 2.0 * piDouble);
+ srB[2] = fmod(srB[2], 2.0 * piDouble);
+
+ if (fabs(srA[2] - srB[2]) > piDouble) {
+ if (srA[2] > srB[2])
+ srA[2] -= piDouble * 2.0;
+ else
+ srB[2] -= piDouble * 2.0;
+ }
+
+ for (int i = 0; i < 9; i++)
+ srA[i] = srA[i] + progress * (srB[i] - srA[i]);
+
+ affineTransformCompose(*this, srA);
+}
+
+TransformationMatrix AffineTransform::toTransformationMatrix() const
+{
+ return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2],
+ m_transform[3], m_transform[4], m_transform[5]);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/transforms/AffineTransform.h b/Source/WebCore/platform/graphics/transforms/AffineTransform.h
new file mode 100644
index 0000000..baee102
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * 2010 Dirk Schulze <krit@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 AffineTransform_h
+#define AffineTransform_h
+
+#include "TransformationMatrix.h"
+
+#include <string.h> // for memcpy
+#include <wtf/FastAllocBase.h>
+
+#if PLATFORM(CG)
+#include <CoreGraphics/CGAffineTransform.h>
+#elif PLATFORM(CAIRO)
+#include <cairo.h>
+#elif PLATFORM(OPENVG)
+#include "VGUtils.h"
+#elif PLATFORM(QT)
+#include <QTransform>
+#elif PLATFORM(SKIA)
+#include <SkMatrix.h>
+#elif PLATFORM(WX) && USE(WXGC)
+#include <wx/graphics.h>
+#endif
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatQuad;
+class FloatRect;
+class IntPoint;
+class IntRect;
+class TransformationMatrix;
+
+class AffineTransform : public FastAllocBase {
+public:
+ typedef double Transform[6];
+
+ AffineTransform();
+ AffineTransform(double a, double b, double c, double d, double e, double f);
+
+ void setMatrix(double a, double b, double c, double d, double e, double f);
+
+ void map(double x, double y, double& x2, double& y2) const;
+
+ // Rounds the mapped point to the nearest integer value.
+ IntPoint mapPoint(const IntPoint&) const;
+
+ FloatPoint mapPoint(const FloatPoint&) const;
+
+ // Rounds the resulting mapped rectangle out. This is helpful for bounding
+ // box computations but may not be what is wanted in other contexts.
+ IntRect mapRect(const IntRect&) const;
+
+ FloatRect mapRect(const FloatRect&) const;
+ FloatQuad mapQuad(const FloatQuad&) const;
+
+ bool isIdentity() const;
+
+ double a() const { return m_transform[0]; }
+ void setA(double a) { m_transform[0] = a; }
+ double b() const { return m_transform[1]; }
+ void setB(double b) { m_transform[1] = b; }
+ double c() const { return m_transform[2]; }
+ void setC(double c) { m_transform[2] = c; }
+ double d() const { return m_transform[3]; }
+ void setD(double d) { m_transform[3] = d; }
+ double e() const { return m_transform[4]; }
+ void setE(double e) { m_transform[4] = e; }
+ double f() const { return m_transform[5]; }
+ void setF(double f) { m_transform[5] = f; }
+
+ void makeIdentity();
+
+ AffineTransform& multiply(const AffineTransform&);
+ AffineTransform& multLeft(const AffineTransform&);
+ AffineTransform& scale(double);
+ AffineTransform& scale(double sx, double sy);
+ AffineTransform& scaleNonUniform(double sx, double sy);
+ AffineTransform& rotate(double d);
+ AffineTransform& rotateFromVector(double x, double y);
+ AffineTransform& translate(double tx, double ty);
+ AffineTransform& translateRight(double tx, double ty);
+ AffineTransform& shear(double sx, double sy);
+ AffineTransform& flipX();
+ AffineTransform& flipY();
+ AffineTransform& skew(double angleX, double angleY);
+ AffineTransform& skewX(double angle);
+ AffineTransform& skewY(double angle);
+
+ double xScale() const;
+ double yScale() const;
+
+ double det() const;
+ bool isInvertible() const;
+ AffineTransform inverse() const;
+
+ void blend(const AffineTransform& from, double progress);
+
+ TransformationMatrix toTransformationMatrix() const;
+
+ bool isIdentityOrTranslation() const
+ {
+ return m_transform[0] == 1 && m_transform[1] == 0 && m_transform[2] == 0 && m_transform[3] == 1;
+ }
+
+ bool isIdentityOrTranslationOrFlipped() const
+ {
+ return m_transform[0] == 1 && m_transform[1] == 0 && m_transform[2] == 0 && (m_transform[3] == 1 || m_transform[3] == -1);
+ }
+
+ bool operator== (const AffineTransform& m2) const
+ {
+ return (m_transform[0] == m2.m_transform[0]
+ && m_transform[1] == m2.m_transform[1]
+ && m_transform[2] == m2.m_transform[2]
+ && m_transform[3] == m2.m_transform[3]
+ && m_transform[4] == m2.m_transform[4]
+ && m_transform[5] == m2.m_transform[5]);
+ }
+
+ bool operator!=(const AffineTransform& other) const { return !(*this == other); }
+
+ // *this = *this * t (i.e., a multRight)
+ AffineTransform& operator*=(const AffineTransform& t)
+ {
+ *this = *this * t;
+ return *this;
+ }
+
+ // result = *this * t (i.e., a multRight)
+ AffineTransform operator*(const AffineTransform& t) const
+ {
+ AffineTransform result = t;
+ result.multLeft(*this);
+ return result;
+ }
+
+#if PLATFORM(CG)
+ operator CGAffineTransform() const;
+#elif PLATFORM(CAIRO)
+ operator cairo_matrix_t() const;
+#elif PLATFORM(OPENVG)
+ operator VGMatrix() const;
+#elif PLATFORM(QT)
+ operator QTransform() const;
+#elif PLATFORM(SKIA)
+ operator SkMatrix() const;
+#elif PLATFORM(WX) && USE(WXGC)
+ operator wxGraphicsMatrix() const;
+#endif
+
+private:
+ void setMatrix(const Transform m)
+ {
+ if (m && m != m_transform)
+ memcpy(m_transform, m, sizeof(Transform));
+ }
+
+ Transform m_transform;
+};
+
+AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/transforms/IdentityTransformOperation.h b/Source/WebCore/platform/graphics/transforms/IdentityTransformOperation.h
new file mode 100644
index 0000000..347737c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/IdentityTransformOperation.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef IdentityTransformOperation_h
+#define IdentityTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class IdentityTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<IdentityTransformOperation> create()
+ {
+ return adoptRef(new IdentityTransformOperation());
+ }
+
+private:
+ virtual bool isIdentity() const { return true; }
+ virtual OperationType getOperationType() const { return IDENTITY; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == IDENTITY; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ return isSameType(o);
+ }
+
+ virtual bool apply(TransformationMatrix&, const IntSize&) const
+ {
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation*, double, bool = false)
+ {
+ return this;
+ }
+
+ IdentityTransformOperation()
+ {
+ }
+
+};
+
+} // namespace WebCore
+
+#endif // IdentityTransformOperation_h
diff --git a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp
new file mode 100644
index 0000000..230be3c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Matrix3DTransformOperation.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> Matrix3DTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ // Convert the TransformOperations into matrices
+ IntSize size;
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ if (from)
+ from->apply(fromT, size);
+
+ apply(toT, size);
+
+ if (blendToIdentity)
+ std::swap(fromT, toT);
+
+ toT.blend(fromT, progress);
+ return Matrix3DTransformOperation::create(toT);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h
new file mode 100644
index 0000000..0a0aaf0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 Matrix3DTransformOperation_h
+#define Matrix3DTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class Matrix3DTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<Matrix3DTransformOperation> create(const TransformationMatrix& matrix)
+ {
+ return adoptRef(new Matrix3DTransformOperation(matrix));
+ }
+
+ TransformationMatrix matrix() const {return m_matrix; }
+
+private:
+ virtual bool isIdentity() const { return m_matrix.isIdentity(); }
+
+ virtual OperationType getOperationType() const { return MATRIX_3D; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX_3D; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const Matrix3DTransformOperation* m = static_cast<const Matrix3DTransformOperation*>(&o);
+ return m_matrix == m->m_matrix;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.multLeft(TransformationMatrix(m_matrix));
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ Matrix3DTransformOperation(const TransformationMatrix& mat)
+ {
+ m_matrix = mat;
+ }
+
+ TransformationMatrix m_matrix;
+};
+
+} // namespace WebCore
+
+#endif // Matrix3DTransformOperation_h
diff --git a/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
new file mode 100644
index 0000000..0eaccea
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "MatrixTransformOperation.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ // convert the TransformOperations into matrices
+ IntSize size;
+ TransformationMatrix fromT;
+ TransformationMatrix toT(m_a, m_b, m_c, m_d, m_e, m_f);
+ if (from) {
+ const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(from);
+ fromT.setMatrix(m->m_a, m->m_b, m->m_c, m->m_d, m->m_e, m->m_f);
+ }
+
+ if (blendToIdentity)
+ std::swap(fromT, toT);
+
+ toT.blend(fromT, progress);
+ return MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f());
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
new file mode 100644
index 0000000..fd9b27e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MatrixTransformOperation_h
+#define MatrixTransformOperation_h
+
+#include "TransformOperation.h"
+#include "TransformationMatrix.h"
+
+namespace WebCore {
+
+class MatrixTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<MatrixTransformOperation> create(double a, double b, double c, double d, double e, double f)
+ {
+ return adoptRef(new MatrixTransformOperation(a, b, c, d, e, f));
+ }
+
+ static PassRefPtr<MatrixTransformOperation> create(const TransformationMatrix& t)
+ {
+ return adoptRef(new MatrixTransformOperation(t));
+ }
+
+ TransformationMatrix matrix() const { return TransformationMatrix(m_a, m_b, m_c, m_d, m_e, m_f); }
+
+private:
+ virtual bool isIdentity() const { return m_a == 1 && m_b == 0 && m_c == 0 && m_d == 1 && m_e == 0 && m_f == 0; }
+
+ virtual OperationType getOperationType() const { return MATRIX; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+
+ const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(&o);
+ return m_a == m->m_a && m_b == m->m_b && m_c == m->m_c && m_d == m->m_d && m_e == m->m_e && m_f == m->m_f;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ TransformationMatrix matrix(m_a, m_b, m_c, m_d, m_e, m_f);
+ transform.multLeft(TransformationMatrix(matrix));
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ MatrixTransformOperation(double a, double b, double c, double d, double e, double f)
+ : m_a(a)
+ , m_b(b)
+ , m_c(c)
+ , m_d(d)
+ , m_e(e)
+ , m_f(f)
+ {
+ }
+
+ MatrixTransformOperation(const TransformationMatrix& t)
+ : m_a(t.a())
+ , m_b(t.b())
+ , m_c(t.c())
+ , m_d(t.d())
+ , m_e(t.e())
+ , m_f(t.f())
+ {
+ }
+
+ double m_a;
+ double m_b;
+ double m_c;
+ double m_d;
+ double m_e;
+ double m_f;
+};
+
+} // namespace WebCore
+
+#endif // MatrixTransformOperation_h
diff --git a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp
new file mode 100644
index 0000000..9fd03a1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "PerspectiveTransformOperation.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> PerspectiveTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return PerspectiveTransformOperation::create(m_p + (1. - m_p) * progress);
+
+ const PerspectiveTransformOperation* fromOp = static_cast<const PerspectiveTransformOperation*>(from);
+ double fromP = fromOp ? fromOp->m_p : 0;
+ double toP = m_p;
+
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ fromT.applyPerspective(fromP);
+ toT.applyPerspective(toP);
+ toT.blend(fromT, progress);
+ TransformationMatrix::DecomposedType decomp;
+ toT.decompose(decomp);
+
+ return PerspectiveTransformOperation::create(decomp.perspectiveZ ? -1.0 / decomp.perspectiveZ : 0.0);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h
new file mode 100644
index 0000000..834cc83
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 PerspectiveTransformOperation_h
+#define PerspectiveTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class PerspectiveTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<PerspectiveTransformOperation> create(double p)
+ {
+ return adoptRef(new PerspectiveTransformOperation(p));
+ }
+
+ double perspective() const { return m_p; }
+
+private:
+ virtual bool isIdentity() const { return m_p == 0; }
+ virtual OperationType getOperationType() const { return PERSPECTIVE; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == PERSPECTIVE; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const PerspectiveTransformOperation* p = static_cast<const PerspectiveTransformOperation*>(&o);
+ return m_p == p->m_p;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.applyPerspective(m_p);
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ PerspectiveTransformOperation(double p)
+ : m_p(p)
+ {
+ }
+
+ double m_p;
+};
+
+} // namespace WebCore
+
+#endif // PerspectiveTransformOperation_h
diff --git a/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
new file mode 100644
index 0000000..919d174
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "RotateTransformOperation.h"
+
+#include <algorithm>
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return RotateTransformOperation::create(m_x, m_y, m_z, m_angle - m_angle * progress, m_type);
+
+ const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from);
+
+ // Optimize for single axis rotation
+ if (!fromOp || (fromOp->m_x == 0 && fromOp->m_y == 0 && fromOp->m_z == 1) ||
+ (fromOp->m_x == 0 && fromOp->m_y == 1 && fromOp->m_z == 0) ||
+ (fromOp->m_x == 1 && fromOp->m_y == 0 && fromOp->m_z == 0)) {
+ double fromAngle = fromOp ? fromOp->m_angle : 0;
+ return RotateTransformOperation::create(fromOp ? fromOp->m_x : m_x,
+ fromOp ? fromOp->m_y : m_y,
+ fromOp ? fromOp->m_z : m_z,
+ fromAngle + (m_angle - fromAngle) * progress, m_type);
+ }
+
+ const RotateTransformOperation* toOp = this;
+
+ // Create the 2 rotation matrices
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ fromT.rotate3d((float)(fromOp ? fromOp->m_x : 0),
+ (float)(fromOp ? fromOp->m_y : 0),
+ (float)(fromOp ? fromOp->m_z : 1),
+ (float)(fromOp ? fromOp->m_angle : 0));
+
+ toT.rotate3d((float)(toOp ? toOp->m_x : 0),
+ (float)(toOp ? toOp->m_y : 0),
+ (float)(toOp ? toOp->m_z : 1),
+ (float)(toOp ? toOp->m_angle : 0));
+
+ // Blend them
+ toT.blend(fromT, progress);
+
+ // Extract the result as a quaternion
+ TransformationMatrix::DecomposedType decomp;
+ toT.decompose(decomp);
+
+ // Convert that to Axis/Angle form
+ double x = -decomp.quaternionX;
+ double y = -decomp.quaternionY;
+ double z = -decomp.quaternionZ;
+ double length = sqrt(x * x + y * y + z * z);
+ double angle = 0;
+
+ if (length > 0.00001) {
+ x /= length;
+ y /= length;
+ z /= length;
+ angle = rad2deg(acos(decomp.quaternionW) * 2);
+ } else {
+ x = 0;
+ y = 0;
+ z = 1;
+ }
+ return RotateTransformOperation::create(x, y, z, angle, ROTATE_3D);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h b/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h
new file mode 100644
index 0000000..2acb002
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RotateTransformOperation_h
+#define RotateTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class RotateTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<RotateTransformOperation> create(double angle, OperationType type)
+ {
+ return adoptRef(new RotateTransformOperation(0, 0, 1, angle, type));
+ }
+
+ static PassRefPtr<RotateTransformOperation> create(double x, double y, double z, double angle, OperationType type)
+ {
+ return adoptRef(new RotateTransformOperation(x, y, z, angle, type));
+ }
+
+ double x() const { return m_x; }
+ double y() const { return m_y; }
+ double z() const { return m_z; }
+ double angle() const { return m_angle; }
+
+private:
+ virtual bool isIdentity() const { return m_angle == 0; }
+
+ virtual OperationType getOperationType() const { return m_type; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const RotateTransformOperation* r = static_cast<const RotateTransformOperation*>(&o);
+ return m_x == r->m_x && m_y == r->m_y && m_z == r->m_z && m_angle == r->m_angle;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize& /*borderBoxSize*/) const
+ {
+ transform.rotate3d(m_x, m_y, m_z, m_angle);
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ RotateTransformOperation(double x, double y, double z, double angle, OperationType type)
+ : m_x(x)
+ , m_y(y)
+ , m_z(z)
+ , m_angle(angle)
+ , m_type(type)
+ {
+ ASSERT(type == ROTATE_X || type == ROTATE_Y || type == ROTATE_Z || type == ROTATE_3D);
+ }
+
+ double m_x;
+ double m_y;
+ double m_z;
+ double m_angle;
+ OperationType m_type;
+};
+
+} // namespace WebCore
+
+#endif // RotateTransformOperation_h
diff --git a/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
new file mode 100644
index 0000000..45d119c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "ScaleTransformOperation.h"
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> ScaleTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return ScaleTransformOperation::create(m_x + (1. - m_x) * progress,
+ m_y + (1. - m_y) * progress,
+ m_z + (1. - m_z) * progress, m_type);
+
+ const ScaleTransformOperation* fromOp = static_cast<const ScaleTransformOperation*>(from);
+ double fromX = fromOp ? fromOp->m_x : 1.;
+ double fromY = fromOp ? fromOp->m_y : 1.;
+ double fromZ = fromOp ? fromOp->m_z : 1.;
+ return ScaleTransformOperation::create(fromX + (m_x - fromX) * progress,
+ fromY + (m_y - fromY) * progress,
+ fromZ + (m_z - fromZ) * progress, m_type);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h b/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
new file mode 100644
index 0000000..a87bb3b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ScaleTransformOperation_h
+#define ScaleTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class ScaleTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, OperationType type)
+ {
+ return adoptRef(new ScaleTransformOperation(sx, sy, 1, type));
+ }
+
+ static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, double sz, OperationType type)
+ {
+ return adoptRef(new ScaleTransformOperation(sx, sy, sz, type));
+ }
+
+ double x() const { return m_x; }
+ double y() const { return m_y; }
+ double z() const { return m_z; }
+
+private:
+ virtual bool isIdentity() const { return m_x == 1 && m_y == 1 && m_z == 1; }
+
+ virtual OperationType getOperationType() const { return m_type; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const ScaleTransformOperation* s = static_cast<const ScaleTransformOperation*>(&o);
+ return m_x == s->m_x && m_y == s->m_y && m_z == s->m_z;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.scale3d(m_x, m_y, m_z);
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ ScaleTransformOperation(double sx, double sy, double sz, OperationType type)
+ : m_x(sx)
+ , m_y(sy)
+ , m_z(sz)
+ , m_type(type)
+ {
+ ASSERT(type == SCALE_X || type == SCALE_Y || type == SCALE_Z || type == SCALE || type == SCALE_3D);
+ }
+
+ double m_x;
+ double m_y;
+ double m_z;
+ OperationType m_type;
+};
+
+} // namespace WebCore
+
+#endif // ScaleTransformOperation_h
diff --git a/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp
new file mode 100644
index 0000000..2a430e9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "SkewTransformOperation.h"
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> SkewTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return SkewTransformOperation::create(m_angleX - m_angleX * progress, m_angleY - m_angleY * progress, m_type);
+
+ const SkewTransformOperation* fromOp = static_cast<const SkewTransformOperation*>(from);
+ double fromAngleX = fromOp ? fromOp->m_angleX : 0;
+ double fromAngleY = fromOp ? fromOp->m_angleY : 0;
+ return SkewTransformOperation::create(fromAngleX + (m_angleX - fromAngleX) * progress, fromAngleY + (m_angleY - fromAngleY) * progress, m_type);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.h b/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.h
new file mode 100644
index 0000000..afe9a7b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SkewTransformOperation_h
+#define SkewTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class SkewTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<SkewTransformOperation> create(double angleX, double angleY, OperationType type)
+ {
+ return adoptRef(new SkewTransformOperation(angleX, angleY, type));
+ }
+
+ double angleX() const { return m_angleX; }
+ double angleY() const { return m_angleY; }
+
+private:
+ virtual bool isIdentity() const { return m_angleX == 0 && m_angleY == 0; }
+ virtual OperationType getOperationType() const { return m_type; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const SkewTransformOperation* s = static_cast<const SkewTransformOperation*>(&o);
+ return m_angleX == s->m_angleX && m_angleY == s->m_angleY;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.skew(m_angleX, m_angleY);
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ SkewTransformOperation(double angleX, double angleY, OperationType type)
+ : m_angleX(angleX)
+ , m_angleY(angleY)
+ , m_type(type)
+ {
+ }
+
+ double m_angleX;
+ double m_angleY;
+ OperationType m_type;
+};
+
+} // namespace WebCore
+
+#endif // SkewTransformOperation_h
diff --git a/Source/WebCore/platform/graphics/transforms/TransformOperation.h b/Source/WebCore/platform/graphics/transforms/TransformOperation.h
new file mode 100644
index 0000000..c610c4b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/TransformOperation.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TransformOperation_h
+#define TransformOperation_h
+
+#include "TransformationMatrix.h"
+#include "IntSize.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+// CSS Transforms (may become part of CSS3)
+
+class TransformOperation : public RefCounted<TransformOperation> {
+public:
+ enum OperationType {
+ SCALE_X, SCALE_Y, SCALE,
+ TRANSLATE_X, TRANSLATE_Y, TRANSLATE,
+ ROTATE,
+ ROTATE_Z = ROTATE,
+ SKEW_X, SKEW_Y, SKEW,
+ MATRIX,
+ SCALE_Z, SCALE_3D,
+ TRANSLATE_Z, TRANSLATE_3D,
+ ROTATE_X, ROTATE_Y, ROTATE_3D,
+ MATRIX_3D,
+ PERSPECTIVE,
+ IDENTITY, NONE
+ };
+
+ virtual ~TransformOperation() { }
+
+ virtual bool operator==(const TransformOperation&) const = 0;
+ bool operator!=(const TransformOperation& o) const { return !(*this == o); }
+
+ virtual bool isIdentity() const = 0;
+
+ // Return true if the borderBoxSize was used in the computation, false otherwise.
+ virtual bool apply(TransformationMatrix&, const IntSize& borderBoxSize) const = 0;
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false) = 0;
+
+ virtual OperationType getOperationType() const = 0;
+ virtual bool isSameType(const TransformOperation&) const { return false; }
+
+ bool is3DOperation() const
+ {
+ OperationType opType = getOperationType();
+ return opType == SCALE_Z ||
+ opType == SCALE_3D ||
+ opType == TRANSLATE_Z ||
+ opType == TRANSLATE_3D ||
+ opType == ROTATE_X ||
+ opType == ROTATE_Y ||
+ opType == ROTATE_3D ||
+ opType == MATRIX_3D ||
+ opType == PERSPECTIVE;
+ }
+};
+
+} // namespace WebCore
+
+#endif // TransformOperation_h
diff --git a/Source/WebCore/platform/graphics/transforms/TransformOperations.cpp b/Source/WebCore/platform/graphics/transforms/TransformOperations.cpp
new file mode 100644
index 0000000..3d71480
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/TransformOperations.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "TransformOperations.h"
+
+#include "IdentityTransformOperation.h"
+
+namespace WebCore {
+
+TransformOperations::TransformOperations(bool makeIdentity)
+{
+ if (makeIdentity)
+ m_operations.append(IdentityTransformOperation::create());
+}
+
+bool TransformOperations::operator==(const TransformOperations& o) const
+{
+ if (m_operations.size() != o.m_operations.size())
+ return false;
+
+ unsigned s = m_operations.size();
+ for (unsigned i = 0; i < s; i++) {
+ if (*m_operations[i] != *o.m_operations[i])
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/transforms/TransformOperations.h b/Source/WebCore/platform/graphics/transforms/TransformOperations.h
new file mode 100644
index 0000000..c0da377
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/TransformOperations.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TransformOperations_h
+#define TransformOperations_h
+
+#include "TransformOperation.h"
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class TransformOperations : public FastAllocBase {
+public:
+ TransformOperations(bool makeIdentity = false);
+
+ bool operator==(const TransformOperations& o) const;
+ bool operator!=(const TransformOperations& o) const
+ {
+ return !(*this == o);
+ }
+
+ void apply(const IntSize& sz, TransformationMatrix& t) const
+ {
+ for (unsigned i = 0; i < m_operations.size(); ++i)
+ m_operations[i]->apply(t, sz);
+ }
+
+ // Return true if any of the operation types are 3D operation types (even if the
+ // values describe affine transforms)
+ bool has3DOperation() const
+ {
+ for (unsigned i = 0; i < m_operations.size(); ++i)
+ if (m_operations[i]->is3DOperation())
+ return true;
+ return false;
+ }
+
+ void clear()
+ {
+ m_operations.clear();
+ }
+
+ Vector<RefPtr<TransformOperation> >& operations() { return m_operations; }
+ const Vector<RefPtr<TransformOperation> >& operations() const { return m_operations; }
+
+ size_t size() const { return m_operations.size(); }
+ const TransformOperation* at(size_t index) const { return index < m_operations.size() ? m_operations.at(index).get() : 0; }
+
+private:
+ Vector<RefPtr<TransformOperation> > m_operations;
+};
+
+} // namespace WebCore
+
+#endif // TransformOperations_h
diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
new file mode 100644
index 0000000..10c7f70
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
@@ -0,0 +1,1132 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "TransformationMatrix.h"
+
+#include "FloatPoint3D.h"
+#include "FloatRect.h"
+#include "FloatQuad.h"
+#include "IntRect.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+//
+// Supporting Math Functions
+//
+// This is a set of function from various places (attributed inline) to do things like
+// inversion and decomposition of a 4x4 matrix. They are used throughout the code
+//
+
+//
+// Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.
+
+// EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code
+// as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial
+// or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there
+// are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or
+// webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes
+// with no guarantee.
+
+// A Note About row-major vs. column major matrixes
+//
+// The clients of this class (CSSMatrix and SVGMatrix) assume a column-major ordering.
+// That means that when the matrix is initialized with 16 values, the first 4 values
+// go in the 4 rows of the first column, etc. And in the dereferencing calls, the first
+// digit is the column (e.g., m23() is column 2 row 3). Because C++ uses row-major arrays
+// the internal matrix is stored in row-major order, so m[2][0] means row 2, column 0. This
+// has no bearing on how the matrix is viewed on the outside, since all access is done
+// with function calls. But it does help make the code more clear if you know that.
+//
+// FIXME: Multiply calls are named for what they do in the internal, row-major world.
+// multLeft is actually a multRight in a column-major world, and multiply is a multLeft
+// in a column-major world. For now I've left it that way to avoid too many confusing
+// changes to the code. In particular AffineTransform uses these same terms for the
+// opposite operations. So we have to be VERY careful when we change them.
+
+typedef double Vector4[4];
+typedef double Vector3[3];
+
+const double SMALL_NUMBER = 1.e-8;
+
+// inverse(original_matrix, inverse_matrix)
+//
+// calculate the inverse of a 4x4 matrix
+//
+// -1
+// A = ___1__ adjoint A
+// det A
+
+// double = determinant2x2(double a, double b, double c, double d)
+//
+// calculate the determinant of a 2x2 matrix.
+
+static double determinant2x2(double a, double b, double c, double d)
+{
+ return a * d - b * c;
+}
+
+// double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
+//
+// Calculate the determinant of a 3x3 matrix
+// in the form
+//
+// | a1, b1, c1 |
+// | a2, b2, c2 |
+// | a3, b3, c3 |
+
+static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3)
+{
+ return a1 * determinant2x2(b2, b3, c2, c3)
+ - b1 * determinant2x2(a2, a3, c2, c3)
+ + c1 * determinant2x2(a2, a3, b2, b3);
+}
+
+// double = determinant4x4(matrix)
+//
+// calculate the determinant of a 4x4 matrix.
+
+static double determinant4x4(const TransformationMatrix::Matrix4& m)
+{
+ // Assign to individual variable names to aid selecting
+ // correct elements
+
+ double a1 = m[0][0];
+ double b1 = m[0][1];
+ double c1 = m[0][2];
+ double d1 = m[0][3];
+
+ double a2 = m[1][0];
+ double b2 = m[1][1];
+ double c2 = m[1][2];
+ double d2 = m[1][3];
+
+ double a3 = m[2][0];
+ double b3 = m[2][1];
+ double c3 = m[2][2];
+ double d3 = m[2][3];
+
+ double a4 = m[3][0];
+ double b4 = m[3][1];
+ double c4 = m[3][2];
+ double d4 = m[3][3];
+
+ return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
+ - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
+ + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
+ - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
+}
+
+// adjoint( original_matrix, inverse_matrix )
+//
+// calculate the adjoint of a 4x4 matrix
+//
+// Let a denote the minor determinant of matrix A obtained by
+// ij
+//
+// deleting the ith row and jth column from A.
+//
+// i+j
+// Let b = (-1) a
+// ij ji
+//
+// The matrix B = (b ) is the adjoint of A
+// ij
+
+static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
+{
+ // Assign to individual variable names to aid
+ // selecting correct values
+ double a1 = matrix[0][0];
+ double b1 = matrix[0][1];
+ double c1 = matrix[0][2];
+ double d1 = matrix[0][3];
+
+ double a2 = matrix[1][0];
+ double b2 = matrix[1][1];
+ double c2 = matrix[1][2];
+ double d2 = matrix[1][3];
+
+ double a3 = matrix[2][0];
+ double b3 = matrix[2][1];
+ double c3 = matrix[2][2];
+ double d3 = matrix[2][3];
+
+ double a4 = matrix[3][0];
+ double b4 = matrix[3][1];
+ double c4 = matrix[3][2];
+ double d4 = matrix[3][3];
+
+ // Row column labeling reversed since we transpose rows & columns
+ result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
+ result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
+ result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
+ result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
+
+ result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
+ result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
+ result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
+ result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
+
+ result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
+ result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
+ result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
+ result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
+
+ result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
+ result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
+ result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
+ result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
+}
+
+// Returns false if the matrix is not invertible
+static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
+{
+ // Calculate the adjoint matrix
+ adjoint(matrix, result);
+
+ // Calculate the 4x4 determinant
+ // If the determinant is zero,
+ // then the inverse matrix is not unique.
+ double det = determinant4x4(matrix);
+
+ if (fabs(det) < SMALL_NUMBER)
+ return false;
+
+ // Scale the adjoint matrix to get the inverse
+
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ result[i][j] = result[i][j] / det;
+
+ return true;
+}
+
+// End of code adapted from Matrix Inversion by Richard Carling
+
+// Perform a decomposition on the passed matrix, return false if unsuccessful
+// From Graphics Gems: unmatrix.c
+
+// Transpose rotation portion of matrix a, return b
+static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b)
+{
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ b[i][j] = a[j][i];
+}
+
+// Multiply a homogeneous point by a matrix and return the transformed point
+static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result)
+{
+ result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) +
+ (p[2] * m[2][0]) + (p[3] * m[3][0]);
+ result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) +
+ (p[2] * m[2][1]) + (p[3] * m[3][1]);
+ result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) +
+ (p[2] * m[2][2]) + (p[3] * m[3][2]);
+ result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) +
+ (p[2] * m[2][3]) + (p[3] * m[3][3]);
+}
+
+static double v3Length(Vector3 a)
+{
+ return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2]));
+}
+
+static void v3Scale(Vector3 v, double desiredLength)
+{
+ double len = v3Length(v);
+ if (len != 0) {
+ double l = desiredLength / len;
+ v[0] *= l;
+ v[1] *= l;
+ v[2] *= l;
+ }
+}
+
+static double v3Dot(const Vector3 a, const Vector3 b)
+{
+ return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
+}
+
+// Make a linear combination of two vectors and return the result.
+// result = (a * ascl) + (b * bscl)
+static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl)
+{
+ result[0] = (ascl * a[0]) + (bscl * b[0]);
+ result[1] = (ascl * a[1]) + (bscl * b[1]);
+ result[2] = (ascl * a[2]) + (bscl * b[2]);
+}
+
+// Return the cross product result = a cross b */
+static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result)
+{
+ result[0] = (a[1] * b[2]) - (a[2] * b[1]);
+ result[1] = (a[2] * b[0]) - (a[0] * b[2]);
+ result[2] = (a[0] * b[1]) - (a[1] * b[0]);
+}
+
+static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result)
+{
+ TransformationMatrix::Matrix4 localMatrix;
+ memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4));
+
+ // Normalize the matrix.
+ if (localMatrix[3][3] == 0)
+ return false;
+
+ int i, j;
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++)
+ localMatrix[i][j] /= localMatrix[3][3];
+
+ // perspectiveMatrix is used to solve for perspective, but it also provides
+ // an easy way to test for singularity of the upper 3x3 component.
+ TransformationMatrix::Matrix4 perspectiveMatrix;
+ memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4));
+ for (i = 0; i < 3; i++)
+ perspectiveMatrix[i][3] = 0;
+ perspectiveMatrix[3][3] = 1;
+
+ if (determinant4x4(perspectiveMatrix) == 0)
+ return false;
+
+ // First, isolate perspective. This is the messiest.
+ if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) {
+ // rightHandSide is the right hand side of the equation.
+ Vector4 rightHandSide;
+ rightHandSide[0] = localMatrix[0][3];
+ rightHandSide[1] = localMatrix[1][3];
+ rightHandSide[2] = localMatrix[2][3];
+ rightHandSide[3] = localMatrix[3][3];
+
+ // Solve the equation by inverting perspectiveMatrix and multiplying
+ // rightHandSide by the inverse. (This is the easiest way, not
+ // necessarily the best.)
+ TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix;
+ inverse(perspectiveMatrix, inversePerspectiveMatrix);
+ transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);
+
+ Vector4 perspectivePoint;
+ v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
+
+ result.perspectiveX = perspectivePoint[0];
+ result.perspectiveY = perspectivePoint[1];
+ result.perspectiveZ = perspectivePoint[2];
+ result.perspectiveW = perspectivePoint[3];
+
+ // Clear the perspective partition
+ localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0;
+ localMatrix[3][3] = 1;
+ } else {
+ // No perspective.
+ result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0;
+ result.perspectiveW = 1;
+ }
+
+ // Next take care of translation (easy).
+ result.translateX = localMatrix[3][0];
+ localMatrix[3][0] = 0;
+ result.translateY = localMatrix[3][1];
+ localMatrix[3][1] = 0;
+ result.translateZ = localMatrix[3][2];
+ localMatrix[3][2] = 0;
+
+ // Vector4 type and functions need to be added to the common set.
+ Vector3 row[3], pdum3;
+
+ // Now get scale and shear.
+ for (i = 0; i < 3; i++) {
+ row[i][0] = localMatrix[i][0];
+ row[i][1] = localMatrix[i][1];
+ row[i][2] = localMatrix[i][2];
+ }
+
+ // Compute X scale factor and normalize first row.
+ result.scaleX = v3Length(row[0]);
+ v3Scale(row[0], 1.0);
+
+ // Compute XY shear factor and make 2nd row orthogonal to 1st.
+ result.skewXY = v3Dot(row[0], row[1]);
+ v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY);
+
+ // Now, compute Y scale and normalize 2nd row.
+ result.scaleY = v3Length(row[1]);
+ v3Scale(row[1], 1.0);
+ result.skewXY /= result.scaleY;
+
+ // Compute XZ and YZ shears, orthogonalize 3rd row.
+ result.skewXZ = v3Dot(row[0], row[2]);
+ v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ);
+ result.skewYZ = v3Dot(row[1], row[2]);
+ v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ);
+
+ // Next, get Z scale and normalize 3rd row.
+ result.scaleZ = v3Length(row[2]);
+ v3Scale(row[2], 1.0);
+ result.skewXZ /= result.scaleZ;
+ result.skewYZ /= result.scaleZ;
+
+ // At this point, the matrix (in rows[]) is orthonormal.
+ // Check for a coordinate system flip. If the determinant
+ // is -1, then negate the matrix and the scaling factors.
+ v3Cross(row[1], row[2], pdum3);
+ if (v3Dot(row[0], pdum3) < 0) {
+ for (i = 0; i < 3; i++) {
+ result.scaleX *= -1;
+ row[i][0] *= -1;
+ row[i][1] *= -1;
+ row[i][2] *= -1;
+ }
+ }
+
+ // Now, get the rotations out, as described in the gem.
+
+ // FIXME - Add the ability to return either quaternions (which are
+ // easier to recompose with) or Euler angles (rx, ry, rz), which
+ // are easier for authors to deal with. The latter will only be useful
+ // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
+ // will leave the Euler angle code here for now.
+
+ // ret.rotateY = asin(-row[0][2]);
+ // if (cos(ret.rotateY) != 0) {
+ // ret.rotateX = atan2(row[1][2], row[2][2]);
+ // ret.rotateZ = atan2(row[0][1], row[0][0]);
+ // } else {
+ // ret.rotateX = atan2(-row[2][0], row[1][1]);
+ // ret.rotateZ = 0;
+ // }
+
+ double s, t, x, y, z, w;
+
+ t = row[0][0] + row[1][1] + row[2][2] + 1.0;
+
+ if (t > 1e-4) {
+ s = 0.5 / sqrt(t);
+ w = 0.25 / s;
+ x = (row[2][1] - row[1][2]) * s;
+ y = (row[0][2] - row[2][0]) * s;
+ z = (row[1][0] - row[0][1]) * s;
+ } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) {
+ s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx
+ x = 0.25 * s;
+ y = (row[0][1] + row[1][0]) / s;
+ z = (row[0][2] + row[2][0]) / s;
+ w = (row[2][1] - row[1][2]) / s;
+ } else if (row[1][1] > row[2][2]) {
+ s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy
+ x = (row[0][1] + row[1][0]) / s;
+ y = 0.25 * s;
+ z = (row[1][2] + row[2][1]) / s;
+ w = (row[0][2] - row[2][0]) / s;
+ } else {
+ s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz
+ x = (row[0][2] + row[2][0]) / s;
+ y = (row[1][2] + row[2][1]) / s;
+ z = 0.25 * s;
+ w = (row[1][0] - row[0][1]) / s;
+ }
+
+ result.quaternionX = x;
+ result.quaternionY = y;
+ result.quaternionZ = z;
+ result.quaternionW = w;
+
+ return true;
+}
+
+// Perform a spherical linear interpolation between the two
+// passed quaternions with 0 <= t <= 1
+static void slerp(double qa[4], const double qb[4], double t)
+{
+ double ax, ay, az, aw;
+ double bx, by, bz, bw;
+ double cx, cy, cz, cw;
+ double angle;
+ double th, invth, scale, invscale;
+
+ ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3];
+ bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3];
+
+ angle = ax * bx + ay * by + az * bz + aw * bw;
+
+ if (angle < 0.0) {
+ ax = -ax; ay = -ay;
+ az = -az; aw = -aw;
+ angle = -angle;
+ }
+
+ if (angle + 1.0 > .05) {
+ if (1.0 - angle >= .05) {
+ th = acos (angle);
+ invth = 1.0 / sin (th);
+ scale = sin (th * (1.0 - t)) * invth;
+ invscale = sin (th * t) * invth;
+ } else {
+ scale = 1.0 - t;
+ invscale = t;
+ }
+ } else {
+ bx = -ay;
+ by = ax;
+ bz = -aw;
+ bw = az;
+ scale = sin(piDouble * (.5 - t));
+ invscale = sin (piDouble * t);
+ }
+
+ cx = ax * scale + bx * invscale;
+ cy = ay * scale + by * invscale;
+ cz = az * scale + bz * invscale;
+ cw = aw * scale + bw * invscale;
+
+ qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw;
+}
+
+// End of Supporting Math Functions
+
+TransformationMatrix& TransformationMatrix::scale(double s)
+{
+ return scaleNonUniform(s, s);
+}
+
+TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
+{
+ return rotate(rad2deg(atan2(y, x)));
+}
+
+TransformationMatrix& TransformationMatrix::flipX()
+{
+ return scaleNonUniform(-1.0f, 1.0f);
+}
+
+TransformationMatrix& TransformationMatrix::flipY()
+{
+ return scaleNonUniform(1.0f, -1.0f);
+}
+
+FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p) const
+{
+ // This is basically raytracing. We have a point in the destination
+ // plane with z=0, and we cast a ray parallel to the z-axis from that
+ // point to find the z-position at which it intersects the z=0 plane
+ // with the transform applied. Once we have that point we apply the
+ // inverse transform to find the corresponding point in the source
+ // space.
+ //
+ // Given a plane with normal Pn, and a ray starting at point R0 and
+ // with direction defined by the vector Rd, we can find the
+ // intersection point as a distance d from R0 in units of Rd by:
+ //
+ // d = -dot (Pn', R0) / dot (Pn', Rd)
+
+ double x = p.x();
+ double y = p.y();
+ double z = -(m13() * x + m23() * y + m43()) / m33();
+
+ double outX = x * m11() + y * m21() + z * m31() + m41();
+ double outY = x * m12() + y * m22() + z * m32() + m42();
+
+ double w = x * m14() + y * m24() + z * m34() + m44();
+ if (w != 1 && w != 0) {
+ outX /= w;
+ outY /= w;
+ }
+
+ return FloatPoint(static_cast<float>(outX), static_cast<float>(outY));
+}
+
+FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q) const
+{
+ FloatQuad projectedQuad;
+ projectedQuad.setP1(projectPoint(q.p1()));
+ projectedQuad.setP2(projectPoint(q.p2()));
+ projectedQuad.setP3(projectPoint(q.p3()));
+ projectedQuad.setP4(projectPoint(q.p4()));
+ return projectedQuad;
+}
+
+FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const
+{
+ if (isIdentityOrTranslation())
+ return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1]));
+
+ double x, y;
+ multVecMatrix(p.x(), p.y(), x, y);
+ return FloatPoint(static_cast<float>(x), static_cast<float>(y));
+}
+
+FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const
+{
+ if (isIdentityOrTranslation())
+ return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]),
+ p.y() + static_cast<float>(m_matrix[3][1]),
+ p.z() + static_cast<float>(m_matrix[3][2]));
+
+ double x, y, z;
+ multVecMatrix(p.x(), p.y(), p.z(), x, y, z);
+ return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
+}
+
+IntRect TransformationMatrix::mapRect(const IntRect &rect) const
+{
+ return enclosingIntRect(mapRect(FloatRect(rect)));
+}
+
+FloatRect TransformationMatrix::mapRect(const FloatRect& r) const
+{
+ if (isIdentityOrTranslation()) {
+ FloatRect mappedRect(r);
+ mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
+ return mappedRect;
+ }
+
+ FloatQuad resultQuad = mapQuad(FloatQuad(r));
+ return resultQuad.boundingBox();
+}
+
+FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const
+{
+ if (isIdentityOrTranslation()) {
+ FloatQuad mappedQuad(q);
+ mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
+ return mappedQuad;
+ }
+
+ FloatQuad result;
+ result.setP1(mapPoint(q.p1()));
+ result.setP2(mapPoint(q.p2()));
+ result.setP3(mapPoint(q.p3()));
+ result.setP4(mapPoint(q.p4()));
+ return result;
+}
+
+TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
+{
+ TransformationMatrix mat;
+ mat.m_matrix[0][0] = sx;
+ mat.m_matrix[1][1] = sy;
+
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz)
+{
+ TransformationMatrix mat;
+ mat.m_matrix[0][0] = sx;
+ mat.m_matrix[1][1] = sy;
+ mat.m_matrix[2][2] = sz;
+
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle)
+{
+ // angles are in degrees. Switch to radians
+ angle = deg2rad(angle);
+
+ angle /= 2.0f;
+ double sinA = sin(angle);
+ double cosA = cos(angle);
+ double sinA2 = sinA * sinA;
+
+ // normalize
+ double length = sqrt(x * x + y * y + z * z);
+ if (length == 0) {
+ // bad vector, just use something reasonable
+ x = 0;
+ y = 0;
+ z = 1;
+ } else if (length != 1) {
+ x /= length;
+ y /= length;
+ z /= length;
+ }
+
+ TransformationMatrix mat;
+
+ // optimize case where axis is along major axis
+ if (x == 1.0f && y == 0.0f && z == 0.0f) {
+ mat.m_matrix[0][0] = 1.0f;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = -2.0f * sinA * cosA;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ } else if (x == 0.0f && y == 1.0f && z == 0.0f) {
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ } else if (x == 0.0f && y == 0.0f && z == 1.0f) {
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 2.0f * sinA * cosA;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ } else {
+ double x2 = x*x;
+ double y2 = y*y;
+ double z2 = z*z;
+
+ mat.m_matrix[0][0] = 1.0f - 2.0f * (y2 + z2) * sinA2;
+ mat.m_matrix[0][1] = 2.0f * (x * y * sinA2 + z * sinA * cosA);
+ mat.m_matrix[0][2] = 2.0f * (x * z * sinA2 - y * sinA * cosA);
+ mat.m_matrix[1][0] = 2.0f * (y * x * sinA2 - z * sinA * cosA);
+ mat.m_matrix[1][1] = 1.0f - 2.0f * (z2 + x2) * sinA2;
+ mat.m_matrix[1][2] = 2.0f * (y * z * sinA2 + x * sinA * cosA);
+ mat.m_matrix[2][0] = 2.0f * (z * x * sinA2 + y * sinA * cosA);
+ mat.m_matrix[2][1] = 2.0f * (z * y * sinA2 - x * sinA * cosA);
+ mat.m_matrix[2][2] = 1.0f - 2.0f * (x2 + y2) * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ }
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz)
+{
+ // angles are in degrees. Switch to radians
+ rx = deg2rad(rx);
+ ry = deg2rad(ry);
+ rz = deg2rad(rz);
+
+ TransformationMatrix mat;
+
+ rz /= 2.0f;
+ double sinA = sin(rz);
+ double cosA = cos(rz);
+ double sinA2 = sinA * sinA;
+
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 2.0f * sinA * cosA;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+
+ TransformationMatrix rmat(mat);
+
+ ry /= 2.0f;
+ sinA = sin(ry);
+ cosA = cos(ry);
+ sinA2 = sinA * sinA;
+
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+
+ rmat.multLeft(mat);
+
+ rx /= 2.0f;
+ sinA = sin(rx);
+ cosA = cos(rx);
+ sinA2 = sinA * sinA;
+
+ mat.m_matrix[0][0] = 1.0f;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = -2.0f * sinA * cosA;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+
+ rmat.multLeft(mat);
+
+ multLeft(rmat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
+{
+ m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0];
+ m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1];
+ m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2];
+ m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3];
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz)
+{
+ m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0];
+ m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1];
+ m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2];
+ m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3];
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty)
+{
+ if (tx != 0) {
+ m_matrix[0][0] += m_matrix[0][3] * tx;
+ m_matrix[1][0] += m_matrix[1][3] * tx;
+ m_matrix[2][0] += m_matrix[2][3] * tx;
+ m_matrix[3][0] += m_matrix[3][3] * tx;
+ }
+
+ if (ty != 0) {
+ m_matrix[0][1] += m_matrix[0][3] * ty;
+ m_matrix[1][1] += m_matrix[1][3] * ty;
+ m_matrix[2][1] += m_matrix[2][3] * ty;
+ m_matrix[3][1] += m_matrix[3][3] * ty;
+ }
+
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz)
+{
+ translateRight(tx, ty);
+ if (tz != 0) {
+ m_matrix[0][2] += m_matrix[0][3] * tz;
+ m_matrix[1][2] += m_matrix[1][3] * tz;
+ m_matrix[2][2] += m_matrix[2][3] * tz;
+ m_matrix[3][2] += m_matrix[3][3] * tz;
+ }
+
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::skew(double sx, double sy)
+{
+ // angles are in degrees. Switch to radians
+ sx = deg2rad(sx);
+ sy = deg2rad(sy);
+
+ TransformationMatrix mat;
+ mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row
+ mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row
+
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::applyPerspective(double p)
+{
+ TransformationMatrix mat;
+ if (p != 0)
+ mat.m_matrix[2][3] = -1/p;
+
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, const FloatRect& to)
+{
+ ASSERT(!from.isEmpty());
+ return TransformationMatrix(to.width() / from.width(),
+ 0, 0,
+ to.height() / from.height(),
+ to.x() - from.x(),
+ to.y() - from.y());
+}
+
+//
+// *this = mat * *this
+//
+TransformationMatrix& TransformationMatrix::multLeft(const TransformationMatrix& mat)
+{
+ Matrix4 tmp;
+
+ tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0]
+ + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]);
+ tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1]
+ + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]);
+ tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2]
+ + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]);
+ tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3]
+ + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]);
+
+ tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0]
+ + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]);
+ tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1]
+ + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]);
+ tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2]
+ + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]);
+ tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3]
+ + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]);
+
+ tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0]
+ + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]);
+ tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1]
+ + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]);
+ tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2]
+ + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]);
+ tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3]
+ + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]);
+
+ tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0]
+ + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]);
+ tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1]
+ + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]);
+ tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2]
+ + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]);
+ tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3]
+ + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]);
+
+ setMatrix(tmp);
+ return *this;
+}
+
+void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const
+{
+ resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0];
+ resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1];
+ double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3];
+ if (w != 1 && w != 0) {
+ resultX /= w;
+ resultY /= w;
+ }
+}
+
+void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const
+{
+ resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
+ resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
+ resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2];
+ double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3];
+ if (w != 1 && w != 0) {
+ resultX /= w;
+ resultY /= w;
+ resultZ /= w;
+ }
+}
+
+bool TransformationMatrix::isInvertible() const
+{
+ if (isIdentityOrTranslation())
+ return true;
+
+ double det = WebCore::determinant4x4(m_matrix);
+
+ if (fabs(det) < SMALL_NUMBER)
+ return false;
+
+ return true;
+}
+
+TransformationMatrix TransformationMatrix::inverse() const
+{
+ if (isIdentityOrTranslation()) {
+ // identity matrix
+ if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0)
+ return TransformationMatrix();
+
+ // translation
+ return TransformationMatrix(1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1);
+ }
+
+ TransformationMatrix invMat;
+ bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix);
+ if (!inverted)
+ return TransformationMatrix();
+
+ return invMat;
+}
+
+void TransformationMatrix::makeAffine()
+{
+ m_matrix[0][2] = 0;
+ m_matrix[0][3] = 0;
+
+ m_matrix[1][2] = 0;
+ m_matrix[1][3] = 0;
+
+ m_matrix[2][0] = 0;
+ m_matrix[2][1] = 0;
+ m_matrix[2][2] = 1;
+ m_matrix[2][3] = 0;
+
+ m_matrix[3][2] = 0;
+ m_matrix[3][3] = 1;
+}
+
+AffineTransform TransformationMatrix::toAffineTransform() const
+{
+ return AffineTransform(m_matrix[0][0], m_matrix[0][1], m_matrix[1][0],
+ m_matrix[1][1], m_matrix[3][0], m_matrix[3][1]);
+}
+
+static inline void blendFloat(double& from, double to, double progress)
+{
+ if (from != to)
+ from = from + (to - from) * progress;
+}
+
+void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
+{
+ if (from.isIdentity() && isIdentity())
+ return;
+
+ // decompose
+ DecomposedType fromDecomp;
+ DecomposedType toDecomp;
+ from.decompose(fromDecomp);
+ decompose(toDecomp);
+
+ // interpolate
+ blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress);
+ blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress);
+ blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress);
+ blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress);
+ blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress);
+ blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress);
+ blendFloat(fromDecomp.translateX, toDecomp.translateX, progress);
+ blendFloat(fromDecomp.translateY, toDecomp.translateY, progress);
+ blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress);
+ blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress);
+ blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress);
+ blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress);
+ blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress);
+
+ slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress);
+
+ // recompose
+ recompose(fromDecomp);
+}
+
+bool TransformationMatrix::decompose(DecomposedType& decomp) const
+{
+ if (isIdentity()) {
+ memset(&decomp, 0, sizeof(decomp));
+ decomp.perspectiveW = 1;
+ decomp.scaleX = 1;
+ decomp.scaleY = 1;
+ decomp.scaleZ = 1;
+ }
+
+ if (!WebCore::decompose(m_matrix, decomp))
+ return false;
+ return true;
+}
+
+void TransformationMatrix::recompose(const DecomposedType& decomp)
+{
+ makeIdentity();
+
+ // first apply perspective
+ m_matrix[0][3] = (float) decomp.perspectiveX;
+ m_matrix[1][3] = (float) decomp.perspectiveY;
+ m_matrix[2][3] = (float) decomp.perspectiveZ;
+ m_matrix[3][3] = (float) decomp.perspectiveW;
+
+ // now translate
+ translate3d((float) decomp.translateX, (float) decomp.translateY, (float) decomp.translateZ);
+
+ // apply rotation
+ double xx = decomp.quaternionX * decomp.quaternionX;
+ double xy = decomp.quaternionX * decomp.quaternionY;
+ double xz = decomp.quaternionX * decomp.quaternionZ;
+ double xw = decomp.quaternionX * decomp.quaternionW;
+ double yy = decomp.quaternionY * decomp.quaternionY;
+ double yz = decomp.quaternionY * decomp.quaternionZ;
+ double yw = decomp.quaternionY * decomp.quaternionW;
+ double zz = decomp.quaternionZ * decomp.quaternionZ;
+ double zw = decomp.quaternionZ * decomp.quaternionW;
+
+ // Construct a composite rotation matrix from the quaternion values
+ TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0,
+ 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0,
+ 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0,
+ 0, 0, 0, 1);
+
+ multLeft(rotationMatrix);
+
+ // now apply skew
+ if (decomp.skewYZ) {
+ TransformationMatrix tmp;
+ tmp.setM32((float) decomp.skewYZ);
+ multLeft(tmp);
+ }
+
+ if (decomp.skewXZ) {
+ TransformationMatrix tmp;
+ tmp.setM31((float) decomp.skewXZ);
+ multLeft(tmp);
+ }
+
+ if (decomp.skewXY) {
+ TransformationMatrix tmp;
+ tmp.setM21((float) decomp.skewXY);
+ multLeft(tmp);
+ }
+
+ // finally, apply scale
+ scale3d((float) decomp.scaleX, (float) decomp.scaleY, (float) decomp.scaleZ);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h
new file mode 100644
index 0000000..f13bcc1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 TransformationMatrix_h
+#define TransformationMatrix_h
+
+#include "AffineTransform.h"
+#include "FloatPoint.h"
+#include "IntPoint.h"
+#include <string.h> //for memcpy
+#include <wtf/FastAllocBase.h>
+
+#if PLATFORM(CA)
+#include <QuartzCore/CATransform3D.h>
+#endif
+#if PLATFORM(CG)
+#include <CoreGraphics/CGAffineTransform.h>
+#elif PLATFORM(CAIRO)
+#include <cairo.h>
+#elif PLATFORM(OPENVG)
+#include "VGUtils.h"
+#elif PLATFORM(QT)
+#include <QTransform>
+#elif PLATFORM(SKIA)
+#include <SkMatrix.h>
+#elif PLATFORM(WX) && USE(WXGC)
+#include <wx/graphics.h>
+#endif
+
+#if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS)) || (PLATFORM(WX) && OS(WINDOWS))
+#if COMPILER(MINGW) && !COMPILER(MINGW64)
+typedef struct _XFORM XFORM;
+#else
+typedef struct tagXFORM XFORM;
+#endif
+#endif
+
+namespace WebCore {
+
+class AffineTransform;
+class IntRect;
+class FloatPoint3D;
+class FloatRect;
+class FloatQuad;
+
+class TransformationMatrix : public FastAllocBase {
+public:
+ typedef double Matrix4[4][4];
+
+ TransformationMatrix() { makeIdentity(); }
+ TransformationMatrix(const TransformationMatrix& t) { *this = t; }
+ TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); }
+ TransformationMatrix(double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44)
+ {
+ setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
+ }
+
+ void setMatrix(double a, double b, double c, double d, double e, double f)
+ {
+ m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0;
+ m_matrix[1][0] = c; m_matrix[1][1] = d; m_matrix[1][2] = 0; m_matrix[1][3] = 0;
+ m_matrix[2][0] = 0; m_matrix[2][1] = 0; m_matrix[2][2] = 1; m_matrix[2][3] = 0;
+ m_matrix[3][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1;
+ }
+
+ void setMatrix(double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44)
+ {
+ m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14;
+ m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24;
+ m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34;
+ m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44;
+ }
+
+ TransformationMatrix& operator =(const TransformationMatrix &t)
+ {
+ setMatrix(t.m_matrix);
+ return *this;
+ }
+
+ TransformationMatrix& makeIdentity()
+ {
+ setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ return *this;
+ }
+
+ bool isIdentity() const
+ {
+ return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 &&
+ m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 &&
+ m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 &&
+ m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1;
+ }
+
+ // This form preserves the double math from input to output
+ void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); }
+
+ // Map a 3D point through the transform, returning a 3D point.
+ FloatPoint3D mapPoint(const FloatPoint3D&) const;
+
+ // Map a 2D point through the transform, returning a 2D point.
+ // Note that this ignores the z component, effectively projecting the point into the z=0 plane.
+ FloatPoint mapPoint(const FloatPoint&) const;
+
+ // Like the version above, except that it rounds the mapped point to the nearest integer value.
+ IntPoint mapPoint(const IntPoint& p) const
+ {
+ return roundedIntPoint(mapPoint(FloatPoint(p)));
+ }
+
+ // If the matrix has 3D components, the z component of the result is
+ // dropped, effectively projecting the rect into the z=0 plane
+ FloatRect mapRect(const FloatRect&) const;
+
+ // Rounds the resulting mapped rectangle out. This is helpful for bounding
+ // box computations but may not be what is wanted in other contexts.
+ IntRect mapRect(const IntRect&) const;
+
+ // If the matrix has 3D components, the z component of the result is
+ // dropped, effectively projecting the quad into the z=0 plane
+ FloatQuad mapQuad(const FloatQuad&) const;
+
+ // Map a point on the z=0 plane into a point on
+ // the plane with with the transform applied, by extending
+ // a ray perpendicular to the source plane and computing
+ // the local x,y position of the point where that ray intersects
+ // with the destination plane.
+ FloatPoint projectPoint(const FloatPoint&) const;
+ // Projects the four corners of the quad
+ FloatQuad projectQuad(const FloatQuad&) const;
+
+ double m11() const { return m_matrix[0][0]; }
+ void setM11(double f) { m_matrix[0][0] = f; }
+ double m12() const { return m_matrix[0][1]; }
+ void setM12(double f) { m_matrix[0][1] = f; }
+ double m13() const { return m_matrix[0][2]; }
+ void setM13(double f) { m_matrix[0][2] = f; }
+ double m14() const { return m_matrix[0][3]; }
+ void setM14(double f) { m_matrix[0][3] = f; }
+ double m21() const { return m_matrix[1][0]; }
+ void setM21(double f) { m_matrix[1][0] = f; }
+ double m22() const { return m_matrix[1][1]; }
+ void setM22(double f) { m_matrix[1][1] = f; }
+ double m23() const { return m_matrix[1][2]; }
+ void setM23(double f) { m_matrix[1][2] = f; }
+ double m24() const { return m_matrix[1][3]; }
+ void setM24(double f) { m_matrix[1][3] = f; }
+ double m31() const { return m_matrix[2][0]; }
+ void setM31(double f) { m_matrix[2][0] = f; }
+ double m32() const { return m_matrix[2][1]; }
+ void setM32(double f) { m_matrix[2][1] = f; }
+ double m33() const { return m_matrix[2][2]; }
+ void setM33(double f) { m_matrix[2][2] = f; }
+ double m34() const { return m_matrix[2][3]; }
+ void setM34(double f) { m_matrix[2][3] = f; }
+ double m41() const { return m_matrix[3][0]; }
+ void setM41(double f) { m_matrix[3][0] = f; }
+ double m42() const { return m_matrix[3][1]; }
+ void setM42(double f) { m_matrix[3][1] = f; }
+ double m43() const { return m_matrix[3][2]; }
+ void setM43(double f) { m_matrix[3][2] = f; }
+ double m44() const { return m_matrix[3][3]; }
+ void setM44(double f) { m_matrix[3][3] = f; }
+
+ double a() const { return m_matrix[0][0]; }
+ void setA(double a) { m_matrix[0][0] = a; }
+
+ double b() const { return m_matrix[0][1]; }
+ void setB(double b) { m_matrix[0][1] = b; }
+
+ double c() const { return m_matrix[1][0]; }
+ void setC(double c) { m_matrix[1][0] = c; }
+
+ double d() const { return m_matrix[1][1]; }
+ void setD(double d) { m_matrix[1][1] = d; }
+
+ double e() const { return m_matrix[3][0]; }
+ void setE(double e) { m_matrix[3][0] = e; }
+
+ double f() const { return m_matrix[3][1]; }
+ void setF(double f) { m_matrix[3][1] = f; }
+
+ // this = this * mat
+ TransformationMatrix& multiply(const TransformationMatrix& t) { return *this *= t; }
+
+ // this = mat * this
+ TransformationMatrix& multLeft(const TransformationMatrix& mat);
+
+ TransformationMatrix& scale(double);
+ TransformationMatrix& scaleNonUniform(double sx, double sy);
+ TransformationMatrix& scale3d(double sx, double sy, double sz);
+
+ TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); }
+ TransformationMatrix& rotateFromVector(double x, double y);
+ TransformationMatrix& rotate3d(double rx, double ry, double rz);
+
+ // The vector (x,y,z) is normalized if it's not already. A vector of
+ // (0,0,0) uses a vector of (0,0,1).
+ TransformationMatrix& rotate3d(double x, double y, double z, double angle);
+
+ TransformationMatrix& translate(double tx, double ty);
+ TransformationMatrix& translate3d(double tx, double ty, double tz);
+
+ // translation added with a post-multiply
+ TransformationMatrix& translateRight(double tx, double ty);
+ TransformationMatrix& translateRight3d(double tx, double ty, double tz);
+
+ TransformationMatrix& flipX();
+ TransformationMatrix& flipY();
+ TransformationMatrix& skew(double angleX, double angleY);
+ TransformationMatrix& skewX(double angle) { return skew(angle, 0); }
+ TransformationMatrix& skewY(double angle) { return skew(0, angle); }
+
+ TransformationMatrix& applyPerspective(double p);
+ bool hasPerspective() const { return m_matrix[2][3] != 0.0f; }
+
+ // returns a transformation that maps a rect to a rect
+ static TransformationMatrix rectToRect(const FloatRect&, const FloatRect&);
+
+ bool isInvertible() const;
+
+ // This method returns the identity matrix if it is not invertible.
+ // Use isInvertible() before calling this if you need to know.
+ TransformationMatrix inverse() const;
+
+ // decompose the matrix into its component parts
+ typedef struct {
+ double scaleX, scaleY, scaleZ;
+ double skewXY, skewXZ, skewYZ;
+ double quaternionX, quaternionY, quaternionZ, quaternionW;
+ double translateX, translateY, translateZ;
+ double perspectiveX, perspectiveY, perspectiveZ, perspectiveW;
+ } DecomposedType;
+
+ bool decompose(DecomposedType& decomp) const;
+ void recompose(const DecomposedType& decomp);
+
+ void blend(const TransformationMatrix& from, double progress);
+
+ bool isAffine() const
+ {
+ return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 &&
+ m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1);
+ }
+
+ // Throw away the non-affine parts of the matrix (lossy!)
+ void makeAffine();
+
+ AffineTransform toAffineTransform() const;
+
+ bool operator==(const TransformationMatrix& m2) const
+ {
+ return (m_matrix[0][0] == m2.m_matrix[0][0] &&
+ m_matrix[0][1] == m2.m_matrix[0][1] &&
+ m_matrix[0][2] == m2.m_matrix[0][2] &&
+ m_matrix[0][3] == m2.m_matrix[0][3] &&
+ m_matrix[1][0] == m2.m_matrix[1][0] &&
+ m_matrix[1][1] == m2.m_matrix[1][1] &&
+ m_matrix[1][2] == m2.m_matrix[1][2] &&
+ m_matrix[1][3] == m2.m_matrix[1][3] &&
+ m_matrix[2][0] == m2.m_matrix[2][0] &&
+ m_matrix[2][1] == m2.m_matrix[2][1] &&
+ m_matrix[2][2] == m2.m_matrix[2][2] &&
+ m_matrix[2][3] == m2.m_matrix[2][3] &&
+ m_matrix[3][0] == m2.m_matrix[3][0] &&
+ m_matrix[3][1] == m2.m_matrix[3][1] &&
+ m_matrix[3][2] == m2.m_matrix[3][2] &&
+ m_matrix[3][3] == m2.m_matrix[3][3]);
+ }
+
+ bool operator!=(const TransformationMatrix& other) const { return !(*this == other); }
+
+ // *this = *this * t (i.e., a multRight)
+ TransformationMatrix& operator*=(const TransformationMatrix& t)
+ {
+ *this = *this * t;
+ return *this;
+ }
+
+ // result = *this * t (i.e., a multRight)
+ TransformationMatrix operator*(const TransformationMatrix& t) const
+ {
+ TransformationMatrix result = t;
+ result.multLeft(*this);
+ return result;
+ }
+
+#if PLATFORM(CA)
+ TransformationMatrix(const CATransform3D&);
+ operator CATransform3D() const;
+#endif
+#if PLATFORM(CG)
+ TransformationMatrix(const CGAffineTransform&);
+ operator CGAffineTransform() const;
+#elif PLATFORM(CAIRO)
+ operator cairo_matrix_t() const;
+#elif PLATFORM(OPENVG)
+ operator VGMatrix() const;
+#elif PLATFORM(QT)
+ operator QTransform() const;
+#elif PLATFORM(SKIA)
+ operator SkMatrix() const;
+#elif PLATFORM(WX) && USE(WXGC)
+ operator wxGraphicsMatrix() const;
+#endif
+
+#if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS)) || (PLATFORM(WX) && OS(WINDOWS))
+ operator XFORM() const;
+#endif
+
+ bool isIdentityOrTranslation() const
+ {
+ return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0
+ && m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0
+ && m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0
+ && m_matrix[3][3] == 1;
+ }
+
+private:
+ // multiply passed 2D point by matrix (assume z=0)
+ void multVecMatrix(double x, double y, double& dstX, double& dstY) const;
+
+ // multiply passed 3D point by matrix
+ void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const;
+
+ void setMatrix(const Matrix4 m)
+ {
+ if (m && m != m_matrix)
+ memcpy(m_matrix, m, sizeof(Matrix4));
+ }
+
+ Matrix4 m_matrix;
+};
+
+} // namespace WebCore
+
+#endif // TransformationMatrix_h
diff --git a/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
new file mode 100644
index 0000000..a8ad131
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "TranslateTransformOperation.h"
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> TranslateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress),
+ Length(m_y.type()).blend(m_y, progress),
+ Length(m_z.type()).blend(m_z, progress), m_type);
+
+ const TranslateTransformOperation* fromOp = static_cast<const TranslateTransformOperation*>(from);
+ Length fromX = fromOp ? fromOp->m_x : Length(m_x.type());
+ Length fromY = fromOp ? fromOp->m_y : Length(m_y.type());
+ Length fromZ = fromOp ? fromOp->m_z : Length(m_z.type());
+ return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_z.blend(fromZ, progress), m_type);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
new file mode 100644
index 0000000..ea48d49
--- /dev/null
+++ b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TranslateTransformOperation_h
+#define TranslateTransformOperation_h
+
+#include "Length.h"
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class TranslateTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, OperationType type)
+ {
+ return adoptRef(new TranslateTransformOperation(tx, ty, Length(0, Fixed), type));
+ }
+
+ static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, const Length& tz, OperationType type)
+ {
+ return adoptRef(new TranslateTransformOperation(tx, ty, tz, type));
+ }
+
+ double x(const IntSize& borderBoxSize) const { return m_x.calcFloatValue(borderBoxSize.width()); }
+ double y(const IntSize& borderBoxSize) const { return m_y.calcFloatValue(borderBoxSize.height()); }
+ double z(const IntSize&) const { return m_z.calcFloatValue(1); }
+
+ Length x() const { return m_x; }
+ Length y() const { return m_y; }
+ Length z() const { return m_z; }
+
+private:
+ virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0 && m_z.calcFloatValue(1) == 0; }
+
+ virtual OperationType getOperationType() const { return m_type; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const TranslateTransformOperation* t = static_cast<const TranslateTransformOperation*>(&o);
+ return m_x == t->m_x && m_y == t->m_y && m_z == t->m_z;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize& borderBoxSize) const
+ {
+ transform.translate3d(x(borderBoxSize), y(borderBoxSize), z(borderBoxSize));
+ return m_x.type() == Percent || m_y.type() == Percent;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ TranslateTransformOperation(const Length& tx, const Length& ty, const Length& tz, OperationType type)
+ : m_x(tx)
+ , m_y(ty)
+ , m_z(tz)
+ , m_type(type)
+ {
+ ASSERT(type == TRANSLATE_X || type == TRANSLATE_Y || type == TRANSLATE_Z || type == TRANSLATE || type == TRANSLATE_3D);
+ }
+
+ Length m_x;
+ Length m_y;
+ Length m_z;
+ OperationType m_type;
+};
+
+} // namespace WebCore
+
+#endif // TranslateTransformOperation_h
diff --git a/Source/WebCore/platform/graphics/win/FontCGWin.cpp b/Source/WebCore/platform/graphics/win/FontCGWin.cpp
new file mode 100644
index 0000000..8012722
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "AffineTransform.h"
+#include "FloatConversion.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "SimpleFontData.h"
+#include "UniscribeController.h"
+#include "WebCoreTextRenderer.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+const int syntheticObliqueAngle = 14;
+
+static inline CGFloat toCGFloat(FIXED f)
+{
+ return f.value + f.fract / CGFloat(65536.0);
+}
+
+static CGPathRef createPathForGlyph(HDC hdc, Glyph glyph)
+{
+ CGMutablePathRef path = CGPathCreateMutable();
+
+ static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 };
+ GLYPHMETRICS glyphMetrics;
+ // GGO_NATIVE matches the outline perfectly when Windows font smoothing is off.
+ // GGO_NATIVE | GGO_UNHINTED does not match perfectly either when Windows font smoothing is on or off.
+ DWORD outlineLength = GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, 0, 0, &identity);
+ ASSERT(outlineLength >= 0);
+ if (outlineLength < 0)
+ return path;
+
+ Vector<UInt8> outline(outlineLength);
+ GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, outlineLength, outline.data(), &identity);
+
+ unsigned offset = 0;
+ while (offset < outlineLength) {
+ LPTTPOLYGONHEADER subpath = reinterpret_cast<LPTTPOLYGONHEADER>(outline.data() + offset);
+ ASSERT(subpath->dwType == TT_POLYGON_TYPE);
+ if (subpath->dwType != TT_POLYGON_TYPE)
+ return path;
+
+ CGPathMoveToPoint(path, 0, toCGFloat(subpath->pfxStart.x), toCGFloat(subpath->pfxStart.y));
+
+ unsigned subpathOffset = sizeof(*subpath);
+ while (subpathOffset < subpath->cb) {
+ LPTTPOLYCURVE segment = reinterpret_cast<LPTTPOLYCURVE>(reinterpret_cast<UInt8*>(subpath) + subpathOffset);
+ switch (segment->wType) {
+ case TT_PRIM_LINE:
+ for (unsigned i = 0; i < segment->cpfx; i++)
+ CGPathAddLineToPoint(path, 0, toCGFloat(segment->apfx[i].x), toCGFloat(segment->apfx[i].y));
+ break;
+
+ case TT_PRIM_QSPLINE:
+ for (unsigned i = 0; i < segment->cpfx; i++) {
+ CGFloat x = toCGFloat(segment->apfx[i].x);
+ CGFloat y = toCGFloat(segment->apfx[i].y);
+ CGFloat cpx;
+ CGFloat cpy;
+
+ if (i == segment->cpfx - 2) {
+ cpx = toCGFloat(segment->apfx[i + 1].x);
+ cpy = toCGFloat(segment->apfx[i + 1].y);
+ i++;
+ } else {
+ cpx = (toCGFloat(segment->apfx[i].x) + toCGFloat(segment->apfx[i + 1].x)) / 2;
+ cpy = (toCGFloat(segment->apfx[i].y) + toCGFloat(segment->apfx[i + 1].y)) / 2;
+ }
+
+ CGPathAddQuadCurveToPoint(path, 0, x, y, cpx, cpy);
+ }
+ break;
+
+ case TT_PRIM_CSPLINE:
+ for (unsigned i = 0; i < segment->cpfx; i += 3) {
+ CGFloat cp1x = toCGFloat(segment->apfx[i].x);
+ CGFloat cp1y = toCGFloat(segment->apfx[i].y);
+ CGFloat cp2x = toCGFloat(segment->apfx[i + 1].x);
+ CGFloat cp2y = toCGFloat(segment->apfx[i + 1].y);
+ CGFloat x = toCGFloat(segment->apfx[i + 2].x);
+ CGFloat y = toCGFloat(segment->apfx[i + 2].y);
+
+ CGPathAddCurveToPoint(path, 0, cp1x, cp1y, cp2x, cp2y, x, y);
+ }
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ return path;
+ }
+
+ subpathOffset += sizeof(*segment) + (segment->cpfx - 1) * sizeof(segment->apfx[0]);
+ }
+ CGPathCloseSubpath(path);
+ offset += subpath->cb;
+ }
+ return path;
+}
+
+static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point)
+{
+ Color fillColor = graphicsContext->fillColor();
+
+ bool drawIntoBitmap = false;
+ TextDrawingModeFlags drawingMode = graphicsContext->textDrawingMode();
+ if (drawingMode == TextModeFill) {
+ if (!fillColor.alpha())
+ return;
+
+ drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer();
+ if (!drawIntoBitmap) {
+ FloatSize offset;
+ float blur;
+ Color color;
+ ColorSpace shadowColorSpace;
+
+ graphicsContext->getShadow(offset, blur, color, shadowColorSpace);
+ drawIntoBitmap = offset.width() || offset.height() || blur;
+ }
+ }
+
+ // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances.
+ Vector<int, 2048> gdiAdvances;
+ int totalWidth = 0;
+ for (int i = 0; i < numGlyphs; i++) {
+ gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i)));
+ totalWidth += gdiAdvances[i];
+ }
+
+ HDC hdc = 0;
+ OwnPtr<GraphicsContext::WindowsBitmap> bitmap;
+ IntRect textRect;
+ if (!drawIntoBitmap)
+ hdc = graphicsContext->getWindowsContext(textRect, true, false);
+ if (!hdc) {
+ drawIntoBitmap = true;
+ // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges.
+ // FIXME: Can get glyphs' optical bounds (even from CG) to get this right.
+ int lineGap = font->lineGap();
+ textRect = IntRect(point.x() - (font->ascent() + font->descent()) / 2, point.y() - font->ascent() - lineGap, totalWidth + font->ascent() + font->descent(), font->lineSpacing());
+ bitmap.set(graphicsContext->createWindowsBitmap(textRect.size()));
+ memset(bitmap->buffer(), 255, bitmap->bufferLength());
+ hdc = bitmap->hdc();
+
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -textRect.x();
+ xform.eDy = -textRect.y();
+ SetWorldTransform(hdc, &xform);
+ }
+
+ SelectObject(hdc, font->platformData().hfont());
+
+ // Set the correct color.
+ if (drawIntoBitmap)
+ SetTextColor(hdc, RGB(0, 0, 0));
+ else
+ SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue()));
+
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextAlign(hdc, TA_LEFT | TA_BASELINE);
+
+ // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
+ FloatSize translation = glyphBuffer.offsetAt(from);
+ if (translation.width() || translation.height()) {
+ XFORM xform;
+ xform.eM11 = 1.0;
+ xform.eM12 = 0;
+ xform.eM21 = 0;
+ xform.eM22 = 1.0;
+ xform.eDx = translation.width();
+ xform.eDy = translation.height();
+ ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+ }
+
+ if (drawingMode == TextModeFill) {
+ XFORM xform;
+ xform.eM11 = 1.0;
+ xform.eM12 = 0;
+ xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0;
+ xform.eM22 = 1.0;
+ xform.eDx = point.x();
+ xform.eDy = point.y();
+ ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+ ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
+ if (font->syntheticBoldOffset()) {
+ xform.eM21 = 0;
+ xform.eDx = font->syntheticBoldOffset();
+ xform.eDy = 0;
+ ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+ ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
+ }
+ } else {
+ XFORM xform;
+ GetWorldTransform(hdc, &xform);
+ AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy);
+ CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity;
+ if (font->platformData().syntheticOblique())
+ initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0));
+ initialGlyphTransform.tx = 0;
+ initialGlyphTransform.ty = 0;
+ CGContextRef cgContext = graphicsContext->platformContext();
+
+ CGContextSaveGState(cgContext);
+
+ BOOL fontSmoothingEnabled = false;
+ SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0);
+ CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled);
+
+ CGContextScaleCTM(cgContext, 1.0, -1.0);
+ CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height()));
+
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i)));
+ CGContextSaveGState(cgContext);
+ CGContextConcatCTM(cgContext, initialGlyphTransform);
+
+ if (drawingMode & TextModeFill) {
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextFillPath(cgContext);
+ if (font->syntheticBoldOffset()) {
+ CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0);
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextFillPath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0);
+ }
+ }
+ if (drawingMode & TextModeStroke) {
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextStrokePath(cgContext);
+ if (font->syntheticBoldOffset()) {
+ CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0);
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextStrokePath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0);
+ }
+ }
+
+ CGContextRestoreGState(cgContext);
+ CGContextTranslateCTM(cgContext, gdiAdvances[i], 0);
+ }
+
+ CGContextRestoreGState(cgContext);
+ }
+
+ if (drawIntoBitmap) {
+ UInt8* buffer = bitmap->buffer();
+ unsigned bufferLength = bitmap->bufferLength();
+ for (unsigned i = 0; i < bufferLength; i += 4) {
+ // Use green, which is always in the middle.
+ UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255;
+ buffer[i] = fillColor.blue();
+ buffer[i + 1] = fillColor.green();
+ buffer[i + 2] = fillColor.red();
+ buffer[i + 3] = alpha;
+ }
+ graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.topLeft());
+ } else
+ graphicsContext->releaseWindowsContext(hdc, textRect, true, false);
+}
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ CGContextRef cgContext = graphicsContext->platformContext();
+ bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();
+
+ switch(fontDescription().fontSmoothing()) {
+ case Antialiased: {
+ graphicsContext->setShouldAntialias(true);
+ shouldUseFontSmoothing = false;
+ break;
+ }
+ case SubpixelAntialiased: {
+ graphicsContext->setShouldAntialias(true);
+ shouldUseFontSmoothing = true;
+ break;
+ }
+ case NoSmoothing: {
+ graphicsContext->setShouldAntialias(false);
+ shouldUseFontSmoothing = false;
+ break;
+ }
+ case AutoSmoothing: {
+ // For the AutoSmooth case, don't do anything! Keep the default settings.
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ if (font->platformData().useGDI() && !shouldUseFontSmoothing) {
+ drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
+ return;
+ }
+
+ uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing);
+
+ const FontPlatformData& platformData = font->platformData();
+
+ CGContextSetFont(cgContext, platformData.cgFont());
+
+ CGAffineTransform matrix = CGAffineTransformIdentity;
+ matrix.b = -matrix.b;
+ matrix.d = -matrix.d;
+
+ if (platformData.syntheticOblique()) {
+ static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f);
+ matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0));
+ }
+
+ CGContextSetTextMatrix(cgContext, matrix);
+
+ // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
+ FloatSize translation = glyphBuffer.offsetAt(from);
+
+ CGContextSetFontSize(cgContext, platformData.size());
+ wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI());
+
+ FloatSize shadowOffset;
+ float shadowBlur;
+ Color shadowColor;
+ ColorSpace shadowColorSpace;
+ graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
+
+ bool hasSimpleShadow = graphicsContext->textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && (!graphicsContext->shadowsIgnoreTransforms() || graphicsContext->getCTM().isIdentityOrTranslationOrFlipped());
+ if (hasSimpleShadow) {
+ // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
+ graphicsContext->clearShadow();
+ Color fillColor = graphicsContext->fillColor();
+ Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
+ graphicsContext->setFillColor(shadowFillColor, ColorSpaceDeviceRGB);
+ float shadowTextX = point.x() + translation.width() + shadowOffset.width();
+ // If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative.
+ float shadowTextY = point.y() + translation.height() + shadowOffset.height() * (graphicsContext->shadowsIgnoreTransforms() ? -1 : 1);
+ CGContextSetTextPosition(cgContext, shadowTextX, shadowTextY);
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->syntheticBoldOffset()) {
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowOffset.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+ graphicsContext->setFillColor(fillColor, ColorSpaceDeviceRGB);
+ }
+
+ CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->syntheticBoldOffset()) {
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->syntheticBoldOffset(), point.y() + translation.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+
+ if (hasSimpleShadow)
+ graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB);
+
+ wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp
new file mode 100644
index 0000000..e800245
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -0,0 +1,603 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include <winsock2.h>
+#include "FontCache.h"
+#include "Font.h"
+#include "SimpleFontData.h"
+#include "UnicodeRange.h"
+#include <mlang.h>
+#include <windows.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.h>
+#if PLATFORM(CG)
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
+
+using std::min;
+
+namespace WebCore
+{
+
+void FontCache::platformInit()
+{
+#if PLATFORM(CG)
+ wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac.
+#endif
+}
+
+IMLangFontLink2* FontCache::getFontLinkInterface()
+{
+ static IMultiLanguage *multiLanguage;
+ if (!multiLanguage) {
+ if (CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLanguage, (void**)&multiLanguage) != S_OK)
+ return 0;
+ }
+
+ static IMLangFontLink2* langFontLink;
+ if (!langFontLink) {
+ if (multiLanguage->QueryInterface(&langFontLink) != S_OK)
+ return 0;
+ }
+
+ return langFontLink;
+}
+
+static int CALLBACK metaFileEnumProc(HDC hdc, HANDLETABLE* table, CONST ENHMETARECORD* record, int tableEntries, LPARAM logFont)
+{
+ if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
+ const EMREXTCREATEFONTINDIRECTW* createFontRecord = reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
+ *reinterpret_cast<LOGFONT*>(logFont) = createFontRecord->elfw.elfLogFont;
+ }
+ return true;
+}
+
+static int CALLBACK linkedFontEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM hfont)
+{
+ *reinterpret_cast<HFONT*>(hfont) = CreateFontIndirect(logFont);
+ return false;
+}
+
+static const Vector<String>* getLinkedFonts(String& family)
+{
+ static HashMap<String, Vector<String>*> systemLinkMap;
+ Vector<String>* result = systemLinkMap.get(family);
+ if (result)
+ return result;
+
+ result = new Vector<String>;
+ systemLinkMap.set(family, result);
+ HKEY fontLinkKey;
+ if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", 0, KEY_READ, &fontLinkKey)))
+ return result;
+
+ DWORD linkedFontsBufferSize = 0;
+ RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, NULL, &linkedFontsBufferSize);
+ WCHAR* linkedFonts = reinterpret_cast<WCHAR*>(malloc(linkedFontsBufferSize));
+ if (SUCCEEDED(RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, reinterpret_cast<BYTE*>(linkedFonts), &linkedFontsBufferSize))) {
+ unsigned i = 0;
+ unsigned length = linkedFontsBufferSize / sizeof(*linkedFonts);
+ while (i < length) {
+ while (i < length && linkedFonts[i] != ',')
+ i++;
+ i++;
+ unsigned j = i;
+ while (j < length && linkedFonts[j])
+ j++;
+ result->append(String(linkedFonts + i, j - i));
+ i = j + 1;
+ }
+ }
+ free(linkedFonts);
+ RegCloseKey(fontLinkKey);
+ return result;
+}
+
+static const Vector<DWORD, 4>& getCJKCodePageMasks()
+{
+ // The default order in which we look for a font for a CJK character. If the user's default code page is
+ // one of these, we will use it first.
+ static const UINT CJKCodePages[] = {
+ 932, /* Japanese */
+ 936, /* Simplified Chinese */
+ 950, /* Traditional Chinese */
+ 949 /* Korean */
+ };
+
+ static Vector<DWORD, 4> codePageMasks;
+ static bool initialized;
+ if (!initialized) {
+ initialized = true;
+ IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
+ if (!langFontLink)
+ return codePageMasks;
+
+ UINT defaultCodePage;
+ DWORD defaultCodePageMask = 0;
+ if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage)))
+ langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask);
+
+ if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3])
+ codePageMasks.append(defaultCodePageMask);
+ for (unsigned i = 0; i < 4; ++i) {
+ if (defaultCodePage != CJKCodePages[i]) {
+ DWORD codePageMask;
+ langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask);
+ codePageMasks.append(codePageMask);
+ }
+ }
+ }
+ return codePageMasks;
+}
+
+static bool currentFontContainsCharacter(HDC hdc, UChar character)
+{
+ static Vector<char, 512> glyphsetBuffer;
+ glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0));
+ GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data());
+ GetFontUnicodeRanges(hdc, glyphset);
+
+ // FIXME: Change this to a binary search.
+ unsigned i = 0;
+ while (i < glyphset->cRanges && glyphset->ranges[i].wcLow <= character)
+ i++;
+
+ return i && glyphset->ranges[i - 1].wcLow + glyphset->ranges[i - 1].cGlyphs > character;
+}
+
+static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0)
+{
+ HFONT MLangFont;
+ HFONT hfont = 0;
+ if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &MLangFont)) && MLangFont) {
+ LOGFONT lf;
+ GetObject(MLangFont, sizeof(LOGFONT), &lf);
+ langFontLink->ReleaseFont(MLangFont);
+ hfont = CreateFontIndirect(&lf);
+ }
+ return hfont;
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ UChar character = characters[0];
+ SimpleFontData* fontData = 0;
+ HDC hdc = GetDC(0);
+ HFONT primaryFont = font.primaryFont()->fontDataForCharacter(character)->platformData().hfont();
+ HGDIOBJ oldFont = SelectObject(hdc, primaryFont);
+ HFONT hfont = 0;
+
+ if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
+ // Try MLang font linking first.
+ DWORD codePages = 0;
+ langFontLink->GetCharCodePages(character, &codePages);
+
+ if (codePages && findCharUnicodeRange(character) == cRangeSetCJK) {
+ // The CJK character may belong to multiple code pages. We want to
+ // do font linking against a single one of them, preferring the default
+ // code page for the user's locale.
+ const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
+ unsigned numCodePages = CJKCodePageMasks.size();
+ for (unsigned i = 0; i < numCodePages && !hfont; ++i) {
+ hfont = createMLangFont(langFontLink, hdc, CJKCodePageMasks[i]);
+ if (hfont && !(codePages & CJKCodePageMasks[i])) {
+ // We asked about a code page that is not one of the code pages
+ // returned by MLang, so the font might not contain the character.
+ SelectObject(hdc, hfont);
+ if (!currentFontContainsCharacter(hdc, character)) {
+ DeleteObject(hfont);
+ hfont = 0;
+ }
+ SelectObject(hdc, primaryFont);
+ }
+ }
+ } else
+ hfont = createMLangFont(langFontLink, hdc, codePages, character);
+ }
+
+ // A font returned from MLang is trusted to contain the character.
+ bool containsCharacter = hfont;
+
+ if (!hfont) {
+ // To find out what font Uniscribe would use, we make it draw into a metafile and intercept
+ // calls to CreateFontIndirect().
+ HDC metaFileDc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
+ SelectObject(metaFileDc, primaryFont);
+
+ bool scriptStringOutSucceeded = false;
+ SCRIPT_STRING_ANALYSIS ssa;
+
+ // FIXME: If length is greater than 1, we actually return the font for the last character.
+ // This function should be renamed getFontDataForCharacter and take a single 32-bit character.
+ if (SUCCEEDED(ScriptStringAnalyse(metaFileDc, characters, length, 0, -1, SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
+ 0, NULL, NULL, NULL, NULL, NULL, &ssa))) {
+ scriptStringOutSucceeded = SUCCEEDED(ScriptStringOut(ssa, 0, 0, 0, NULL, 0, 0, FALSE));
+ ScriptStringFree(&ssa);
+ }
+ HENHMETAFILE metaFile = CloseEnhMetaFile(metaFileDc);
+ if (scriptStringOutSucceeded) {
+ LOGFONT logFont;
+ logFont.lfFaceName[0] = 0;
+ EnumEnhMetaFile(0, metaFile, metaFileEnumProc, &logFont, NULL);
+ if (logFont.lfFaceName[0])
+ hfont = CreateFontIndirect(&logFont);
+ }
+ DeleteEnhMetaFile(metaFile);
+ }
+
+ String familyName;
+ const Vector<String>* linkedFonts = 0;
+ unsigned linkedFontIndex = 0;
+ while (hfont) {
+ SelectObject(hdc, hfont);
+ WCHAR name[LF_FACESIZE];
+ GetTextFace(hdc, LF_FACESIZE, name);
+ familyName = name;
+
+ if (containsCharacter || currentFontContainsCharacter(hdc, character))
+ break;
+
+ if (!linkedFonts)
+ linkedFonts = getLinkedFonts(familyName);
+ SelectObject(hdc, oldFont);
+ DeleteObject(hfont);
+ hfont = 0;
+
+ if (linkedFonts->size() <= linkedFontIndex)
+ break;
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ memcpy(logFont.lfFaceName, linkedFonts->at(linkedFontIndex).characters(), linkedFonts->at(linkedFontIndex).length() * sizeof(WCHAR));
+ logFont.lfFaceName[linkedFonts->at(linkedFontIndex).length()] = 0;
+ EnumFontFamiliesEx(hdc, &logFont, linkedFontEnumProc, reinterpret_cast<LPARAM>(&hfont), 0);
+ linkedFontIndex++;
+ }
+
+ if (hfont) {
+ if (!familyName.isEmpty()) {
+ FontPlatformData* result = getCachedFontPlatformData(font.fontDescription(), familyName);
+ if (result)
+ fontData = getCachedFontData(result);
+ }
+
+ SelectObject(hdc, oldFont);
+ DeleteObject(hfont);
+ }
+
+ ReleaseDC(0, hdc);
+ return fontData;
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+static SimpleFontData* fontDataFromDescriptionAndLogFont(FontCache* fontCache, const FontDescription& fontDescription, const LOGFONT& font, AtomicString& outFontFamilyName)
+{
+ AtomicString familyName = String(font.lfFaceName, wcsnlen(font.lfFaceName, LF_FACESIZE));
+ SimpleFontData* fontData = fontCache->getCachedFontData(fontDescription, familyName);
+ if (fontData)
+ outFontFamilyName = familyName;
+ return fontData;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ DEFINE_STATIC_LOCAL(AtomicString, fallbackFontName, ());
+ if (!fallbackFontName.isEmpty())
+ return getCachedFontData(fontDescription, fallbackFontName);
+
+ // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick
+ // the default that the user would get without changing any prefs.
+
+ // Search all typical Windows-installed full Unicode fonts.
+ // Sorted by most to least glyphs according to http://en.wikipedia.org/wiki/Unicode_typefaces
+ // Start with Times New Roman also since it is the default if the user doesn't change prefs.
+ static AtomicString fallbackFonts[] = {
+ AtomicString("Times New Roman"),
+ AtomicString("Microsoft Sans Serif"),
+ AtomicString("Tahoma"),
+ AtomicString("Lucida Sans Unicode"),
+ AtomicString("Arial")
+ };
+ SimpleFontData* simpleFont;
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(fallbackFonts); ++i) {
+ if (simpleFont = getCachedFontData(fontDescription, fallbackFonts[i])) {
+ fallbackFontName = fallbackFonts[i];
+ return simpleFont;
+ }
+ }
+
+ // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available.
+ if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))) {
+ LOGFONT defaultGUILogFont;
+ GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont);
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, defaultGUILogFont, fallbackFontName))
+ return simpleFont;
+ }
+
+ // Fall back to Non-client metrics fonts.
+ NONCLIENTMETRICS nonClientMetrics = {0};
+ nonClientMetrics.cbSize = sizeof(nonClientMetrics);
+ if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) {
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfMessageFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfMenuFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfStatusFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfCaptionFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfSmCaptionFont, fallbackFontName))
+ return simpleFont;
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+static LONG toGDIFontWeight(FontWeight fontWeight)
+{
+ static LONG gdiFontWeights[] = {
+ FW_THIN, // FontWeight100
+ FW_EXTRALIGHT, // FontWeight200
+ FW_LIGHT, // FontWeight300
+ FW_NORMAL, // FontWeight400
+ FW_MEDIUM, // FontWeight500
+ FW_SEMIBOLD, // FontWeight600
+ FW_BOLD, // FontWeight700
+ FW_EXTRABOLD, // FontWeight800
+ FW_HEAVY // FontWeight900
+ };
+ return gdiFontWeights[fontWeight];
+}
+
+static inline bool isGDIFontWeightBold(LONG gdiFontWeight)
+{
+ return gdiFontWeight >= FW_SEMIBOLD;
+}
+
+static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family)
+{
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr)) {
+ if (gdiFontWeight == FW_NORMAL)
+ return FW_MEDIUM;
+ if (gdiFontWeight == FW_BOLD)
+ return FW_SEMIBOLD;
+ }
+ return gdiFontWeight;
+}
+
+struct MatchImprovingProcData {
+ MatchImprovingProcData(LONG desiredWeight, bool desiredItalic)
+ : m_desiredWeight(desiredWeight)
+ , m_desiredItalic(desiredItalic)
+ , m_hasMatched(false)
+ {
+ }
+
+ LONG m_desiredWeight;
+ bool m_desiredItalic;
+ bool m_hasMatched;
+ LOGFONT m_chosen;
+};
+
+static int CALLBACK matchImprovingEnumProc(CONST LOGFONT* candidate, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ MatchImprovingProcData* matchData = reinterpret_cast<MatchImprovingProcData*>(lParam);
+
+ if (!matchData->m_hasMatched) {
+ matchData->m_hasMatched = true;
+ matchData->m_chosen = *candidate;
+ return 1;
+ }
+
+ if (!candidate->lfItalic != !matchData->m_chosen.lfItalic) {
+ if (!candidate->lfItalic == !matchData->m_desiredItalic)
+ matchData->m_chosen = *candidate;
+
+ return 1;
+ }
+
+ unsigned chosenWeightDeltaMagnitude = abs(matchData->m_chosen.lfWeight - matchData->m_desiredWeight);
+ unsigned candidateWeightDeltaMagnitude = abs(candidate->lfWeight - matchData->m_desiredWeight);
+
+ // If both are the same distance from the desired weight, prefer the candidate if it is further from regular.
+ if (chosenWeightDeltaMagnitude == candidateWeightDeltaMagnitude && abs(candidate->lfWeight - FW_NORMAL) > abs(matchData->m_chosen.lfWeight - FW_NORMAL)) {
+ matchData->m_chosen = *candidate;
+ return 1;
+ }
+
+ // Otherwise, prefer the one closer to the desired weight.
+ if (candidateWeightDeltaMagnitude < chosenWeightDeltaMagnitude)
+ matchData->m_chosen = *candidate;
+
+ return 1;
+}
+
+static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool desiredItalic, int size, bool synthesizeItalic)
+{
+ HDC hdc = GetDC(0);
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = min(family.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, family.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ MatchImprovingProcData matchData(desiredWeight, desiredItalic);
+ EnumFontFamiliesEx(hdc, &logFont, matchImprovingEnumProc, reinterpret_cast<LPARAM>(&matchData), 0);
+
+ ReleaseDC(0, hdc);
+
+ if (!matchData.m_hasMatched)
+ return 0;
+
+ matchData.m_chosen.lfHeight = -size;
+ matchData.m_chosen.lfWidth = 0;
+ matchData.m_chosen.lfEscapement = 0;
+ matchData.m_chosen.lfOrientation = 0;
+ matchData.m_chosen.lfUnderline = false;
+ matchData.m_chosen.lfStrikeOut = false;
+ matchData.m_chosen.lfCharSet = DEFAULT_CHARSET;
+#if PLATFORM(CG) || PLATFORM(CAIRO)
+ matchData.m_chosen.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+#else
+ matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS;
+#endif
+ matchData.m_chosen.lfQuality = DEFAULT_QUALITY;
+ matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+ if (desiredItalic && !matchData.m_chosen.lfItalic && synthesizeItalic)
+ matchData.m_chosen.lfItalic = 1;
+
+ HFONT result = CreateFontIndirect(&matchData.m_chosen);
+ if (!result)
+ return 0;
+
+ HDC dc = GetDC(0);
+ SaveDC(dc);
+ SelectObject(dc, result);
+ WCHAR actualName[LF_FACESIZE];
+ GetTextFace(dc, LF_FACESIZE, actualName);
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+
+ if (wcsicmp(matchData.m_chosen.lfFaceName, actualName)) {
+ DeleteObject(result);
+ result = 0;
+ }
+
+ return result;
+}
+
+struct TraitsInFamilyProcData {
+ TraitsInFamilyProcData(const AtomicString& familyName)
+ : m_familyName(familyName)
+ {
+ }
+
+ const AtomicString& m_familyName;
+ HashSet<unsigned> m_traitsMasks;
+};
+
+static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam);
+
+ unsigned traitsMask = 0;
+ traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask;
+ traitsMask |= FontVariantNormalMask;
+ LONG weight = adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName);
+ traitsMask |= weight == FW_THIN ? FontWeight100Mask :
+ weight == FW_EXTRALIGHT ? FontWeight200Mask :
+ weight == FW_LIGHT ? FontWeight300Mask :
+ weight == FW_NORMAL ? FontWeight400Mask :
+ weight == FW_MEDIUM ? FontWeight500Mask :
+ weight == FW_SEMIBOLD ? FontWeight600Mask :
+ weight == FW_BOLD ? FontWeight700Mask :
+ weight == FW_EXTRABOLD ? FontWeight800Mask :
+ FontWeight900Mask;
+ procData->m_traitsMasks.add(traitsMask);
+ return 1;
+}
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ HDC hdc = GetDC(0);
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ TraitsInFamilyProcData procData(familyName);
+ EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
+ copyToVector(procData.m_traitsMasks, traitsMasks);
+
+ ReleaseDC(0, hdc);
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ bool isLucidaGrande = false;
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr))
+ isLucidaGrande = true;
+
+ bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande;
+
+ // The logical size constant is 32. We do this for subpixel precision when rendering using Uniscribe.
+ // This masks rounding errors related to the HFONT metrics being different from the CGFont metrics.
+ // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't
+ // look as nice. That may be solvable though.
+ LONG weight = adjustedGDIFontWeight(toGDIFontWeight(fontDescription.weight()), family);
+ HFONT hfont = createGDIFont(family, weight, fontDescription.italic(),
+ fontDescription.computedPixelSize() * (useGDI ? 1 : 32), useGDI);
+
+ if (!hfont)
+ return 0;
+
+ if (isLucidaGrande)
+ useGDI = false; // Never use GDI for Lucida Grande.
+
+ LOGFONT logFont;
+ GetObject(hfont, sizeof(LOGFONT), &logFont);
+
+ bool synthesizeBold = isGDIFontWeightBold(weight) && !isGDIFontWeightBold(logFont.lfWeight);
+ bool synthesizeItalic = fontDescription.italic() && !logFont.lfItalic;
+
+ FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(), synthesizeBold, synthesizeItalic, useGDI);
+
+#if PLATFORM(CG)
+ bool fontCreationFailed = !result->cgFont();
+#elif PLATFORM(CAIRO)
+ bool fontCreationFailed = !result->fontFace();
+#endif
+
+ if (fontCreationFailed) {
+ // The creation of the CGFontRef failed for some reason. We already asserted in debug builds, but to make
+ // absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next
+ // font.
+ delete result;
+ DeleteObject(hfont);
+ return 0;
+ }
+
+ return result;
+}
+
+}
+
diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..9cae99b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "Base64.h"
+#include "FontPlatformData.h"
+#include "OpenTypeUtilities.h"
+#include "SharedBuffer.h"
+#include "SoftLinking.h"
+#include "WOFFFileFormat.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/RetainPtr.h>
+
+// From t2embapi.h, which is missing from the Microsoft Platform SDK.
+typedef unsigned long(WINAPIV *READEMBEDPROC) (void*, void*, unsigned long);
+struct TTLOADINFO;
+#define TTLOAD_PRIVATE 0x00000001
+#define LICENSE_PREVIEWPRINT 0x0004
+#define E_NONE 0x0000L
+
+namespace WebCore {
+
+using namespace std;
+
+SOFT_LINK_LIBRARY(T2embed);
+SOFT_LINK(T2embed, TTLoadEmbeddedFont, LONG, __stdcall, (HANDLE* phFontReference, ULONG ulFlags, ULONG* pulPrivStatus, ULONG ulPrivs, ULONG* pulStatus, READEMBEDPROC lpfnReadFromStream, LPVOID lpvReadStream, LPWSTR szWinFamilyName, LPSTR szMacFamilyName, TTLOADINFO* pTTLoadInfo), (phFontReference, ulFlags,pulPrivStatus, ulPrivs, pulStatus, lpfnReadFromStream, lpvReadStream, szWinFamilyName, szMacFamilyName, pTTLoadInfo));
+SOFT_LINK(T2embed, TTGetNewFontName, LONG, __stdcall, (HANDLE* phFontReference, LPWSTR szWinFamilyName, long cchMaxWinName, LPSTR szMacFamilyName, long cchMaxMacName), (phFontReference, szWinFamilyName, cchMaxWinName, szMacFamilyName, cchMaxMacName));
+SOFT_LINK(T2embed, TTDeleteEmbeddedFont, LONG, __stdcall, (HANDLE hFontReference, ULONG ulFlags, ULONG* pulStatus), (hFontReference, ulFlags, pulStatus));
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ if (m_fontReference) {
+ if (m_name.isNull()) {
+ ASSERT(T2embedLibrary());
+ ULONG status;
+ TTDeleteEmbeddedFont(m_fontReference, 0, &status);
+ } else
+ RemoveFontMemResourceEx(m_fontReference);
+ }
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode renderingMode)
+{
+ ASSERT(m_fontReference);
+ ASSERT(T2embedLibrary());
+
+ LOGFONT& logFont = *static_cast<LOGFONT*>(malloc(sizeof(LOGFONT)));
+ if (m_name.isNull())
+ TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0);
+ else
+ memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), sizeof(logFont.lfFaceName[0]) * min(static_cast<size_t>(LF_FACESIZE), 1 + m_name.length()));
+
+ logFont.lfHeight = -size;
+ if (renderingMode == NormalRenderingMode)
+ logFont.lfHeight *= 32;
+ logFont.lfWidth = 0;
+ logFont.lfEscapement = 0;
+ logFont.lfOrientation = 0;
+ logFont.lfUnderline = false;
+ logFont.lfStrikeOut = false;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ logFont.lfQuality = CLEARTYPE_QUALITY;
+ logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ logFont.lfItalic = italic;
+ logFont.lfWeight = bold ? 700 : 400;
+
+ HFONT hfont = CreateFontIndirect(&logFont);
+
+ RetainPtr<CGFontRef> cgFont(AdoptCF, CGFontCreateWithPlatformFont(&logFont));
+ return FontPlatformData(hfont, cgFont.get(), size, bold, italic, renderingMode == AlternateRenderingMode);
+}
+
+// Streams the concatenation of a header and font data.
+class EOTStream {
+public:
+ EOTStream(const EOTHeader& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
+ : m_eotHeader(eotHeader)
+ , m_fontData(fontData)
+ , m_overlayDst(overlayDst)
+ , m_overlaySrc(overlaySrc)
+ , m_overlayLength(overlayLength)
+ , m_offset(0)
+ , m_inHeader(true)
+ {
+ }
+
+ size_t read(void* buffer, size_t count);
+
+private:
+ const EOTHeader& m_eotHeader;
+ const SharedBuffer* m_fontData;
+ size_t m_overlayDst;
+ size_t m_overlaySrc;
+ size_t m_overlayLength;
+ size_t m_offset;
+ bool m_inHeader;
+};
+
+size_t EOTStream::read(void* buffer, size_t count)
+{
+ size_t bytesToRead = count;
+ if (m_inHeader) {
+ size_t bytesFromHeader = min(m_eotHeader.size() - m_offset, count);
+ memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader);
+ m_offset += bytesFromHeader;
+ bytesToRead -= bytesFromHeader;
+ if (m_offset == m_eotHeader.size()) {
+ m_inHeader = false;
+ m_offset = 0;
+ }
+ }
+ if (bytesToRead && !m_inHeader) {
+ size_t bytesFromData = min(m_fontData->size() - m_offset, bytesToRead);
+ memcpy(buffer, m_fontData->data() + m_offset, bytesFromData);
+ if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) {
+ size_t dstOffset = max<int>(m_overlayDst - m_offset, 0);
+ size_t srcOffset = max<int>(0, m_offset - m_overlayDst);
+ size_t bytesToCopy = min(bytesFromData - dstOffset, m_overlayLength - srcOffset);
+ memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy);
+ }
+ m_offset += bytesFromData;
+ bytesToRead -= bytesFromData;
+ }
+ return count - bytesToRead;
+}
+
+static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length)
+{
+ return static_cast<EOTStream*>(stream)->read(buffer, length);
+}
+
+// Creates a unique and unpredictable font name, in order to avoid collisions and to
+// not allow access from CSS.
+static String createUniqueFontName()
+{
+ Vector<char> fontUuid(sizeof(GUID));
+ CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data()));
+
+ Vector<char> fontNameVector;
+ base64Encode(fontUuid, fontNameVector);
+ ASSERT(fontNameVector.size() < LF_FACESIZE);
+ return String(fontNameVector.data(), fontNameVector.size());
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+ ASSERT(T2embedLibrary());
+
+ RefPtr<SharedBuffer> sfntBuffer;
+ if (isWOFF(buffer)) {
+ Vector<char> sfnt;
+ if (!convertWOFFToSfnt(buffer, sfnt))
+ return 0;
+
+ sfntBuffer = SharedBuffer::adoptVector(sfnt);
+ buffer = sfntBuffer.get();
+ }
+
+ // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's
+ // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the
+ // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name
+ // we avoid namespace collisions.
+
+ String fontName = createUniqueFontName();
+
+ // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, so we need to create an EOT header
+ // and prepend it to the font data.
+ EOTHeader eotHeader;
+ size_t overlayDst;
+ size_t overlaySrc;
+ size_t overlayLength;
+ if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength))
+ return 0;
+
+ HANDLE fontReference;
+ ULONG privStatus;
+ ULONG status;
+ EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength);
+
+ LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0);
+ if (loadEmbeddedFontResult == E_NONE)
+ fontName = String();
+ else {
+ fontReference = renameAndActivateFont(buffer, fontName);
+ if (!fontReference)
+ return 0;
+ }
+
+ return new FontCustomPlatformData(fontReference, fontName);
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype") || equalIgnoringCase(format, "woff");
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h
new file mode 100644
index 0000000..1bdf270
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+typedef struct CGFont* CGFontRef;
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(HANDLE fontReference, const String& name)
+ : m_fontReference(fontReference)
+ , m_name(name)
+ {
+ }
+
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+
+ static bool supportsFormat(const String&);
+
+ HANDLE m_fontReference;
+ String m_name;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
new file mode 100644
index 0000000..c3decbf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformDataCairo.h"
+
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ cairo_font_face_destroy(m_fontFace);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation)
+{
+ return FontPlatformData(m_fontFace, size, bold, italic);
+}
+
+static void releaseData(void* data)
+{
+ static_cast<SharedBuffer*>(data)->deref();
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+ buffer->ref();
+ HFONT font = reinterpret_cast<HFONT>(buffer);
+ cairo_font_face_t* fontFace = cairo_win32_font_face_create_for_hfont(font);
+ if (!fontFace)
+ return 0;
+
+ static cairo_user_data_key_t bufferKey;
+ cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData);
+
+ return new FontCustomPlatformData(fontFace);
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype");
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
new file mode 100644
index 0000000..3ab52b8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ * Copyright (C) 2010 Brent Fulgham <bfulgham@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformDataCairo_h
+#define FontCustomPlatformDataCairo_h
+
+#include "FontDescription.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+#include <cairo.h>
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(cairo_font_face_t* fontFace)
+ : m_fontFace(fontFace)
+ {
+ }
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal);
+
+ static bool supportsFormat(const String&);
+
+ cairo_font_face_t* m_fontFace;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
new file mode 100644
index 0000000..9234229
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+using std::min;
+
+namespace WebCore {
+
+static inline USHORT readBigEndianWord(const BYTE* word) { return (word[0] << 8) | word[1]; }
+
+static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc)
+{
+ const DWORD cMaxNameTableSize = 1024 * 1024;
+
+ static HashMap<String, RetainPtr<CFStringRef> > nameMap;
+
+ // Check our hash first.
+ String faceString(faceName);
+ RetainPtr<CFStringRef> result = nameMap.get(faceString);
+ if (result)
+ return result.get();
+
+ // We need to obtain the PostScript name from the name table and use it instead,.
+ DWORD bufferSize = GetFontData(dc, 'eman', 0, NULL, 0); // "name" backwards
+ if (bufferSize == 0 || bufferSize == GDI_ERROR || bufferSize > cMaxNameTableSize)
+ return NULL;
+
+ Vector<BYTE> bufferVector(bufferSize);
+ BYTE* buffer = bufferVector.data();
+ if (GetFontData(dc, 'eman', 0, buffer, bufferSize) == GDI_ERROR)
+ return NULL;
+
+ if (bufferSize < 6)
+ return NULL;
+
+ USHORT numberOfRecords = readBigEndianWord(buffer + 2);
+ UINT stringsOffset = readBigEndianWord(buffer + 4);
+ if (bufferSize < stringsOffset)
+ return NULL;
+
+ BYTE* strings = buffer + stringsOffset;
+
+ // Now walk each name record looking for a Mac or Windows PostScript name.
+ UINT offset = 6;
+ for (int i = 0; i < numberOfRecords; i++) {
+ if (bufferSize < offset + 12)
+ return NULL;
+
+ USHORT platformID = readBigEndianWord(buffer + offset);
+ USHORT encodingID = readBigEndianWord(buffer + offset + 2);
+ USHORT languageID = readBigEndianWord(buffer + offset + 4);
+ USHORT nameID = readBigEndianWord(buffer + offset + 6);
+ USHORT length = readBigEndianWord(buffer + offset + 8);
+ USHORT nameOffset = readBigEndianWord(buffer + offset + 10);
+
+ if (platformID == 3 && encodingID == 1 && languageID == 0x409 && nameID == 6) {
+ // This is a Windows PostScript name and is therefore UTF-16.
+ // Pass Big Endian as the encoding.
+ if (bufferSize < stringsOffset + nameOffset + length)
+ return NULL;
+ result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingUTF16BE, false));
+ break;
+ } else if (platformID == 1 && encodingID == 0 && languageID == 0 && nameID == 6) {
+ // This is a Mac PostScript name and is therefore ASCII.
+ // See http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
+ if (bufferSize < stringsOffset + nameOffset + length)
+ return NULL;
+ result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingASCII, false));
+ break;
+ }
+
+ offset += 12;
+ }
+
+ if (result)
+ nameMap.set(faceString, result);
+ return result.get();
+}
+
+void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
+{
+ LOGFONT logfont;
+ GetObject(font, sizeof(logfont), &logfont);
+ m_cgFont.adoptCF(CGFontCreateWithPlatformFont(&logfont));
+}
+
+FontPlatformData::FontPlatformData(HFONT hfont, CGFontRef font, float size, bool bold, bool oblique, bool useGDI)
+ : m_font(RefCountedGDIHandle<HFONT>::create(hfont))
+ , m_size(size)
+ , m_cgFont(font)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(useGDI)
+{
+}
+
+FontPlatformData::~FontPlatformData()
+{
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
new file mode 100644
index 0000000..0f5c365
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ * Copyright (C) 2007 Alp Toker
+ * Copyright (C) 2008, 2010 Brent Fulgham
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+#include <cairo-win32.h>
+
+using namespace std;
+
+namespace WebCore {
+
+void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
+{
+ m_fontFace = cairo_win32_font_face_create_for_hfont(font);
+
+ cairo_matrix_t sizeMatrix, ctm;
+ cairo_matrix_init_identity(&ctm);
+ cairo_matrix_init_scale(&sizeMatrix, size, size);
+
+ static cairo_font_options_t* fontOptions = 0;
+ if (!fontOptions) {
+ fontOptions = cairo_font_options_create();
+ cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
+ }
+
+ m_scaledFont = cairo_scaled_font_create(m_fontFace, &sizeMatrix, &ctm, fontOptions);
+}
+
+FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool oblique)
+ : m_font(0)
+ , m_size(size)
+ , m_fontFace(fontFace)
+ , m_scaledFont(0)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(false)
+{
+ cairo_matrix_t fontMatrix;
+ cairo_matrix_init_scale(&fontMatrix, size, size);
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity(&ctm);
+ cairo_font_options_t* options = cairo_font_options_create();
+
+ // We force antialiasing and disable hinting to provide consistent
+ // typographic qualities for custom fonts on all platforms.
+ cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
+
+ m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
+ cairo_font_options_destroy(options);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& source)
+ : m_font(source.m_font)
+ , m_size(source.m_size)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+ , m_syntheticBold(source.m_syntheticBold)
+ , m_syntheticOblique(source.m_syntheticOblique)
+ , m_useGDI(source.m_useGDI)
+{
+ if (source.m_fontFace)
+ m_fontFace = cairo_font_face_reference(source.m_fontFace);
+
+ if (source.m_scaledFont)
+ m_scaledFont = cairo_scaled_font_reference(source.m_scaledFont);
+}
+
+
+FontPlatformData::~FontPlatformData()
+{
+ cairo_scaled_font_destroy(m_scaledFont);
+ cairo_font_face_destroy(m_fontFace);
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ // Check for self-assignment.
+ if (this == &other)
+ return *this;
+
+ m_font = other.m_font;
+ m_size = other.m_size;
+ m_syntheticBold = other.m_syntheticBold;
+ m_syntheticOblique = other.m_syntheticOblique;
+ m_useGDI = other.m_useGDI;
+
+ if (other.m_fontFace)
+ cairo_font_face_reference(other.m_fontFace);
+ if (m_fontFace)
+ cairo_font_face_destroy(m_fontFace);
+ m_fontFace = other.m_fontFace;
+
+ if (other.m_scaledFont)
+ cairo_scaled_font_reference(other.m_scaledFont);
+ if (m_scaledFont)
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = other.m_scaledFont;
+
+ return *this;
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& other) const
+{
+ return m_font == other.m_font
+ && m_fontFace == other.m_fontFace
+ && m_scaledFont == other.m_scaledFont
+ && m_size == other.m_size
+ && m_syntheticBold == other.m_syntheticBold
+ && m_syntheticOblique == other.m_syntheticOblique
+ && m_useGDI == other.m_useGDI;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
new file mode 100644
index 0000000..09ed4a6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
@@ -0,0 +1,95 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ * Copyright (C) 2008 Brent Fulgham
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+using std::min;
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI)
+ : m_font(RefCountedGDIHandle<HFONT>::create(font))
+ , m_size(size)
+#if PLATFORM(CG)
+ , m_cgFont(0)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(useGDI)
+{
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ SelectObject(hdc, font);
+ UINT bufferSize = GetOutlineTextMetrics(hdc, 0, NULL);
+
+ ASSERT_WITH_MESSAGE(bufferSize, "Bitmap fonts not supported with CoreGraphics.");
+
+ if (bufferSize) {
+ OUTLINETEXTMETRICW* metrics = (OUTLINETEXTMETRICW*)malloc(bufferSize);
+
+ GetOutlineTextMetricsW(hdc, bufferSize, metrics);
+ WCHAR* faceName = (WCHAR*)((uintptr_t)metrics + (uintptr_t)metrics->otmpFaceName);
+
+ platformDataInit(font, size, hdc, faceName);
+
+ free(metrics);
+ }
+
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+ : m_size(size)
+#if PLATFORM(CG)
+ , m_cgFont(0)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(false)
+{
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontWin.cpp b/Source/WebCore/platform/graphics/win/FontWin.cpp
new file mode 100644
index 0000000..2170954
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontWin.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "Logging.h"
+#include "SimpleFontData.h"
+#include "UniscribeController.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return true;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h,
+ int from, int to) const
+{
+ UniscribeController it(this, run);
+ it.advance(from);
+ float beforeWidth = it.runWidthSoFar();
+ it.advance(to);
+ float afterWidth = it.runWidthSoFar();
+
+ // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
+ if (run.rtl()) {
+ it.advance(run.length());
+ float totalWidth = it.runWidthSoFar();
+ return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
+ }
+
+ return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
+}
+
+float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
+{
+ if (forTextEmphasis) {
+ // FIXME: Add forTextEmphasis paremeter to UniscribeController and use it.
+ LOG_ERROR("Not implemented for text emphasis.");
+ return 0;
+ }
+
+ UniscribeController controller(this, run);
+ controller.advance(from);
+ float beforeWidth = controller.runWidthSoFar();
+ controller.advance(to, &glyphBuffer);
+
+ if (glyphBuffer.isEmpty())
+ return 0;
+
+ float afterWidth = controller.runWidthSoFar();
+
+ if (run.rtl()) {
+ controller.advance(run.length());
+ return controller.runWidthSoFar() - afterWidth;
+ }
+ return beforeWidth;
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point,
+ int from, int to) const
+{
+ // This glyph buffer holds our glyphs + advances + font data for each glyph.
+ GlyphBuffer glyphBuffer;
+
+ float startX = point.x() + getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer);
+
+ // We couldn't generate any glyphs for the run. Give up.
+ if (glyphBuffer.isEmpty())
+ return;
+
+ // Draw the glyph buffer now at the starting point returned in startX.
+ FloatPoint startPoint(startX, point.y());
+ drawGlyphBuffer(context, glyphBuffer, startPoint);
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
+{
+ GlyphBuffer glyphBuffer;
+ float initialAdvance = getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer, ForTextEmphasis);
+
+ if (glyphBuffer.isEmpty())
+ return;
+
+ drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+ UniscribeController controller(this, run, fallbackFonts);
+ controller.advance(run.length());
+ if (glyphOverflow) {
+ glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - ascent());
+ glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - descent());
+ glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX()));
+ glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.runWidthSoFar()));
+ }
+ return controller.runWidthSoFar();
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const
+{
+ // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
+ // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
+ int x = static_cast<int>(xFloat);
+
+ UniscribeController controller(this, run);
+ return controller.offsetForPosition(x, includePartialGlyphs);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GDIExtras.cpp b/Source/WebCore/platform/graphics/win/GDIExtras.cpp
new file mode 100644
index 0000000..4bd95da
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GDIExtras.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "GDIExtras.h"
+
+#include "SoftLinking.h"
+
+namespace WebCore {
+
+#if OS(WINCE)
+SOFT_LINK_LIBRARY(coredll)
+SOFT_LINK_OPTIONAL(coredll, AlphaBlend, BOOL, APIENTRY, (HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc,
+ int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction))
+
+AlphaBlendPointerType AlphaBlendPointer()
+{
+ return AlphaBlendPtr();
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/win/GDIExtras.h b/Source/WebCore/platform/graphics/win/GDIExtras.h
new file mode 100644
index 0000000..0166124
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GDIExtras.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 GDIExtras_h
+#define GDIExtras_h
+
+#include <windows.h>
+
+namespace WebCore {
+
+typedef BOOL (APIENTRY *AlphaBlendPointerType) (HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc,
+ int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction);
+
+#if OS(WINCE)
+AlphaBlendPointerType AlphaBlendPointer();
+#endif
+
+inline bool hasAlphaBlendSupport()
+{
+#if OS(WINCE)
+ return AlphaBlendPointer();
+#else
+ return true;
+#endif
+}
+
+inline bool alphaBlendIfSupported(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc,
+ int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction)
+{
+#if OS(WINCE)
+ AlphaBlendPointerType alphaBlendPointer = AlphaBlendPointer();
+ if (!alphaBlendPointer)
+ return false;
+
+ alphaBlendPointer(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, blendFunction);
+#else
+ AlphaBlend(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, blendFunction);
+#endif
+ return true;
+}
+
+} // namespace WebCore
+
+#endif // GDIExtras_h
diff --git a/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp b/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
new file mode 100644
index 0000000..c11fc1b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs.
+ // We won't support this for now.
+ if (bufferLength > length)
+ return false;
+
+ bool haveGlyphs = false;
+ CGGlyph localGlyphBuffer[GlyphPage::size];
+ wkGetGlyphs(fontData->platformData().cgFont(), buffer, localGlyphBuffer, bufferLength);
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = localGlyphBuffer[i];
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+ return haveGlyphs;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp b/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp
new file mode 100644
index 0000000..b679ced
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs.
+ // We won't support this for now.
+ if (bufferLength > length)
+ return false;
+
+ bool haveGlyphs = false;
+
+ HDC dc = GetDC((HWND)0);
+ SaveDC(dc);
+ SelectObject(dc, fontData->platformData().hfont());
+
+ TEXTMETRIC tm;
+ GetTextMetrics(dc, &tm);
+
+ WORD localGlyphBuffer[GlyphPage::size * 2];
+ DWORD result = GetGlyphIndices(dc, buffer, bufferLength, localGlyphBuffer, 0);
+ bool success = result != GDI_ERROR && static_cast<unsigned>(result) == bufferLength;
+ if (success) {
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = localGlyphBuffer[i];
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+ }
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+
+ return haveGlyphs;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
new file mode 100644
index 0000000..d3c6b58
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GraphicsContextCG.h"
+
+#include "AffineTransform.h"
+#include "Path.h"
+
+#include <CoreGraphics/CGBitmapContext.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include "GraphicsContextPlatformPrivateCG.h"
+
+using namespace std;
+
+namespace WebCore {
+
+static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha)
+{
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+ BITMAP info;
+
+ GetObject(bitmap, sizeof(info), &info);
+
+ // FIXME: We can get here because we asked for a bitmap that is too big
+ // when we have a tiled layer and we're compositing. In that case
+ // bmBitsPixel will be 0. This seems to be benign, so for now we will
+ // exit gracefully and look at it later:
+ // https://bugs.webkit.org/show_bug.cgi?id=52041
+ // ASSERT(info.bmBitsPixel == 32);
+ if (info.bmBitsPixel != 32)
+ return 0;
+
+ CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | (hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst);
+ CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, deviceRGBColorSpaceRef(), bitmapInfo);
+
+ // Flip coords
+ CGContextTranslateCTM(context, 0, info.bmHeight);
+ CGContextScaleCTM(context, 1, -1);
+
+ // Put the HDC In advanced mode so it will honor affine transforms.
+ SetGraphicsMode(hdc, GM_ADVANCED);
+
+ return context;
+}
+
+GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
+ : m_updatingControlTints(false)
+{
+ platformInit(hdc, hasAlpha);
+}
+
+void GraphicsContext::platformInit(HDC hdc, bool hasAlpha)
+{
+ m_data = new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha));
+ CGContextRelease(m_data->m_cgContext.get());
+ m_data->m_hdc = hdc;
+ setPaintingDisabled(!m_data->m_cgContext);
+ if (m_data->m_cgContext) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
+ setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
+ }
+}
+
+// FIXME: Is it possible to merge getWindowsContext and createWindowsBitmap into a single API
+// suitable for all clients?
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer());
+ if (!createdBitmap) {
+ m_data->restore();
+ return;
+ }
+
+ if (dstRect.isEmpty())
+ return;
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+
+ // Need to make a CGImage out of the bitmap's pixel buffer and then draw
+ // it into our context.
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little |
+ (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst));
+
+ CGImageRef image = CGBitmapContextCreateImage(bitmapContext);
+ CGContextDrawImage(m_data->m_cgContext.get(), dstRect, image);
+
+ // Delete all our junk.
+ CGImageRelease(image);
+ CGContextRelease(bitmapContext);
+ ::DeleteDC(hdc);
+ ::DeleteObject(bitmap);
+}
+
+void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point)
+{
+ // FIXME: Creating CFData is non-optimal, but needed to avoid crashing when printing. Ideally we should
+ // make a custom CGDataProvider that controls the WindowsBitmap lifetime. see <rdar://6394455>
+ RetainPtr<CFDataRef> imageData(AdoptCF, CFDataCreate(kCFAllocatorDefault, image->buffer(), image->bufferLength()));
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(imageData.get()));
+ RetainPtr<CGImageRef> cgImage(AdoptCF, CGImageCreate(image->size().width(), image->size().height(), 8, 32, image->bytesPerRow(), deviceRGBColorSpaceRef(),
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst, dataProvider.get(), 0, true, kCGRenderingIntentDefault));
+ CGContextDrawImage(m_data->m_cgContext.get(), CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get());
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+// FIXME: This is nearly identical to the GraphicsContext::drawFocusRing function in GraphicsContextMac.mm.
+// The code could move to GraphicsContextCG.cpp and be shared.
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ float radius = (width - 1) / 2.0f;
+ offset += radius;
+ CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0;
+
+ CGMutablePathRef focusRingPath = CGPathCreateMutable();
+ unsigned rectCount = rects.size();
+ for (unsigned i = 0; i < rectCount; i++)
+ CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset));
+
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+
+ CGContextBeginPath(context);
+ CGContextAddPath(context, focusRingPath);
+
+ wkDrawFocusRing(context, colorRef, radius);
+
+ CGPathRelease(focusRingPath);
+
+ CGContextRestoreGState(context);
+}
+
+// Pulled from GraphicsContextCG
+static void setCGStrokeColor(CGContextRef context, const Color& color)
+{
+ CGFloat red, green, blue, alpha;
+ color.getRGBA(red, green, blue, alpha);
+ CGContextSetRGBStrokeColor(context, red, green, blue, alpha);
+}
+
+static const Color& spellingPatternColor() {
+ static const Color spellingColor(255, 0, 0);
+ return spellingColor;
+}
+
+static const Color& grammarPatternColor() {
+ static const Color grammarColor(0, 128, 0);
+ return grammarColor;
+}
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint& point, int width, TextCheckingLineStyle style)
+{
+ if (paintingDisabled())
+ return;
+
+ if (style != TextCheckingSpellingLineStyle && style != TextCheckingGrammarLineStyle)
+ return;
+
+ // These are the same for misspelling or bad grammar
+ const int patternHeight = 3; // 3 rows
+ ASSERT(cMisspellingLineThickness == patternHeight);
+ const int patternWidth = 4; // 4 pixels
+ ASSERT(patternWidth == cMisspellingLinePatternWidth);
+
+ // Make sure to draw only complete dots.
+ // NOTE: Code here used to shift the underline to the left and increase the width
+ // to make sure everything gets underlined, but that results in drawing out of
+ // bounds (e.g. when at the edge of a view) and could make it appear that the
+ // space between adjacent misspelled words was underlined.
+ // allow slightly more considering that the pattern ends with a transparent pixel
+ int widthMod = width % patternWidth;
+ if (patternWidth - widthMod > cMisspellingLinePatternGapWidth)
+ width -= widthMod;
+
+ // Draw the underline
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+
+ const Color& patternColor = style == TextCheckingGrammarLineStyle ? grammarPatternColor() : spellingPatternColor();
+ setCGStrokeColor(context, patternColor);
+
+ wkSetPatternPhaseInUserSpace(context, point);
+ CGContextSetBlendMode(context, kCGBlendModeNormal);
+
+ // 3 rows, each offset by half a pixel for blending purposes
+ const CGPoint upperPoints [] = {{point.x(), point.y() + patternHeight - 2.5 }, {point.x() + width, point.y() + patternHeight - 2.5}};
+ const CGPoint middlePoints [] = {{point.x(), point.y() + patternHeight - 1.5 }, {point.x() + width, point.y() + patternHeight - 1.5}};
+ const CGPoint lowerPoints [] = {{point.x(), point.y() + patternHeight - 0.5 }, {point.x() + width, point.y() + patternHeight - 0.5 }};
+
+ // Dash lengths for the top and bottom of the error underline are the same.
+ // These are magic.
+ static const float edge_dash_lengths[] = {2.0f, 2.0f};
+ static const float middle_dash_lengths[] = {2.76f, 1.24f};
+ static const float edge_offset = -(edge_dash_lengths[1] - 1.0f) / 2.0f;
+ static const float middle_offset = -(middle_dash_lengths[1] - 1.0f) / 2.0f;
+
+ // Line opacities. Once again, these are magic.
+ const float upperOpacity = 0.33f;
+ const float middleOpacity = 0.75f;
+ const float lowerOpacity = 0.88f;
+
+ //Top line
+ CGContextSetLineDash(context, edge_offset, edge_dash_lengths, WTF_ARRAY_LENGTH(edge_dash_lengths));
+ CGContextSetAlpha(context, upperOpacity);
+ CGContextStrokeLineSegments(context, upperPoints, 2);
+
+ // Middle line
+ CGContextSetLineDash(context, middle_offset, middle_dash_lengths, WTF_ARRAY_LENGTH(middle_dash_lengths));
+ CGContextSetAlpha(context, middleOpacity);
+ CGContextStrokeLineSegments(context, middlePoints, 2);
+
+ // Bottom line
+ CGContextSetLineDash(context, edge_offset, edge_dash_lengths, WTF_ARRAY_LENGTH(edge_dash_lengths));
+ CGContextSetAlpha(context, lowerOpacity);
+ CGContextStrokeLineSegments(context, lowerPoints, 2);
+
+ CGContextRestoreGState(context);
+}
+
+void GraphicsContextPlatformPrivate::flush()
+{
+ CGContextFlush(m_cgContext.get());
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
new file mode 100644
index 0000000..b2c702f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "Path.h"
+
+#include <cairo-win32.h>
+#include "GraphicsContextPlatformPrivateCairo.h"
+
+using namespace std;
+
+namespace WebCore {
+
+static cairo_t* createCairoContextWithHDC(HDC hdc, bool hasAlpha)
+{
+ // Put the HDC In advanced mode so it will honor affine transforms.
+ SetGraphicsMode(hdc, GM_ADVANCED);
+
+ cairo_surface_t* surface = 0;
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+
+ BITMAP info;
+ if (!GetObject(bitmap, sizeof(info), &info))
+ surface = cairo_win32_surface_create(hdc);
+ else {
+ ASSERT(info.bmBitsPixel == 32);
+
+ surface = cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
+ CAIRO_FORMAT_ARGB32,
+ info.bmWidth,
+ info.bmHeight,
+ info.bmWidthBytes);
+ }
+
+ cairo_t* context = cairo_create(surface);
+ cairo_surface_destroy(surface);
+
+ return context;
+}
+
+GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
+ : m_updatingControlTints(false)
+{
+ platformInit(dc, hasAlpha);
+}
+
+void GraphicsContext::platformInit(HDC dc, bool hasAlpha)
+{
+ m_data = new GraphicsContextPlatformPrivate;
+
+ if (dc) {
+ m_data->cr = createCairoContextWithHDC(dc, hasAlpha);
+ m_data->m_hdc = dc;
+ } else {
+ setPaintingDisabled(true);
+ m_data->cr = 0;
+ m_data->m_hdc = 0;
+ }
+
+ if (m_data->cr) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor(), fillColorSpace());
+ setPlatformStrokeColor(strokeColor(), strokeColorSpace());
+ }
+}
+
+static void setRGBABitmapAlpha(unsigned char* bytes, size_t length, unsigned char level)
+{
+ for (size_t i = 0; i < length; i += 4)
+ bytes[i + 3] = level;
+}
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer());
+ if (!hdc || !createdBitmap) {
+ m_data->restore();
+ return;
+ }
+
+ if (dstRect.isEmpty())
+ return;
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ // If this context does not support alpha blending, then it may have
+ // been drawn with GDI functions which always set the alpha channel
+ // to zero. We need to manually set the bitmap to be fully opaque.
+ unsigned char* bytes = reinterpret_cast<unsigned char*>(info.bmBits);
+ if (!supportAlphaBlend)
+ setRGBABitmapAlpha(bytes, info.bmHeight * info.bmWidthBytes, 255);
+
+ // Need to make a cairo_surface_t out of the bitmap's pixel buffer and then draw
+ // it into our context.
+ cairo_surface_t* image = cairo_image_surface_create_for_data(bytes,
+ CAIRO_FORMAT_ARGB32,
+ info.bmWidth,
+ info.bmHeight,
+ info.bmWidthBytes);
+
+ // Scale the target surface to the new image size, and flip it
+ // so that when we set the srcImage as the surface it will draw
+ // right-side-up.
+ cairo_save(m_data->cr);
+ cairo_translate(m_data->cr, dstRect.x(), dstRect.height() + dstRect.y());
+ cairo_scale(m_data->cr, 1.0, -1.0);
+ cairo_set_source_surface(m_data->cr, image, 0, 0);
+
+ if (m_data->layers.size())
+ cairo_paint_with_alpha(m_data->cr, m_data->layers.last());
+ else
+ cairo_paint(m_data->cr);
+
+ // Delete all our junk.
+ cairo_surface_destroy(image);
+ ::DeleteDC(hdc);
+ ::DeleteObject(bitmap);
+ cairo_restore(m_data->cr);
+}
+
+void GraphicsContextPlatformPrivate::syncContext(PlatformGraphicsContext* cr)
+{
+ if (!cr)
+ return;
+
+ cairo_surface_t* surface = cairo_get_target(cr);
+ m_hdc = cairo_win32_surface_get_dc(surface);
+
+ SetGraphicsMode(m_hdc, GM_ADVANCED); // We need this call for themes to honor world transforms.
+}
+
+void GraphicsContextPlatformPrivate::flush()
+{
+ cairo_surface_t* surface = cairo_win32_surface_create(m_hdc);
+ cairo_surface_flush(surface);
+ cairo_surface_destroy(surface);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp
new file mode 100644
index 0000000..f1953e4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#if PLATFORM(CG)
+#include "GraphicsContextPlatformPrivateCG.h"
+#elif PLATFORM(CAIRO)
+#include "GraphicsContextPlatformPrivateCairo.h"
+#endif
+
+#include "AffineTransform.h"
+#include "BitmapInfo.h"
+#include "TransformationMatrix.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+static void fillWithClearColor(HBITMAP bitmap)
+{
+ BITMAP bmpInfo;
+ GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 0, bufferSize);
+}
+
+bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
+
+void GraphicsContext::setShouldIncludeChildWindows(bool include)
+{
+ m_data->m_shouldIncludeChildWindows = include;
+}
+
+bool GraphicsContext::shouldIncludeChildWindows() const
+{
+ return m_data->m_shouldIncludeChildWindows;
+}
+
+GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
+ : m_hdc(0)
+ , m_size(size)
+{
+ BitmapInfo bitmapInfo = BitmapInfo::create(m_size);
+
+ m_bitmap = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&m_bitmapBuffer), 0, 0);
+ if (!m_bitmap)
+ return;
+
+ m_hdc = CreateCompatibleDC(hdc);
+ SelectObject(m_hdc, m_bitmap);
+
+ BITMAP bmpInfo;
+ GetObject(m_bitmap, sizeof(bmpInfo), &bmpInfo);
+ m_bytesPerRow = bmpInfo.bmWidthBytes;
+ m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+
+ SetGraphicsMode(m_hdc, GM_ADVANCED);
+}
+
+GraphicsContext::WindowsBitmap::~WindowsBitmap()
+{
+ if (!m_bitmap)
+ return;
+
+ DeleteDC(m_hdc);
+ DeleteObject(m_bitmap);
+}
+
+GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize size)
+{
+ return new WindowsBitmap(m_data->m_hdc, size);
+}
+
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // FIXME: Should a bitmap be created also when a shadow is set?
+ if (mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer())) {
+ if (dstRect.isEmpty())
+ return 0;
+
+ // Create a bitmap DC in which to draw.
+ BitmapInfo bitmapInfo = BitmapInfo::create(dstRect.size());
+
+ void* pixels = 0;
+ HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ if (!bitmap)
+ return 0;
+
+ HDC bitmapDC = ::CreateCompatibleDC(m_data->m_hdc);
+ ::SelectObject(bitmapDC, bitmap);
+
+ // Fill our buffer with clear if we're going to alpha blend.
+ if (supportAlphaBlend)
+ fillWithClearColor(bitmap);
+
+ // Make sure we can do world transforms.
+ SetGraphicsMode(bitmapDC, GM_ADVANCED);
+
+ // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
+ XFORM xform = TransformationMatrix().translate(-dstRect.x(), -dstRect.y());
+
+ ::SetWorldTransform(bitmapDC, &xform);
+
+ return bitmapDC;
+ }
+
+ m_data->flush();
+ m_data->save();
+ return m_data->m_hdc;
+}
+
+void GraphicsContextPlatformPrivate::save()
+{
+ if (!m_hdc)
+ return;
+ SaveDC(m_hdc);
+}
+
+void GraphicsContextPlatformPrivate::restore()
+{
+ if (!m_hdc)
+ return;
+ RestoreDC(m_hdc, -1);
+}
+
+void GraphicsContextPlatformPrivate::clip(const FloatRect& clipRect)
+{
+ if (!m_hdc)
+ return;
+ IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.right(), clipRect.bottom());
+}
+
+void GraphicsContextPlatformPrivate::clip(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContextPlatformPrivate::scale(const FloatSize& size)
+{
+ if (!m_hdc)
+ return;
+
+ XFORM xform = TransformationMatrix().scaleNonUniform(size.width(), size.height());
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+static const double deg2rad = 0.017453292519943295769; // pi/180
+
+void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
+{
+ XFORM xform = TransformationMatrix().rotate(degreesAngle);
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContextPlatformPrivate::translate(float x , float y)
+{
+ if (!m_hdc)
+ return;
+
+ XFORM xform = TransformationMatrix().translate(x, y);
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
+{
+ if (!m_hdc)
+ return;
+
+ XFORM xform = transform.toTransformationMatrix();
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
new file mode 100644
index 0000000..984fd3f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
@@ -0,0 +1,757 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayerCACF.h"
+
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "Font.h"
+#include "FontSelector.h"
+#include "Image.h"
+#include "PlatformString.h"
+#include "SystemTime.h"
+#include "WebLayer.h"
+#include "WebTiledLayer.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/StringExtras.h>
+#include <wtf/text/CString.h>
+
+using namespace std;
+
+namespace WebCore {
+
+// The threshold width or height above which a tiled layer will be used. This should be
+// large enough to avoid tiled layers for most GraphicsLayers, but less than the D3D
+// texture size limit on all supported hardware.
+static const int cMaxPixelDimension = 2000;
+
+// The width and height of a single tile in a tiled layer. Should be large enough to
+// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
+// to keep the overall tile cost low.
+static const int cTiledLayerTileSize = 512;
+
+static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t)
+{
+ toT3D.m11 = narrowPrecisionToFloat(t.m11());
+ toT3D.m12 = narrowPrecisionToFloat(t.m12());
+ toT3D.m13 = narrowPrecisionToFloat(t.m13());
+ toT3D.m14 = narrowPrecisionToFloat(t.m14());
+ toT3D.m21 = narrowPrecisionToFloat(t.m21());
+ toT3D.m22 = narrowPrecisionToFloat(t.m22());
+ toT3D.m23 = narrowPrecisionToFloat(t.m23());
+ toT3D.m24 = narrowPrecisionToFloat(t.m24());
+ toT3D.m31 = narrowPrecisionToFloat(t.m31());
+ toT3D.m32 = narrowPrecisionToFloat(t.m32());
+ toT3D.m33 = narrowPrecisionToFloat(t.m33());
+ toT3D.m34 = narrowPrecisionToFloat(t.m34());
+ toT3D.m41 = narrowPrecisionToFloat(t.m41());
+ toT3D.m42 = narrowPrecisionToFloat(t.m42());
+ toT3D.m43 = narrowPrecisionToFloat(t.m43());
+ toT3D.m44 = narrowPrecisionToFloat(t.m44());
+}
+
+TransformationMatrix CAToTransform3D(const CATransform3D& fromT3D)
+{
+ return TransformationMatrix(
+ fromT3D.m11,
+ fromT3D.m12,
+ fromT3D.m13,
+ fromT3D.m14,
+ fromT3D.m21,
+ fromT3D.m22,
+ fromT3D.m23,
+ fromT3D.m24,
+ fromT3D.m31,
+ fromT3D.m32,
+ fromT3D.m33,
+ fromT3D.m34,
+ fromT3D.m41,
+ fromT3D.m42,
+ fromT3D.m43,
+ fromT3D.m44);
+}
+
+static void setLayerBorderColor(WKCACFLayer* layer, const Color& color)
+{
+ layer->setBorderColor(cachedCGColor(color, ColorSpaceDeviceRGB));
+}
+
+static void clearBorderColor(WKCACFLayer* layer)
+{
+ layer->setBorderColor(0);
+}
+
+static void setLayerBackgroundColor(WKCACFLayer* layer, const Color& color)
+{
+ layer->setBackgroundColor(cachedCGColor(color, ColorSpaceDeviceRGB));
+}
+
+static void clearLayerBackgroundColor(WKCACFLayer* layer)
+{
+ layer->setBackgroundColor(0);
+}
+
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerCACF(client);
+}
+
+GraphicsLayerCACF::GraphicsLayerCACF(GraphicsLayerClient* client)
+ : GraphicsLayer(client)
+ , m_contentsLayerPurpose(NoContentsLayer)
+ , m_contentsLayerHasBackgroundColor(false)
+{
+ m_layer = WebLayer::create(WKCACFLayer::Layer, this);
+
+ updateDebugIndicators();
+}
+
+GraphicsLayerCACF::~GraphicsLayerCACF()
+{
+ // clean up the WK layer
+ if (m_layer)
+ m_layer->removeFromSuperlayer();
+
+ if (m_contentsLayer)
+ m_contentsLayer->removeFromSuperlayer();
+
+ if (m_transformLayer)
+ m_transformLayer->removeFromSuperlayer();
+}
+
+void GraphicsLayerCACF::setName(const String& name)
+{
+ String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
+ GraphicsLayer::setName(longName);
+
+ m_layer->setName(longName);
+}
+
+bool GraphicsLayerCACF::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ bool childrenChanged = GraphicsLayer::setChildren(children);
+ // FIXME: GraphicsLayer::setChildren calls addChild() for each sublayer, which
+ // will end up calling updateSublayerList() N times.
+ if (childrenChanged)
+ updateSublayerList();
+
+ return childrenChanged;
+}
+
+void GraphicsLayerCACF::addChild(GraphicsLayer* childLayer)
+{
+ GraphicsLayer::addChild(childLayer);
+ updateSublayerList();
+}
+
+void GraphicsLayerCACF::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+ GraphicsLayer::addChildAtIndex(childLayer, index);
+ updateSublayerList();
+}
+
+void GraphicsLayerCACF::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildBelow(childLayer, sibling);
+ updateSublayerList();
+}
+
+void GraphicsLayerCACF::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer *sibling)
+{
+ GraphicsLayer::addChildAbove(childLayer, sibling);
+ updateSublayerList();
+}
+
+bool GraphicsLayerCACF::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ updateSublayerList();
+ return true;
+ }
+ return false;
+}
+
+void GraphicsLayerCACF::removeFromParent()
+{
+ GraphicsLayer::removeFromParent();
+ layerForSuperlayer()->removeFromSuperlayer();
+}
+
+void GraphicsLayerCACF::setPosition(const FloatPoint& point)
+{
+ GraphicsLayer::setPosition(point);
+ updateLayerPosition();
+}
+
+void GraphicsLayerCACF::setAnchorPoint(const FloatPoint3D& point)
+{
+ if (point == m_anchorPoint)
+ return;
+
+ GraphicsLayer::setAnchorPoint(point);
+ updateAnchorPoint();
+}
+
+void GraphicsLayerCACF::setSize(const FloatSize& size)
+{
+ if (size == m_size)
+ return;
+
+ GraphicsLayer::setSize(size);
+ updateLayerSize();
+}
+
+void GraphicsLayerCACF::setTransform(const TransformationMatrix& t)
+{
+ if (t == m_transform)
+ return;
+
+ GraphicsLayer::setTransform(t);
+ updateTransform();
+}
+
+void GraphicsLayerCACF::setChildrenTransform(const TransformationMatrix& t)
+{
+ if (t == m_childrenTransform)
+ return;
+
+ GraphicsLayer::setChildrenTransform(t);
+ updateChildrenTransform();
+}
+
+void GraphicsLayerCACF::setPreserves3D(bool preserves3D)
+{
+ if (preserves3D == m_preserves3D)
+ return;
+
+ GraphicsLayer::setPreserves3D(preserves3D);
+ updateLayerPreserves3D();
+}
+
+void GraphicsLayerCACF::setMasksToBounds(bool masksToBounds)
+{
+ if (masksToBounds == m_masksToBounds)
+ return;
+
+ GraphicsLayer::setMasksToBounds(masksToBounds);
+ updateMasksToBounds();
+}
+
+void GraphicsLayerCACF::setDrawsContent(bool drawsContent)
+{
+ if (drawsContent == m_drawsContent)
+ return;
+
+ GraphicsLayer::setDrawsContent(drawsContent);
+ updateLayerDrawsContent();
+}
+
+void GraphicsLayerCACF::setBackgroundColor(const Color& color)
+{
+ if (m_backgroundColorSet && m_backgroundColor == color)
+ return;
+
+ GraphicsLayer::setBackgroundColor(color);
+
+ m_contentsLayerHasBackgroundColor = true;
+ updateLayerBackgroundColor();
+}
+
+void GraphicsLayerCACF::clearBackgroundColor()
+{
+ if (!m_backgroundColorSet)
+ return;
+
+ GraphicsLayer::clearBackgroundColor();
+ clearLayerBackgroundColor(m_contentsLayer.get());
+}
+
+void GraphicsLayerCACF::setContentsOpaque(bool opaque)
+{
+ if (m_contentsOpaque == opaque)
+ return;
+
+ GraphicsLayer::setContentsOpaque(opaque);
+ updateContentsOpaque();
+}
+
+void GraphicsLayerCACF::setBackfaceVisibility(bool visible)
+{
+ if (m_backfaceVisibility == visible)
+ return;
+
+ GraphicsLayer::setBackfaceVisibility(visible);
+ updateBackfaceVisibility();
+}
+
+void GraphicsLayerCACF::setOpacity(float opacity)
+{
+ float clampedOpacity = max(min(opacity, 1.0f), 0.0f);
+
+ if (m_opacity == clampedOpacity)
+ return;
+
+ GraphicsLayer::setOpacity(clampedOpacity);
+ primaryLayer()->setOpacity(opacity);
+}
+
+void GraphicsLayerCACF::setNeedsDisplay()
+{
+ if (drawsContent())
+ m_layer->setNeedsDisplay();
+}
+
+void GraphicsLayerCACF::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ if (drawsContent()) {
+ CGRect cgRect = rect;
+ m_layer->setNeedsDisplay(&cgRect);
+ }
+}
+
+void GraphicsLayerCACF::setContentsRect(const IntRect& rect)
+{
+ if (rect == m_contentsRect)
+ return;
+
+ GraphicsLayer::setContentsRect(rect);
+ updateContentsRect();
+}
+
+void GraphicsLayerCACF::setContentsToImage(Image* image)
+{
+ bool childrenChanged = false;
+
+ if (image) {
+ m_pendingContentsImage = image->nativeImageForCurrentFrame();
+ m_contentsLayerPurpose = ContentsLayerForImage;
+ if (!m_contentsLayer)
+ childrenChanged = true;
+ } else {
+ m_pendingContentsImage = 0;
+ m_contentsLayerPurpose = NoContentsLayer;
+ if (m_contentsLayer)
+ childrenChanged = true;
+ }
+
+ updateContentsImage();
+
+ // This has to happen after updateContentsImage
+ if (childrenChanged)
+ updateSublayerList();
+}
+
+void GraphicsLayerCACF::setContentsToMedia(PlatformLayer* mediaLayer)
+{
+ if (mediaLayer == m_contentsLayer)
+ return;
+
+ m_contentsLayer = mediaLayer;
+ m_contentsLayerPurpose = mediaLayer ? ContentsLayerForMedia : NoContentsLayer;
+
+ updateContentsMedia();
+
+ // This has to happen after updateContentsMedia
+ updateSublayerList();
+}
+
+PlatformLayer* GraphicsLayerCACF::hostLayerForSublayers() const
+{
+ return m_transformLayer ? m_transformLayer.get() : m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerCACF::layerForSuperlayer() const
+{
+ return m_transformLayer ? m_transformLayer.get() : m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerCACF::platformLayer() const
+{
+ return primaryLayer();
+}
+
+void GraphicsLayerCACF::setDebugBackgroundColor(const Color& color)
+{
+ if (color.isValid())
+ setLayerBackgroundColor(m_layer.get(), color);
+ else
+ clearLayerBackgroundColor(m_layer.get());
+}
+
+void GraphicsLayerCACF::setDebugBorder(const Color& color, float borderWidth)
+{
+ if (color.isValid()) {
+ setLayerBorderColor(m_layer.get(), color);
+ m_layer->setBorderWidth(borderWidth);
+ } else {
+ clearBorderColor(m_layer.get());
+ m_layer->setBorderWidth(0);
+ }
+}
+
+bool GraphicsLayerCACF::requiresTiledLayer(const FloatSize& size) const
+{
+ if (!m_drawsContent)
+ return false;
+
+ // FIXME: catch zero-size height or width here (or earlier)?
+ return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension;
+}
+
+void GraphicsLayerCACF::swapFromOrToTiledLayer(bool useTiledLayer)
+{
+ if (useTiledLayer == m_usingTiledLayer)
+ return;
+
+ CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize);
+
+ RefPtr<WKCACFLayer> oldLayer = m_layer;
+ if (useTiledLayer)
+ m_layer = WebTiledLayer::create(tileSize, this);
+ else
+ m_layer = WebLayer::create(WKCACFLayer::Layer, this);
+
+ m_usingTiledLayer = useTiledLayer;
+
+ m_layer->adoptSublayers(oldLayer.get());
+ if (oldLayer->superlayer())
+ oldLayer->superlayer()->replaceSublayer(oldLayer.get(), m_layer.get());
+
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+ updateMasksToBounds();
+ updateContentsOpaque();
+ updateBackfaceVisibility();
+ updateLayerBackgroundColor();
+
+ updateOpacityOnLayer();
+
+#ifndef NDEBUG
+ String name = String::format("CALayer(%p) GraphicsLayer(%p) %s", m_layer.get(), this, m_usingTiledLayer ? "[Tiled Layer] " : "") + m_name;
+ m_layer->setName(name);
+#endif
+
+ // need to tell new layer to draw itself
+ setNeedsDisplay();
+
+ updateDebugIndicators();
+}
+
+GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCACF::defaultContentsOrientation() const
+{
+ return CompositingCoordinatesTopDown;
+}
+
+void GraphicsLayerCACF::updateSublayerList()
+{
+ Vector<RefPtr<WKCACFLayer> > newSublayers;
+
+ if (m_transformLayer) {
+ // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind.
+ newSublayers.append(m_layer.get());
+ } else if (m_contentsLayer) {
+ // FIXME: add the contents layer in the correct order with negative z-order children.
+ // This does not cause visible rendering issues because currently contents layers are only used
+ // for replaced elements that don't have children.
+ newSublayers.append(m_contentsLayer.get());
+ }
+
+ const Vector<GraphicsLayer*>& childLayers = children();
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerCACF* curChild = static_cast<GraphicsLayerCACF*>(childLayers[i]);
+
+ WKCACFLayer* childLayer = curChild->layerForSuperlayer();
+ newSublayers.append(childLayer);
+ }
+
+ for (int i = 0; i < newSublayers.size(); ++i)
+ newSublayers[i]->removeFromSuperlayer();
+
+ if (m_transformLayer) {
+ m_transformLayer->setSublayers(newSublayers);
+
+ if (m_contentsLayer) {
+ // If we have a transform layer, then the contents layer is parented in the
+ // primary layer (which is itself a child of the transform layer).
+ m_layer->removeAllSublayers();
+ m_layer->addSublayer(m_contentsLayer);
+ }
+ } else
+ m_layer->setSublayers(newSublayers);
+}
+
+void GraphicsLayerCACF::updateLayerPosition()
+{
+ // Position is offset on the layer by the layer anchor point.
+ CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
+ m_position.y() + m_anchorPoint.y() * m_size.height());
+
+ primaryLayer()->setPosition(posPoint);
+}
+
+void GraphicsLayerCACF::updateLayerSize()
+{
+ CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height());
+ if (m_transformLayer) {
+ m_transformLayer->setBounds(rect);
+ // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative.
+ CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ m_layer->setPosition(centerPoint);
+ }
+
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ m_layer->setBounds(rect);
+
+ // Note that we don't resize m_contentsLayer. It's up the caller to do that.
+
+ // if we've changed the bounds, we need to recalculate the position
+ // of the layer, taking anchor point into account.
+ updateLayerPosition();
+}
+
+void GraphicsLayerCACF::updateAnchorPoint()
+{
+ primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y()));
+ primaryLayer()->setAnchorPointZ(m_anchorPoint.z());
+ updateLayerPosition();
+}
+
+void GraphicsLayerCACF::updateTransform()
+{
+ CATransform3D transform;
+ copyTransform(transform, m_transform);
+ primaryLayer()->setTransform(transform);
+}
+
+void GraphicsLayerCACF::updateChildrenTransform()
+{
+ CATransform3D transform;
+ copyTransform(transform, m_childrenTransform);
+ primaryLayer()->setSublayerTransform(transform);
+}
+
+void GraphicsLayerCACF::updateMasksToBounds()
+{
+ m_layer->setMasksToBounds(m_masksToBounds);
+ updateDebugIndicators();
+}
+
+void GraphicsLayerCACF::updateContentsOpaque()
+{
+ m_layer->setOpaque(m_contentsOpaque);
+}
+
+void GraphicsLayerCACF::updateBackfaceVisibility()
+{
+ m_layer->setDoubleSided(m_backfaceVisibility);
+}
+
+void GraphicsLayerCACF::updateLayerPreserves3D()
+{
+ if (m_preserves3D && !m_transformLayer) {
+ // Create the transform layer.
+ m_transformLayer = WebLayer::create(WKCACFLayer::TransformLayer, this);
+
+#ifndef NDEBUG
+ m_transformLayer->setName(String().format("Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this));
+#endif
+ // Copy the position from this layer.
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+
+ CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ m_layer->setPosition(point);
+
+ m_layer->setAnchorPoint(CGPointMake(0.5f, 0.5f));
+ m_layer->setTransform(CATransform3DIdentity);
+
+ // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer.
+ m_layer->setOpacity(1);
+
+ // Move this layer to be a child of the transform layer.
+ if (m_layer->superlayer())
+ m_layer->superlayer()->replaceSublayer(m_layer.get(), m_transformLayer.get());
+ m_transformLayer->addSublayer(m_layer.get());
+
+ updateSublayerList();
+ } else if (!m_preserves3D && m_transformLayer) {
+ // Relace the transformLayer in the parent with this layer.
+ m_layer->removeFromSuperlayer();
+ m_transformLayer->superlayer()->replaceSublayer(m_transformLayer.get(), m_layer.get());
+
+ // Release the transform layer.
+ m_transformLayer = 0;
+
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+
+ updateSublayerList();
+ }
+
+ updateOpacityOnLayer();
+}
+
+void GraphicsLayerCACF::updateLayerDrawsContent()
+{
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ if (m_drawsContent)
+ m_layer->setNeedsDisplay();
+ else
+ m_layer->setContents(0);
+
+ updateDebugIndicators();
+}
+
+void GraphicsLayerCACF::updateLayerBackgroundColor()
+{
+ if (!m_contentsLayer)
+ return;
+
+ // We never create the contents layer just for background color yet.
+ if (m_backgroundColorSet)
+ setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
+ else
+ clearLayerBackgroundColor(m_contentsLayer.get());
+}
+
+void GraphicsLayerCACF::updateContentsImage()
+{
+ if (m_pendingContentsImage) {
+ if (!m_contentsLayer.get()) {
+ RefPtr<WKCACFLayer> imageLayer = WebLayer::create(WKCACFLayer::Layer, this);
+#ifndef NDEBUG
+ imageLayer->setName("Image Layer");
+#endif
+ setupContentsLayer(imageLayer.get());
+ m_contentsLayer = imageLayer;
+ // m_contentsLayer will be parented by updateSublayerList
+ }
+
+ // FIXME: maybe only do trilinear if the image is being scaled down,
+ // but then what if the layer size changes?
+ m_contentsLayer->setMinificationFilter(WKCACFLayer::Trilinear);
+ m_contentsLayer->setContents(m_pendingContentsImage.get());
+ m_pendingContentsImage = 0;
+
+ updateContentsRect();
+ } else {
+ // No image.
+ // m_contentsLayer will be removed via updateSublayerList.
+ m_contentsLayer = 0;
+ }
+}
+
+void GraphicsLayerCACF::updateContentsMedia()
+{
+ // Media layer was set as m_contentsLayer, and will get parented in updateSublayerList().
+ if (m_contentsLayer) {
+ setupContentsLayer(m_contentsLayer.get());
+ updateContentsRect();
+ }
+}
+
+void GraphicsLayerCACF::updateContentsRect()
+{
+ if (!m_contentsLayer)
+ return;
+
+ CGPoint point = CGPointMake(m_contentsRect.x(),
+ m_contentsRect.y());
+ CGRect rect = CGRectMake(0.0f,
+ 0.0f,
+ m_contentsRect.width(),
+ m_contentsRect.height());
+
+ m_contentsLayer->setPosition(point);
+ m_contentsLayer->setBounds(rect);
+}
+
+void GraphicsLayerCACF::setupContentsLayer(WKCACFLayer* contentsLayer)
+{
+ if (contentsLayer == m_contentsLayer)
+ return;
+
+ if (m_contentsLayer) {
+ m_contentsLayer->removeFromSuperlayer();
+ m_contentsLayer = 0;
+ }
+
+ if (contentsLayer) {
+ m_contentsLayer = contentsLayer;
+
+ if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) {
+ CATransform3D flipper = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f};
+ m_contentsLayer->setTransform(flipper);
+ m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 1.0f));
+ } else
+ m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 0.0f));
+
+ // Insert the content layer first. Video elements require this, because they have
+ // shadow content that must display in front of the video.
+ m_layer->insertSublayer(m_contentsLayer.get(), 0);
+
+ updateContentsRect();
+
+ if (showDebugBorders()) {
+ setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180));
+ m_contentsLayer->setBorderWidth(1.0f);
+ }
+ }
+ updateDebugIndicators();
+}
+
+// This function simply mimics the operation of GraphicsLayerCA
+void GraphicsLayerCACF::updateOpacityOnLayer()
+{
+ primaryLayer()->setOpacity(m_opacity);
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.h b/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.h
new file mode 100644
index 0000000..23f36b2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 GraphicsLayerCACF_h
+#define GraphicsLayerCACF_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayer.h"
+#include "GraphicsContext.h"
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+class WKCACFLayer;
+
+class GraphicsLayerCACF : public GraphicsLayer {
+public:
+
+ GraphicsLayerCACF(GraphicsLayerClient*);
+ virtual ~GraphicsLayerCACF();
+
+ virtual void setName(const String& inName);
+
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
+ virtual void addChild(GraphicsLayer *layer);
+ virtual void addChildAtIndex(GraphicsLayer *layer, int index);
+ virtual void addChildAbove(GraphicsLayer *layer, GraphicsLayer *sibling);
+ virtual void addChildBelow(GraphicsLayer *layer, GraphicsLayer *sibling);
+ virtual bool replaceChild(GraphicsLayer *oldChild, GraphicsLayer *newChild);
+
+ virtual void removeFromParent();
+
+ virtual void setPosition(const FloatPoint& inPoint);
+ virtual void setAnchorPoint(const FloatPoint3D& inPoint);
+ virtual void setSize(const FloatSize& inSize);
+
+ virtual void setTransform(const TransformationMatrix&);
+
+ virtual void setChildrenTransform(const TransformationMatrix&);
+
+ virtual void setPreserves3D(bool);
+ virtual void setMasksToBounds(bool);
+ virtual void setDrawsContent(bool);
+
+ virtual void setBackgroundColor(const Color&);
+ virtual void clearBackgroundColor();
+
+ virtual void setContentsOpaque(bool);
+ virtual void setBackfaceVisibility(bool);
+
+ virtual void setOpacity(float opacity);
+
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+
+ virtual void setContentsRect(const IntRect&);
+
+ virtual void setContentsToImage(Image*);
+ virtual void setContentsToMedia(PlatformLayer*);
+
+ virtual PlatformLayer* platformLayer() const;
+
+ virtual void setDebugBackgroundColor(const Color&);
+ virtual void setDebugBorder(const Color&, float borderWidth);
+
+private:
+ void updateOpacityOnLayer();
+
+ WKCACFLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
+ WKCACFLayer* hostLayerForSublayers() const;
+ WKCACFLayer* layerForSuperlayer() const;
+
+ bool requiresTiledLayer(const FloatSize&) const;
+ void swapFromOrToTiledLayer(bool useTiledLayer);
+
+ CompositingCoordinatesOrientation defaultContentsOrientation() const;
+ void updateSublayerList();
+ void updateLayerPosition();
+ void updateLayerSize();
+ void updateAnchorPoint();
+ void updateTransform();
+ void updateChildrenTransform();
+ void updateMasksToBounds();
+ void updateContentsOpaque();
+ void updateBackfaceVisibility();
+ void updateLayerPreserves3D();
+ void updateLayerDrawsContent();
+ void updateLayerBackgroundColor();
+
+ void updateContentsImage();
+ void updateContentsMedia();
+ void updateContentsRect();
+
+ void setupContentsLayer(WKCACFLayer*);
+ WKCACFLayer* contentsLayer() const { return m_contentsLayer.get(); }
+
+ RefPtr<WKCACFLayer> m_layer;
+ RefPtr<WKCACFLayer> m_transformLayer;
+ RefPtr<WKCACFLayer> m_contentsLayer;
+
+ enum ContentsLayerPurpose {
+ NoContentsLayer = 0,
+ ContentsLayerForImage,
+ ContentsLayerForMedia
+ };
+
+ ContentsLayerPurpose m_contentsLayerPurpose;
+ bool m_contentsLayerHasBackgroundColor : 1;
+ RetainPtr<CGImageRef> m_pendingContentsImage;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayerCACF_h
diff --git a/Source/WebCore/platform/graphics/win/IconWin.cpp b/Source/WebCore/platform/graphics/win/IconWin.cpp
new file mode 100644
index 0000000..4d4d219
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/IconWin.cpp
@@ -0,0 +1,99 @@
+/*
+* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+* Copyright (C) 2007-2009 Torch Mobile, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public License
+* along with this library; see the file COPYING.LIB. If not, write to
+* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+* Boston, MA 02110-1301, USA.
+*
+*/
+
+#include "config.h"
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "LocalWindowsContext.h"
+#include "PlatformString.h"
+#include <tchar.h>
+#include <windows.h>
+
+#if OS(WINCE)
+// SHGFI_SHELLICONSIZE is not available on WINCE
+#define SHGFI_SHELLICONSIZE 0
+#endif
+
+namespace WebCore {
+
+static const int shell32MultipleFileIconIndex = 54;
+
+Icon::Icon(HICON icon)
+ : m_hIcon(icon)
+{
+ ASSERT(icon);
+}
+
+Icon::~Icon()
+{
+ DestroyIcon(m_hIcon);
+}
+
+// FIXME: Move the code to ChromeClient::iconForFiles().
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ if (filenames.isEmpty())
+ return 0;
+
+ if (filenames.size() == 1) {
+ SHFILEINFO sfi;
+ memset(&sfi, 0, sizeof(sfi));
+
+ String tmpFilename = filenames[0];
+ if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON))
+ return 0;
+
+ return adoptRef(new Icon(sfi.hIcon));
+ }
+
+#if OS(WINCE)
+ return 0;
+#else
+ TCHAR buffer[MAX_PATH];
+ UINT length = ::GetSystemDirectory(buffer, WTF_ARRAY_LENGTH(buffer));
+ if (!length)
+ return 0;
+
+ if (_tcscat_s(buffer, TEXT("\\shell32.dll")))
+ return 0;
+
+ HICON hIcon;
+ if (!::ExtractIconEx(buffer, shell32MultipleFileIconIndex, 0, &hIcon, 1))
+ return 0;
+ return adoptRef(new Icon(hIcon));
+#endif
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& r)
+{
+ if (context->paintingDisabled())
+ return;
+
+#if OS(WINCE)
+ context->drawIcon(m_hIcon, r, DI_NORMAL);
+#else
+ LocalWindowsContext windowContext(context, r);
+ DrawIconEx(windowContext.hdc(), r.x(), r.y(), m_hIcon, r.width(), r.height(), 0, 0, DI_NORMAL);
+#endif
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/ImageCGWin.cpp b/Source/WebCore/platform/graphics/win/ImageCGWin.cpp
new file mode 100644
index 0000000..6cc5d6d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/ImageCGWin.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "BitmapImage.h"
+#include "BitmapInfo.h"
+#include "GraphicsContextCG.h"
+#include "PlatformString.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <windows.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap)
+{
+ DIBSECTION dibSection;
+ if (!GetObject(hBitmap, sizeof(DIBSECTION), &dibSection))
+ return 0;
+
+ ASSERT(dibSection.dsBm.bmBitsPixel == 32);
+ if (dibSection.dsBm.bmBitsPixel != 32)
+ return 0;
+
+ ASSERT(dibSection.dsBm.bmBits);
+ if (!dibSection.dsBm.bmBits)
+ return 0;
+
+ RetainPtr<CGContextRef> bitmapContext(AdoptCF, CGBitmapContextCreate(dibSection.dsBm.bmBits, dibSection.dsBm.bmWidth, dibSection.dsBm.bmHeight, 8,
+ dibSection.dsBm.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
+
+ // The BitmapImage takes ownership of this.
+ CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext.get());
+
+ return adoptRef(new BitmapImage(cgImage));
+}
+
+bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
+{
+ ASSERT(bmp);
+
+ BITMAP bmpInfo;
+ GetObject(bmp, sizeof(BITMAP), &bmpInfo);
+
+ ASSERT(bmpInfo.bmBitsPixel == 32);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+
+ CGContextRef cgContext = CGBitmapContextCreate(bmpInfo.bmBits, bmpInfo.bmWidth, bmpInfo.bmHeight,
+ 8, bmpInfo.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
+
+ GraphicsContext gc(cgContext);
+
+ IntSize imageSize = BitmapImage::size();
+ if (size)
+ drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), ColorSpaceDeviceRGB, CompositeCopy);
+ else
+ draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy);
+
+ // Do cleanup
+ CGContextRelease(cgContext);
+
+ return true;
+}
+
+void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ size_t frames = frameCount();
+ for (size_t i = 0; i < frames; ++i) {
+ CGImageRef image = frameAtIndex(i);
+ if (CGImageGetHeight(image) == static_cast<size_t>(srcSize.height()) && CGImageGetWidth(image) == static_cast<size_t>(srcSize.width())) {
+ size_t currentFrame = m_currentFrame;
+ m_currentFrame = i;
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), styleColorSpace, compositeOp);
+ m_currentFrame = currentFrame;
+ return;
+ }
+ }
+
+ // No image of the correct size was found, fallback to drawing the current frame
+ IntSize imageSize = BitmapImage::size();
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), styleColorSpace, compositeOp);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/win/ImageCairoWin.cpp b/Source/WebCore/platform/graphics/win/ImageCairoWin.cpp
new file mode 100644
index 0000000..70b132e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/ImageCairoWin.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include <cairo.h>
+#include <cairo-win32.h>
+
+#include <windows.h>
+#include "PlatformString.h"
+
+namespace WebCore {
+
+PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap)
+{
+ DIBSECTION dibSection;
+ if (!GetObject(hBitmap, sizeof(DIBSECTION), &dibSection))
+ return 0;
+
+ ASSERT(dibSection.dsBm.bmBitsPixel == 32);
+ if (dibSection.dsBm.bmBitsPixel != 32)
+ return 0;
+
+ ASSERT(dibSection.dsBm.bmBits);
+ if (!dibSection.dsBm.bmBits)
+ return 0;
+
+ cairo_surface_t* image = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, dibSection.dsBm.bmWidth, dibSection.dsBm.bmHeight);
+
+ // The BitmapImage object takes over ownership of the cairo_surface_t*, so no need to destroy here.
+ return adoptRef(new BitmapImage(image));
+}
+
+bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
+{
+ ASSERT(bmp);
+
+ BITMAP bmpInfo;
+ GetObject(bmp, sizeof(BITMAP), &bmpInfo);
+
+ // If this is a 32bpp bitmap, which it always should be, we'll clear it so alpha-wise it will be visible
+ if (bmpInfo.bmBitsPixel == 32) {
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 255, bufferSize);
+ }
+
+ cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)bmpInfo.bmBits,
+ CAIRO_FORMAT_ARGB32,
+ bmpInfo.bmWidth,
+ bmpInfo.bmHeight,
+ bmpInfo.bmWidthBytes);
+
+
+ cairo_t* targetRef = cairo_create(image);
+ cairo_surface_destroy(image);
+
+ GraphicsContext gc(targetRef);
+
+ IntSize imageSize = BitmapImage::size();
+ if (size)
+ drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), ColorSpaceDeviceRGB, CompositeCopy);
+ else
+ draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy);
+
+ // Do cleanup
+ cairo_destroy(targetRef);
+
+ return true;
+}
+
+void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ size_t frames = frameCount();
+ for (size_t i = 0; i < frames; ++i) {
+ cairo_surface_t* image = frameAtIndex(i);
+ if (cairo_image_surface_get_height(image) == static_cast<size_t>(srcSize.height()) && cairo_image_surface_get_width(image) == static_cast<size_t>(srcSize.width())) {
+ size_t currentFrame = m_currentFrame;
+ m_currentFrame = i;
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), ColorSpaceDeviceRGB, compositeOp);
+ m_currentFrame = currentFrame;
+ return;
+ }
+ }
+
+ // No image of the correct size was found, fallback to drawing the current frame
+ IntSize imageSize = BitmapImage::size();
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, compositeOp);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/win/ImageWin.cpp b/Source/WebCore/platform/graphics/win/ImageWin.cpp
new file mode 100644
index 0000000..54c5b41
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/ImageWin.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+#include "BitmapImage.h"
+
+#include "SharedBuffer.h"
+
+// This function loads resources from WebKit
+PassRefPtr<WebCore::SharedBuffer> loadResourceIntoBuffer(const char*);
+
+namespace WebCore {
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ RefPtr<SharedBuffer> buffer = loadResourceIntoBuffer(name);
+ RefPtr<BitmapImage> img = BitmapImage::create();
+ img->setData(buffer.release(), true);
+ return img.release();
+}
+
+bool BitmapImage::getHBITMAP(HBITMAP bmp)
+{
+ return getHBITMAPOfSize(bmp, 0);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/win/IntPointWin.cpp b/Source/WebCore/platform/graphics/win/IntPointWin.cpp
new file mode 100644
index 0000000..73db199
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/IntPointWin.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const POINT& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator POINT() const
+{
+ POINT p = {m_x, m_y};
+ return p;
+}
+
+IntPoint::IntPoint(const POINTS& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator POINTS() const
+{
+ POINTS p = {m_x, m_y};
+ return p;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/IntRectWin.cpp b/Source/WebCore/platform/graphics/win/IntRectWin.cpp
new file mode 100644
index 0000000..fe25a7f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/IntRectWin.cpp
@@ -0,0 +1,45 @@
+
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntRect::IntRect(const RECT& r)
+ : m_location(IntPoint(r.left, r.top)), m_size(IntSize(r.right-r.left, r.bottom-r.top))
+{
+}
+
+IntRect::operator RECT() const
+{
+ RECT rect = { x(), y(), right(), bottom() };
+ return rect;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/IntSizeWin.cpp b/Source/WebCore/platform/graphics/win/IntSizeWin.cpp
new file mode 100644
index 0000000..26e68da
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/IntSizeWin.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntSize.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntSize::IntSize(const SIZE& s)
+ : m_width(s.cx)
+ , m_height(s.cy)
+{
+}
+
+IntSize::operator SIZE() const
+{
+ SIZE s = {m_width, m_height};
+ return s;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/LocalWindowsContext.h b/Source/WebCore/platform/graphics/win/LocalWindowsContext.h
new file mode 100644
index 0000000..c216140
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/LocalWindowsContext.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 LocalWindowsContext_h
+#define LocalWindowsContext_h
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+class LocalWindowsContext : public Noncopyable {
+public:
+ LocalWindowsContext(GraphicsContext* graphicsContext, const IntRect& rect, bool supportAlphaBlend = true, bool mayCreateBitmap = true)
+ : m_graphicsContext(graphicsContext)
+ , m_rect(rect)
+ , m_supportAlphaBlend(supportAlphaBlend)
+ , m_mayCreateBitmap(mayCreateBitmap)
+ {
+ m_hdc = m_graphicsContext->getWindowsContext(m_rect, m_supportAlphaBlend, m_mayCreateBitmap);
+ }
+
+ ~LocalWindowsContext()
+ {
+ m_graphicsContext->releaseWindowsContext(m_hdc, m_rect, m_supportAlphaBlend, m_mayCreateBitmap);
+ }
+
+ HDC hdc() const { return m_hdc; }
+
+private:
+ GraphicsContext* m_graphicsContext;
+ HDC m_hdc;
+ IntRect m_rect;
+ bool m_supportAlphaBlend;
+ bool m_mayCreateBitmap;
+};
+
+} // namespace WebCore
+#endif // LocalWindowsContext_h
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp
new file mode 100644
index 0000000..cbe38aa
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "MediaPlayerPrivateFullscreenWindow.h"
+
+#include "IntRect.h"
+#include "WebCoreInstanceHandle.h"
+#include <windows.h>
+
+#if PLATFORM(CG)
+#include <CoreGraphics/CGColor.h>
+#endif
+
+namespace WebCore {
+
+MediaPlayerPrivateFullscreenWindow::MediaPlayerPrivateFullscreenWindow(MediaPlayerPrivateFullscreenClient* client)
+ : m_client(client)
+ , m_hwnd(0)
+#if USE(ACCELERATED_COMPOSITING)
+ , m_layerRenderer(WKCACFLayerRenderer::create(0))
+#endif
+{
+}
+
+MediaPlayerPrivateFullscreenWindow::~MediaPlayerPrivateFullscreenWindow()
+{
+ if (m_hwnd)
+ close();
+}
+
+void MediaPlayerPrivateFullscreenWindow::createWindow(HWND parentHwnd)
+{
+ static ATOM windowAtom;
+ static LPCWSTR windowClassName = L"MediaPlayerPrivateFullscreenWindowClass";
+ if (!windowAtom) {
+ WNDCLASSEX wcex = {0};
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = staticWndProc;
+ wcex.hInstance = instanceHandle();
+ wcex.lpszClassName = windowClassName;
+ windowAtom = ::RegisterClassEx(&wcex);
+ }
+
+ if (m_hwnd)
+ close();
+
+ MONITORINFO mi = {0};
+ mi.cbSize = sizeof(MONITORINFO);
+ if (!GetMonitorInfo(MonitorFromWindow(parentHwnd, MONITOR_DEFAULTTONEAREST), &mi))
+ return;
+
+ IntRect monitorRect = mi.rcMonitor;
+
+ ::CreateWindowExW(WS_EX_TOOLWINDOW, windowClassName, L"", WS_POPUP | WS_VISIBLE,
+ monitorRect.x(), monitorRect.y(), monitorRect.width(), monitorRect.height(),
+ parentHwnd, 0, WebCore::instanceHandle(), this);
+ ASSERT(IsWindow(m_hwnd));
+
+ ::SetFocus(m_hwnd);
+}
+
+void MediaPlayerPrivateFullscreenWindow::close()
+{
+ ::DestroyWindow(m_hwnd);
+ ASSERT(!m_hwnd);
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+void MediaPlayerPrivateFullscreenWindow::setRootChildLayer(PassRefPtr<PlatformCALayer> rootChild)
+{
+ if (m_rootChild == rootChild)
+ return;
+
+ if (m_rootChild)
+ m_rootChild->removeFromSuperlayer();
+
+ m_rootChild = rootChild;
+
+ if (!m_rootChild)
+ return;
+
+ m_layerRenderer->setRootChildLayer(m_rootChild.get());
+ PlatformCALayer* rootLayer = m_rootChild->rootLayer();
+ CGRect rootBounds = m_rootChild->rootLayer()->bounds();
+ m_rootChild->setFrame(rootBounds);
+ m_rootChild->setBackgroundColor(CGColorGetConstantColor(kCGColorBlack));
+#ifndef NDEBUG
+ RetainPtr<CGColorRef> redColor(AdoptCF, CGColorCreateGenericRGB(1, 0, 0, 1));
+ rootLayer->setBackgroundColor(redColor.get());
+#else
+ rootLayer->setBackgroundColor(CGColorGetConstantColor(kCGColorBlack));
+#endif
+}
+#endif
+
+LRESULT MediaPlayerPrivateFullscreenWindow::staticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LONG_PTR longPtr = GetWindowLongPtr(hWnd, GWLP_USERDATA);
+
+ if (!longPtr && message == WM_CREATE) {
+ LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
+ longPtr = reinterpret_cast<LONG_PTR>(lpcs->lpCreateParams);
+ ::SetWindowLongPtr(hWnd, GWLP_USERDATA, longPtr);
+ }
+
+ if (MediaPlayerPrivateFullscreenWindow* window = reinterpret_cast<MediaPlayerPrivateFullscreenWindow*>(longPtr))
+ return window->wndProc(hWnd, message, wParam, lParam);
+
+ return ::DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+LRESULT MediaPlayerPrivateFullscreenWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT lResult = 0;
+ switch (message) {
+ case WM_CREATE:
+ m_hwnd = hWnd;
+#if USE(ACCELERATED_COMPOSITING)
+ m_layerRenderer->setHostWindow(m_hwnd);
+ m_layerRenderer->createRenderer();
+ if (m_rootChild)
+ m_layerRenderer->setNeedsDisplay();
+#endif
+ break;
+ case WM_DESTROY:
+ m_hwnd = 0;
+#if USE(ACCELERATED_COMPOSITING)
+ m_layerRenderer->destroyRenderer();
+ m_layerRenderer->setHostWindow(0);
+#endif
+ break;
+ case WM_WINDOWPOSCHANGED:
+ {
+ LPWINDOWPOS wp = reinterpret_cast<LPWINDOWPOS>(lParam);
+ if (wp->flags & SWP_NOSIZE)
+ break;
+#if USE(ACCELERATED_COMPOSITING)
+ m_layerRenderer->resize();
+ PlatformCALayer* rootLayer = m_rootChild->rootLayer();
+ CGRect rootBounds = m_rootChild->rootLayer()->bounds();
+ m_rootChild->setFrame(rootBounds);
+ m_rootChild->setNeedsLayout();
+#endif
+ }
+ break;
+ case WM_PAINT:
+#if USE(ACCELERATED_COMPOSITING)
+ m_layerRenderer->renderSoon();
+#endif
+ break;
+ }
+
+ if (m_client)
+ lResult = m_client->fullscreenClientWndProc(hWnd, message, wParam, lParam);
+
+ return lResult;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h
new file mode 100644
index 0000000..a18f0cc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 MediaPlayerPrivateFullscreenWindow_h
+#define MediaPlayerPrivateFullscreenWindow_h
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "PlatformCALayer.h"
+#include "WKCACFLayerRenderer.h"
+#endif
+#include <wtf/OwnPtr.h>
+
+typedef unsigned WPARAM;
+typedef long LPARAM;
+typedef struct HWND__* HWND;
+typedef _W64 long LONG_PTR;
+typedef LONG_PTR LRESULT;
+typedef unsigned int UINT;
+
+namespace WebCore {
+
+class MediaPlayerPrivateFullscreenClient {
+public:
+ virtual LRESULT fullscreenClientWndProc(HWND, UINT message, WPARAM, LPARAM) = 0;
+protected:
+ virtual ~MediaPlayerPrivateFullscreenClient() {}
+};
+
+class MediaPlayerPrivateFullscreenWindow {
+public:
+ MediaPlayerPrivateFullscreenWindow(MediaPlayerPrivateFullscreenClient*);
+ ~MediaPlayerPrivateFullscreenWindow();
+
+ void createWindow(HWND ownerWindow);
+ void close();
+
+ HWND hwnd() const { return m_hwnd; }
+
+#if USE(ACCELERATED_COMPOSITING)
+ WKCACFLayerRenderer* layerRenderer() const { return m_layerRenderer.get(); }
+
+ PlatformCALayer* rootChildLayer() const { return m_rootChild.get(); }
+ void setRootChildLayer(PassRefPtr<PlatformCALayer>);
+#endif
+
+private:
+ static LRESULT __stdcall staticWndProc(HWND, UINT message, WPARAM, LPARAM);
+ LRESULT wndProc(HWND, UINT message, WPARAM, LPARAM);
+
+ MediaPlayerPrivateFullscreenClient* m_client;
+#if USE(ACCELERATED_COMPOSITING)
+ OwnPtr<WKCACFLayerRenderer> m_layerRenderer;
+ RefPtr<PlatformCALayer> m_rootChild;
+#endif
+ HWND m_hwnd;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp
new file mode 100644
index 0000000..0b91455
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp
@@ -0,0 +1,1252 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+#include "MediaPlayerPrivateQuickTimeVisualContext.h"
+
+#include "Cookie.h"
+#include "CookieJar.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "KURL.h"
+#include "MediaPlayerPrivateTaskTimer.h"
+#include "QTCFDictionary.h"
+#include "QTDecompressionSession.h"
+#include "QTMovie.h"
+#include "QTMovieTask.h"
+#include "QTMovieVisualContext.h"
+#include "ScrollView.h"
+#include "Settings.h"
+#include "SoftLinking.h"
+#include "TimeRanges.h"
+#include "Timer.h"
+#include <AssertMacros.h>
+#include <CoreGraphics/CGContext.h>
+#include <Wininet.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/HashSet.h>
+#include <wtf/MainThread.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "PlatformCALayer.h"
+#include "WKCAImageQueue.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer);
+static bool requiredDllsAvailable();
+
+SOFT_LINK_LIBRARY(Wininet)
+SOFT_LINK(Wininet, InternetSetCookieExW, DWORD, WINAPI, (LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData, DWORD dwFlags, DWORD_PTR dwReserved), (lpszUrl, lpszCookieName, lpszCookieData, dwFlags, dwReserved))
+
+// Interface declaration for MediaPlayerPrivateQuickTimeVisualContext's QTMovieClient aggregate
+class MediaPlayerPrivateQuickTimeVisualContext::MovieClient : public QTMovieClient {
+public:
+ MovieClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {}
+ virtual ~MovieClient() { m_parent = 0; }
+ virtual void movieEnded(QTMovie*);
+ virtual void movieLoadStateChanged(QTMovie*);
+ virtual void movieTimeChanged(QTMovie*);
+private:
+ MediaPlayerPrivateQuickTimeVisualContext* m_parent;
+};
+
+#if USE(ACCELERATED_COMPOSITING)
+class MediaPlayerPrivateQuickTimeVisualContext::LayerClient : public PlatformCALayerClient {
+public:
+ LayerClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {}
+ virtual ~LayerClient() { m_parent = 0; }
+
+private:
+ virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*);
+ virtual bool platformCALayerRespondsToLayoutChanges() const { return true; }
+
+ virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime) { }
+ virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesBottomUp; }
+ virtual void platformCALayerPaintContents(GraphicsContext&, const IntRect& inClip) { }
+ virtual bool platformCALayerShowDebugBorders() const { return false; }
+ virtual bool platformCALayerShowRepaintCounter() const { return false; }
+ virtual int platformCALayerIncrementRepaintCount() { return 0; }
+
+ virtual bool platformCALayerContentsOpaque() const { return false; }
+ virtual bool platformCALayerDrawsContent() const { return false; }
+ virtual void platformCALayerLayerDidDisplay(PlatformLayer*) { }
+
+ MediaPlayerPrivateQuickTimeVisualContext* m_parent;
+};
+
+void MediaPlayerPrivateQuickTimeVisualContext::LayerClient::platformCALayerLayoutSublayersOfLayer(PlatformCALayer* layer)
+{
+ ASSERT(m_parent);
+ ASSERT(m_parent->m_transformLayer == layer);
+
+ FloatSize parentSize = layer->bounds().size();
+ FloatSize naturalSize = m_parent->naturalSize();
+
+ // Calculate the ratio of these two sizes and use that ratio to scale the qtVideoLayer:
+ FloatSize ratio(parentSize.width() / naturalSize.width(), parentSize.height() / naturalSize.height());
+
+ int videoWidth = 0;
+ int videoHeight = 0;
+ m_parent->m_movie->getNaturalSize(videoWidth, videoHeight);
+ FloatRect videoBounds(0, 0, videoWidth * ratio.width(), videoHeight * ratio.height());
+ FloatPoint3D videoAnchor = m_parent->m_qtVideoLayer->anchorPoint();
+
+ // Calculate the new position based on the parent's size:
+ FloatPoint position(parentSize.width() * 0.5 - videoBounds.width() * (0.5 - videoAnchor.x()),
+ parentSize.height() * 0.5 - videoBounds.height() * (0.5 - videoAnchor.y()));
+
+ m_parent->m_qtVideoLayer->setBounds(videoBounds);
+ m_parent->m_qtVideoLayer->setPosition(position);
+}
+#endif
+
+class MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient : public QTMovieVisualContextClient {
+public:
+ VisualContextClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {}
+ virtual ~VisualContextClient() { m_parent = 0; }
+ void imageAvailableForTime(const QTCVTimeStamp*);
+ static void retrieveCurrentImageProc(void*);
+private:
+ MediaPlayerPrivateQuickTimeVisualContext* m_parent;
+};
+
+MediaPlayerPrivateInterface* MediaPlayerPrivateQuickTimeVisualContext::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivateQuickTimeVisualContext(player);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+MediaPlayerPrivateQuickTimeVisualContext::MediaPlayerPrivateQuickTimeVisualContext(MediaPlayer* player)
+ : m_player(player)
+ , m_seekTo(-1)
+ , m_seekTimer(this, &MediaPlayerPrivateQuickTimeVisualContext::seekTimerFired)
+ , m_visualContextTimer(this, &MediaPlayerPrivateQuickTimeVisualContext::visualContextTimerFired)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_enabledTrackCount(0)
+ , m_totalTrackCount(0)
+ , m_hasUnsupportedTracks(false)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+ , m_visible(false)
+ , m_newFrameAvailable(false)
+ , m_movieClient(new MediaPlayerPrivateQuickTimeVisualContext::MovieClient(this))
+#if USE(ACCELERATED_COMPOSITING)
+ , m_layerClient(new MediaPlayerPrivateQuickTimeVisualContext::LayerClient(this))
+ , m_movieTransform(CGAffineTransformIdentity)
+#endif
+ , m_visualContextClient(new MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient(this))
+ , m_delayingLoad(false)
+ , m_preload(MediaPlayer::Auto)
+{
+}
+
+MediaPlayerPrivateQuickTimeVisualContext::~MediaPlayerPrivateQuickTimeVisualContext()
+{
+ tearDownVideoRendering();
+ cancelCallOnMainThread(&VisualContextClient::retrieveCurrentImageProc, this);
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::supportsFullscreen() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ Document* document = m_player->mediaPlayerClient()->mediaPlayerOwningDocument();
+ if (document && document->settings())
+ return document->settings()->acceleratedCompositingEnabled();
+#endif
+ return false;
+}
+
+PlatformMedia MediaPlayerPrivateQuickTimeVisualContext::platformMedia() const
+{
+ PlatformMedia p;
+ p.type = PlatformMedia::QTMovieVisualContextType;
+ p.media.qtMovieVisualContext = m_visualContext.get();
+ return p;
+}
+#if USE(ACCELERATED_COMPOSITING)
+
+PlatformLayer* MediaPlayerPrivateQuickTimeVisualContext::platformLayer() const
+{
+ return m_transformLayer ? m_transformLayer->platformLayer() : 0;
+}
+#endif
+
+String MediaPlayerPrivateQuickTimeVisualContext::rfc2616DateStringFromTime(CFAbsoluteTime time)
+{
+ static const char* const dayStrings[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+ static const char* const monthStrings[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ static const CFStringRef dateFormatString = CFSTR("%s, %02d %s %04d %02d:%02d:%02d GMT");
+ static CFTimeZoneRef gmtTimeZone;
+ if (!gmtTimeZone)
+ gmtTimeZone = CFTimeZoneCopyDefault();
+
+ CFGregorianDate dateValue = CFAbsoluteTimeGetGregorianDate(time, gmtTimeZone);
+ if (!CFGregorianDateIsValid(dateValue, kCFGregorianAllUnits))
+ return String();
+
+ time = CFGregorianDateGetAbsoluteTime(dateValue, gmtTimeZone);
+ SInt32 day = CFAbsoluteTimeGetDayOfWeek(time, 0);
+
+ RetainPtr<CFStringRef> dateCFString(AdoptCF, CFStringCreateWithFormat(0, 0, dateFormatString, dayStrings[day - 1], dateValue.day,
+ monthStrings[dateValue.month - 1], dateValue.year, dateValue.hour, dateValue.minute, (int)dateValue.second));
+ return dateCFString.get();
+}
+
+static void addCookieParam(StringBuilder& cookieBuilder, const String& name, const String& value)
+{
+ if (name.isEmpty())
+ return;
+
+ // If this isn't the first parameter added, terminate the previous one.
+ if (cookieBuilder.length())
+ cookieBuilder.append("; ");
+
+ // Add parameter name, and value if there is one.
+ cookieBuilder.append(name);
+ if (!value.isEmpty()) {
+ cookieBuilder.append('=');
+ cookieBuilder.append(value);
+ }
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setUpCookiesForQuickTime(const String& url)
+{
+ // WebCore loaded the page with the movie URL with CFNetwork but QuickTime will
+ // use WinINet to download the movie, so we need to copy any cookies needed to
+ // download the movie into WinInet before asking QuickTime to open it.
+ Document* document = m_player->mediaPlayerClient()->mediaPlayerOwningDocument();
+ Frame* frame = document ? document->frame() : 0;
+ if (!frame || !frame->page() || !frame->page()->cookieEnabled())
+ return;
+
+ KURL movieURL = KURL(KURL(), url);
+ Vector<Cookie> documentCookies;
+ if (!getRawCookies(frame->document(), movieURL, documentCookies))
+ return;
+
+ for (size_t ndx = 0; ndx < documentCookies.size(); ndx++) {
+ const Cookie& cookie = documentCookies[ndx];
+
+ if (cookie.name.isEmpty())
+ continue;
+
+ // Build up the cookie string with as much information as we can get so WinINet
+ // knows what to do with it.
+ StringBuilder cookieBuilder;
+ addCookieParam(cookieBuilder, cookie.name, cookie.value);
+ addCookieParam(cookieBuilder, "path", cookie.path);
+ if (cookie.expires)
+ addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires));
+ if (cookie.httpOnly)
+ addCookieParam(cookieBuilder, "httpOnly", String());
+ cookieBuilder.append(';');
+
+ String cookieURL;
+ if (!cookie.domain.isEmpty()) {
+ StringBuilder urlBuilder;
+
+ urlBuilder.append(movieURL.protocol());
+ urlBuilder.append("://");
+ if (cookie.domain[0] == '.')
+ urlBuilder.append(cookie.domain.substring(1));
+ else
+ urlBuilder.append(cookie.domain);
+ if (cookie.path.length() > 1)
+ urlBuilder.append(cookie.path);
+
+ cookieURL = urlBuilder.toString();
+ } else
+ cookieURL = movieURL;
+
+ InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, cookieBuilder.toString().charactersWithNullTermination(), 0, 0);
+ }
+}
+
+static void disableComponentsOnce()
+{
+ static bool sComponentsDisabled = false;
+ if (sComponentsDisabled)
+ return;
+ sComponentsDisabled = true;
+
+ uint32_t componentsToDisable[][5] = {
+ {'eat ', 'TEXT', 'text', 0, 0},
+ {'eat ', 'TXT ', 'text', 0, 0},
+ {'eat ', 'utxt', 'text', 0, 0},
+ {'eat ', 'TEXT', 'tx3g', 0, 0},
+ };
+
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(componentsToDisable); ++i)
+ QTMovie::disableComponent(componentsToDisable[i]);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::resumeLoad()
+{
+ m_delayingLoad = false;
+
+ if (!m_movieURL.isEmpty())
+ loadInternal(m_movieURL);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::load(const String& url)
+{
+ m_movieURL = url;
+
+ if (m_preload == MediaPlayer::None) {
+ m_delayingLoad = true;
+ return;
+ }
+
+ loadInternal(url);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::loadInternal(const String& url)
+{
+ if (!QTMovie::initializeQuickTime()) {
+ // FIXME: is this the right error to return?
+ m_networkState = MediaPlayer::DecodeError;
+ m_player->networkStateChanged();
+ return;
+ }
+
+ disableComponentsOnce();
+
+ // Initialize the task timer.
+ MediaPlayerPrivateTaskTimer::initialize();
+
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+ }
+ cancelSeek();
+
+ setUpCookiesForQuickTime(url);
+
+ m_movie = adoptRef(new QTMovie(m_movieClient.get()));
+ m_movie->load(url.characters(), url.length(), m_player->preservesPitch());
+ m_movie->setVolume(m_player->volume());
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::prepareToPlay()
+{
+ if (!m_movie || m_delayingLoad)
+ resumeLoad();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::play()
+{
+ if (!m_movie)
+ return;
+ m_startedPlaying = true;
+
+ m_movie->play();
+ m_visualContextTimer.startRepeating(1.0 / 30);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::pause()
+{
+ if (!m_movie)
+ return;
+ m_startedPlaying = false;
+
+ m_movie->pause();
+ m_visualContextTimer.stop();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::duration() const
+{
+ if (!m_movie)
+ return 0;
+ return m_movie->duration();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::currentTime() const
+{
+ if (!m_movie)
+ return 0;
+ return m_movie->currentTime();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::seek(float time)
+{
+ cancelSeek();
+
+ if (!m_movie)
+ return;
+
+ if (time > duration())
+ time = duration();
+
+ m_seekTo = time;
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else
+ m_seekTimer.start(0, 0.5f);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::doSeek()
+{
+ float oldRate = m_movie->rate();
+ if (oldRate)
+ m_movie->setRate(0);
+ m_movie->setCurrentTime(m_seekTo);
+ float timeAfterSeek = currentTime();
+ // restore playback only if not at end, othewise QTMovie will loop
+ if (oldRate && timeAfterSeek < duration())
+ m_movie->setRate(oldRate);
+ cancelSeek();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::cancelSeek()
+{
+ m_seekTo = -1;
+ m_seekTimer.stop();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::seekTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*)
+{
+ if (!m_movie || !seeking() || currentTime() == m_seekTo) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ return;
+ }
+
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else {
+ MediaPlayer::NetworkState state = networkState();
+ if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ }
+ }
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::paused() const
+{
+ if (!m_movie)
+ return true;
+ return (!m_movie->rate());
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::seeking() const
+{
+ if (!m_movie)
+ return false;
+ return m_seekTo >= 0;
+}
+
+IntSize MediaPlayerPrivateQuickTimeVisualContext::naturalSize() const
+{
+ if (!m_movie)
+ return IntSize();
+ int width;
+ int height;
+ m_movie->getNaturalSize(width, height);
+#if USE(ACCELERATED_COMPOSITING)
+ CGSize originalSize = {width, height};
+ CGSize transformedSize = CGSizeApplyAffineTransform(originalSize, m_movieTransform);
+ return IntSize(abs(transformedSize.width), abs(transformedSize.height));
+#else
+ return IntSize(width, height);
+#endif
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasVideo() const
+{
+ if (!m_movie)
+ return false;
+ return m_movie->hasVideo();
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasAudio() const
+{
+ if (!m_movie)
+ return false;
+ return m_movie->hasAudio();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setVolume(float volume)
+{
+ if (!m_movie)
+ return;
+ m_movie->setVolume(volume);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setRate(float rate)
+{
+ if (!m_movie)
+ return;
+
+ // Do not call setRate(...) unless we have started playing; otherwise
+ // QuickTime's VisualContext can get wedged waiting for a rate change
+ // call which will never come.
+ if (m_startedPlaying)
+ m_movie->setRate(rate);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_movie)
+ return;
+ m_movie->setPreservesPitch(preservesPitch);
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasClosedCaptions() const
+{
+ if (!m_movie)
+ return false;
+ return m_movie->hasClosedCaptions();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setClosedCaptionsVisible(bool visible)
+{
+ if (!m_movie)
+ return;
+ m_movie->setClosedCaptionsVisible(visible);
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivateQuickTimeVisualContext::buffered() const
+{
+ RefPtr<TimeRanges> timeRanges = TimeRanges::create();
+ float loaded = maxTimeLoaded();
+ // rtsp streams are not buffered
+ if (!m_isStreaming && loaded > 0)
+ timeRanges->add(0, loaded);
+ return timeRanges.release();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::maxTimeSeekable() const
+{
+ // infinite duration means live stream
+ return !isfinite(duration()) ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::maxTimeLoaded() const
+{
+ if (!m_movie)
+ return 0;
+ return m_movie->maxTimeLoaded();
+}
+
+unsigned MediaPlayerPrivateQuickTimeVisualContext::bytesLoaded() const
+{
+ if (!m_movie)
+ return 0;
+ float dur = duration();
+ float maxTime = maxTimeLoaded();
+ if (!dur)
+ return 0;
+ return totalBytes() * maxTime / dur;
+}
+
+unsigned MediaPlayerPrivateQuickTimeVisualContext::totalBytes() const
+{
+ if (!m_movie)
+ return 0;
+ return m_movie->dataSize();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::cancelLoad()
+{
+ if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
+ return;
+
+ tearDownVideoRendering();
+
+ // Cancel the load by destroying the movie.
+ m_movie.clear();
+
+ updateStates();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ long loadState = m_movie ? m_movie->loadState() : QTMovieLoadStateError;
+
+ if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) {
+ m_movie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount);
+ if (m_player->inMediaDocument()) {
+ if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) {
+ // This is a type of media that we do not handle directly with a <video>
+ // element, eg. QuickTime VR, a movie with a sprite track, etc. Tell the
+ // MediaPlayerClient that we won't support it.
+ sawUnsupportedTracks();
+ return;
+ }
+ } else if (!m_enabledTrackCount)
+ loadState = QTMovieLoadStateError;
+ }
+
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (loadState >= QTMovieLoadStatePlayable) {
+ // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+ } else if (loadState >= QTMovieLoadStateLoaded) {
+ m_readyState = MediaPlayer::HaveMetadata;
+ } else if (loadState > QTMovieLoadStateError) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveNothing;
+ } else {
+ if (m_player->inMediaDocument()) {
+ // Something went wrong in the loading of media within a standalone file.
+ // This can occur with chained ref movies that eventually resolve to a
+ // file we don't support.
+ sawUnsupportedTracks();
+ return;
+ }
+
+ float loaded = maxTimeLoaded();
+ if (!loaded)
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (!m_enabledTrackCount)
+ m_networkState = MediaPlayer::FormatError;
+ else {
+ // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
+ if (loaded > 0)
+ m_networkState = MediaPlayer::DecodeError;
+ else
+ m_readyState = MediaPlayer::HaveNothing;
+ }
+ }
+
+ if (isReadyForRendering() && !hasSetUpVideoRendering())
+ setUpVideoRendering();
+
+ if (seeking())
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (m_networkState != oldNetworkState)
+ m_player->networkStateChanged();
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::isReadyForRendering() const
+{
+ return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::sawUnsupportedTracks()
+{
+ m_movie->setDisabled(true);
+ m_hasUnsupportedTracks = true;
+ m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::didEnd()
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ m_startedPlaying = false;
+
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setSize(const IntSize& size)
+{
+ if (m_hasUnsupportedTracks || !m_movie || m_size == size)
+ return;
+ m_size = size;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setVisible(bool visible)
+{
+ if (m_hasUnsupportedTracks || !m_movie || m_visible == visible)
+ return;
+
+ m_visible = visible;
+ if (m_visible) {
+ if (isReadyForRendering())
+ setUpVideoRendering();
+ } else
+ tearDownVideoRendering();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::paint(GraphicsContext* p, const IntRect& r)
+{
+ MediaRenderingMode currentMode = currentRenderingMode();
+
+ if (currentMode == MediaRenderingNone)
+ return;
+
+ if (currentMode == MediaRenderingSoftwareRenderer && !m_visualContext)
+ return;
+
+ QTPixelBuffer buffer = m_visualContext->imageForTime(0);
+ if (buffer.pixelBufferRef()) {
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer) {
+ // We are probably being asked to render the video into a canvas, but
+ // there's a good chance the QTPixelBuffer is not ARGB and thus can't be
+ // drawn using CG. If so, fire up an ICMDecompressionSession and convert
+ // the current frame into something which can be rendered by CG.
+ if (!buffer.pixelFormatIs32ARGB() && !buffer.pixelFormatIs32BGRA()) {
+ // The decompression session will only decompress a specific pixelFormat
+ // at a specific width and height; if these differ, the session must be
+ // recreated with the new parameters.
+ if (!m_decompressionSession || !m_decompressionSession->canDecompress(buffer))
+ m_decompressionSession = QTDecompressionSession::create(buffer.pixelFormatType(), buffer.width(), buffer.height());
+ buffer = m_decompressionSession->decompress(buffer);
+ }
+ }
+#endif
+ CGImageRef image = CreateCGImageFromPixelBuffer(buffer);
+
+ CGContextRef context = p->platformContext();
+ CGContextSaveGState(context);
+ CGContextTranslateCTM(context, r.x(), r.y());
+ CGContextTranslateCTM(context, 0, r.height());
+ CGContextScaleCTM(context, 1, -1);
+ CGContextDrawImage(context, CGRectMake(0, 0, r.width(), r.height()), image);
+ CGContextRestoreGState(context);
+
+ CGImageRelease(image);
+ }
+ paintCompleted(*p, r);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::paintCompleted(GraphicsContext& context, const IntRect& rect)
+{
+ m_newFrameAvailable = false;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient::retrieveCurrentImageProc(void* refcon)
+{
+ static_cast<MediaPlayerPrivateQuickTimeVisualContext*>(refcon)->retrieveCurrentImage();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient::imageAvailableForTime(const QTCVTimeStamp* timeStamp)
+{
+ // This call may come in on another thread, so marshall to the main thread first:
+ callOnMainThread(&retrieveCurrentImageProc, m_parent);
+
+ // callOnMainThread must be paired with cancelCallOnMainThread in the destructor,
+ // in case this object is deleted before the main thread request is handled.
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::visualContextTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*)
+{
+ if (m_visualContext && m_visualContext->isImageAvailableForTime(0))
+ retrieveCurrentImage();
+}
+
+static CFDictionaryRef QTCFDictionaryCreateWithDataCallback(CFAllocatorRef allocator, const UInt8* bytes, CFIndex length)
+{
+ RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(allocator, bytes, length, kCFAllocatorNull));
+ if (!data)
+ return 0;
+
+ return reinterpret_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(allocator, data.get(), kCFPropertyListImmutable, 0));
+}
+
+static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ CGDataProviderRef provider = 0;
+ CGColorSpaceRef colorSpace = 0;
+ CGImageRef image = 0;
+
+ size_t bitsPerComponent = 0;
+ size_t bitsPerPixel = 0;
+ CGImageAlphaInfo alphaInfo = kCGImageAlphaNone;
+
+ if (buffer.pixelFormatIs32BGRA()) {
+ bitsPerComponent = 8;
+ bitsPerPixel = 32;
+ alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
+ } else if (buffer.pixelFormatIs32ARGB()) {
+ bitsPerComponent = 8;
+ bitsPerPixel = 32;
+ alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big);
+ } else {
+ // All other pixel formats are currently unsupported:
+ ASSERT_NOT_REACHED();
+ }
+
+ CGDataProviderDirectAccessCallbacks callbacks = {
+ &QTPixelBuffer::dataProviderGetBytePointerCallback,
+ &QTPixelBuffer::dataProviderReleaseBytePointerCallback,
+ &QTPixelBuffer::dataProviderGetBytesAtPositionCallback,
+ &QTPixelBuffer::dataProviderReleaseInfoCallback,
+ };
+
+ // Colorspace should be device, so that Quartz does not have to do an extra render.
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+ require(colorSpace, Bail);
+
+ provider = CGDataProviderCreateDirectAccess(buffer.pixelBufferRef(), buffer.dataSize(), &callbacks);
+ require(provider, Bail);
+
+ // CGDataProvider does not retain the buffer, but it will release it later, so do an extra retain here:
+ QTPixelBuffer::retainCallback(buffer.pixelBufferRef());
+
+ image = CGImageCreate(buffer.width(), buffer.height(), bitsPerComponent, bitsPerPixel, buffer.bytesPerRow(), colorSpace, alphaInfo, provider, 0, false, kCGRenderingIntentDefault);
+
+Bail:
+ // Once the image is created we can release our reference to the provider and the colorspace, they are retained by the image
+ if (provider)
+ CGDataProviderRelease(provider);
+ if (colorSpace)
+ CGColorSpaceRelease(colorSpace);
+
+ return image;
+#else
+ return 0;
+#endif
+}
+
+
+void MediaPlayerPrivateQuickTimeVisualContext::retrieveCurrentImage()
+{
+ if (!m_visualContext)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer) {
+
+ QTPixelBuffer buffer = m_visualContext->imageForTime(0);
+ if (!buffer.pixelBufferRef())
+ return;
+
+ PlatformCALayer* layer = m_qtVideoLayer.get();
+
+ if (!buffer.lockBaseAddress()) {
+ if (requiredDllsAvailable()) {
+ if (!m_imageQueue) {
+ m_imageQueue = new WKCAImageQueue(buffer.width(), buffer.height(), 30);
+ m_imageQueue->setFlags(WKCAImageQueue::Fill, WKCAImageQueue::Fill);
+ layer->setContents(m_imageQueue->get());
+ }
+
+ // Debug QuickTime links against a non-Debug version of CoreFoundation, so the
+ // CFDictionary attached to the CVPixelBuffer cannot be directly passed on into the
+ // CAImageQueue without being converted to a non-Debug CFDictionary. Additionally,
+ // old versions of QuickTime used a non-AAS CoreFoundation, so the types are not
+ // interchangable even in the release case.
+ RetainPtr<CFDictionaryRef> attachments(AdoptCF, QTCFDictionaryCreateCopyWithDataCallback(kCFAllocatorDefault, buffer.attachments(), &QTCFDictionaryCreateWithDataCallback));
+ CFTimeInterval imageTime = QTMovieVisualContext::currentHostTime();
+
+ m_imageQueue->collect();
+
+ uint64_t imageId = m_imageQueue->registerPixelBuffer(buffer.baseAddress(), buffer.dataSize(), buffer.bytesPerRow(), buffer.width(), buffer.height(), buffer.pixelFormatType(), attachments.get(), 0);
+
+ if (m_imageQueue->insertImage(imageTime, WKCAImageQueue::Buffer, imageId, WKCAImageQueue::Opaque | WKCAImageQueue::Flush, &QTPixelBuffer::imageQueueReleaseCallback, buffer.pixelBufferRef())) {
+ // Retain the buffer one extra time so it doesn't dissappear before CAImageQueue decides to release it:
+ QTPixelBuffer::retainCallback(buffer.pixelBufferRef());
+ }
+
+ } else {
+ CGImageRef image = CreateCGImageFromPixelBuffer(buffer);
+ layer->setContents(image);
+ CGImageRelease(image);
+ }
+
+ buffer.unlockBaseAddress();
+ layer->setNeedsCommit();
+ }
+ } else
+#endif
+ m_player->repaint();
+
+ m_visualContext->task();
+}
+
+static HashSet<String> mimeTypeCache()
+{
+ DEFINE_STATIC_LOCAL(HashSet<String>, typeCache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ unsigned count = QTMovie::countSupportedTypes();
+ for (unsigned n = 0; n < count; n++) {
+ const UChar* character;
+ unsigned len;
+ QTMovie::getSupportedType(n, character, len);
+ if (len)
+ typeCache.add(String(character, len));
+ }
+
+ typeListInitialized = true;
+ }
+
+ return typeCache;
+}
+
+static CFStringRef createVersionStringFromModuleName(LPCWSTR moduleName)
+{
+ HMODULE module = GetModuleHandleW(moduleName);
+ if (!module)
+ return 0;
+
+ wchar_t filePath[MAX_PATH] = {0};
+ if (!GetModuleFileNameW(module, filePath, MAX_PATH))
+ return 0;
+
+ DWORD versionInfoSize = GetFileVersionInfoSizeW(filePath, 0);
+ if (!versionInfoSize)
+ return 0;
+
+ CFStringRef versionString = 0;
+ void* versionInfo = calloc(versionInfoSize, sizeof(char));
+ if (GetFileVersionInfo(filePath, 0, versionInfoSize, versionInfo)) {
+ VS_FIXEDFILEINFO* fileInfo = 0;
+ UINT fileInfoLength = 0;
+
+ if (VerQueryValueW(versionInfo, L"\\", reinterpret_cast<LPVOID*>(&fileInfo), &fileInfoLength)) {
+ versionString = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%d.%d.%d.%d"),
+ HIWORD(fileInfo->dwFileVersionMS), LOWORD(fileInfo->dwFileVersionMS),
+ HIWORD(fileInfo->dwFileVersionLS), LOWORD(fileInfo->dwFileVersionLS));
+ }
+ }
+ free(versionInfo);
+
+ return versionString;
+}
+
+static bool requiredDllsAvailable()
+{
+ static bool s_prerequisitesChecked = false;
+ static bool s_prerequisitesSatisfied;
+ static const CFStringRef kMinQuartzCoreVersion = CFSTR("1.0.42.0");
+ static const CFStringRef kMinCoreVideoVersion = CFSTR("1.0.1.0");
+
+ if (s_prerequisitesChecked)
+ return s_prerequisitesSatisfied;
+ s_prerequisitesChecked = true;
+ s_prerequisitesSatisfied = false;
+
+ CFStringRef quartzCoreString = createVersionStringFromModuleName(L"QuartzCore");
+ if (!quartzCoreString)
+ quartzCoreString = createVersionStringFromModuleName(L"QuartzCore_debug");
+
+ CFStringRef coreVideoString = createVersionStringFromModuleName(L"CoreVideo");
+ if (!coreVideoString)
+ coreVideoString = createVersionStringFromModuleName(L"CoreVideo_debug");
+
+ s_prerequisitesSatisfied = (quartzCoreString && coreVideoString
+ && CFStringCompare(quartzCoreString, kMinQuartzCoreVersion, kCFCompareNumerically) != kCFCompareLessThan
+ && CFStringCompare(coreVideoString, kMinCoreVideoVersion, kCFCompareNumerically) != kCFCompareLessThan);
+
+ if (quartzCoreString)
+ CFRelease(quartzCoreString);
+ if (coreVideoString)
+ CFRelease(coreVideoString);
+
+ return s_prerequisitesSatisfied;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::getSupportedTypes(HashSet<String>& types)
+{
+ types = mimeTypeCache();
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::isAvailable()
+{
+ return QTMovie::initializeQuickTime();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivateQuickTimeVisualContext::supportsType(const String& type, const String& codecs)
+{
+ // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
+ // extended MIME type
+ return mimeTypeCache().contains(type) ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieEnded(QTMovie* movie)
+{
+ if (m_parent->m_hasUnsupportedTracks)
+ return;
+
+ m_parent->m_visualContextTimer.stop();
+
+ ASSERT(m_parent->m_movie.get() == movie);
+ m_parent->didEnd();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieLoadStateChanged(QTMovie* movie)
+{
+ if (m_parent->m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_parent->m_movie.get() == movie);
+ m_parent->updateStates();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieTimeChanged(QTMovie* movie)
+{
+ if (m_parent->m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_parent->m_movie.get() == movie);
+ m_parent->updateStates();
+ m_parent->m_player->timeChanged();
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasSingleSecurityOrigin() const
+{
+ // We tell quicktime to disallow resources that come from different origins
+ // so we all media is single origin.
+ return true;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setPreload(MediaPlayer::Preload preload)
+{
+ m_preload = preload;
+ if (m_delayingLoad && m_preload != MediaPlayer::None)
+ resumeLoad();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::mediaTimeForTimeValue(float timeValue) const
+{
+ long timeScale;
+ if (m_readyState < MediaPlayer::HaveMetadata || !(timeScale = m_movie->timeScale()))
+ return timeValue;
+
+ long mediaTimeValue = static_cast<long>(timeValue * timeScale);
+ return static_cast<float>(mediaTimeValue) / timeScale;
+}
+
+MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::currentRenderingMode() const
+{
+ if (!m_movie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ return MediaRenderingMovieLayer;
+#endif
+
+ return m_visualContext ? MediaRenderingSoftwareRenderer : MediaRenderingNone;
+}
+
+MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::preferredRenderingMode() const
+{
+ if (!m_player->frameView() || !m_movie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setUpVideoRendering()
+{
+ MediaRenderingMode currentMode = currentRenderingMode();
+ MediaRenderingMode preferredMode = preferredRenderingMode();
+
+#if !USE(ACCELERATED_COMPOSITING)
+ ASSERT(preferredMode != MediaRenderingMovieLayer);
+#endif
+
+ if (currentMode == preferredMode && currentMode != MediaRenderingNone)
+ return;
+
+ if (currentMode != MediaRenderingNone)
+ tearDownVideoRendering();
+
+ if (preferredMode == MediaRenderingMovieLayer)
+ createLayerForMovie();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+#endif
+
+ QTPixelBuffer::Type contextType = requiredDllsAvailable() && preferredMode == MediaRenderingMovieLayer ? QTPixelBuffer::ConfigureForCAImageQueue : QTPixelBuffer::ConfigureForCGImage;
+ m_visualContext = QTMovieVisualContext::create(m_visualContextClient.get(), contextType);
+ m_visualContext->setMovie(m_movie.get());
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::tearDownVideoRendering()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ destroyLayerForMovie();
+#endif
+
+ m_visualContext = 0;
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasSetUpVideoRendering() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ return m_qtVideoLayer || (currentRenderingMode() != MediaRenderingMovieLayer && m_visualContext);
+#else
+ return true;
+#endif
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::retrieveAndResetMovieTransform()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ // First things first, reset the total movie transform so that
+ // we can bail out early:
+ m_movieTransform = CGAffineTransformIdentity;
+
+ if (!m_movie || !m_movie->hasVideo())
+ return;
+
+ // This trick will only work on movies with a single video track,
+ // so bail out early if the video contains more than one (or zero)
+ // video tracks.
+ QTTrackArray videoTracks = m_movie->videoTracks();
+ if (videoTracks.size() != 1)
+ return;
+
+ QTTrack* track = videoTracks[0].get();
+ ASSERT(track);
+
+ CGAffineTransform movieTransform = m_movie->getTransform();
+ if (!CGAffineTransformEqualToTransform(movieTransform, CGAffineTransformIdentity))
+ m_movie->resetTransform();
+
+ CGAffineTransform trackTransform = track->getTransform();
+ if (!CGAffineTransformEqualToTransform(trackTransform, CGAffineTransformIdentity))
+ track->resetTransform();
+
+ // Multiply the two transforms together, taking care to
+ // do so in the correct order, track * movie = final:
+ m_movieTransform = CGAffineTransformConcat(trackTransform, movieTransform);
+#endif
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::createLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(supportsAcceleratedRendering());
+
+ if (!m_movie || m_qtVideoLayer)
+ return;
+
+ // Create a PlatformCALayer which will transform the contents of the video layer
+ // which is in m_qtVideoLayer.
+ m_transformLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, m_layerClient.get());
+ if (!m_transformLayer)
+ return;
+
+ // Mark the layer as anchored in the top left.
+ m_transformLayer->setAnchorPoint(FloatPoint3D());
+
+ m_qtVideoLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, 0);
+ if (!m_qtVideoLayer)
+ return;
+
+ if (CGAffineTransformEqualToTransform(m_movieTransform, CGAffineTransformIdentity))
+ retrieveAndResetMovieTransform();
+ CGAffineTransform t = m_movieTransform;
+
+ // Remove the translation portion of the transform, since we will always rotate about
+ // the layer's center point. In our limited use-case (a single video track), this is
+ // safe:
+ t.tx = t.ty = 0;
+ m_qtVideoLayer->setTransform(CATransform3DMakeAffineTransform(t));
+
+#ifndef NDEBUG
+ m_qtVideoLayer->setName("Video layer");
+#endif
+ m_transformLayer->appendSublayer(m_qtVideoLayer.get());
+ m_transformLayer->setNeedsLayout();
+ // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
+#endif
+
+ // Fill the newly created layer with image data, so we're not looking at
+ // an empty layer until the next time a new image is available, which could
+ // be a long time if we're paused.
+ if (m_visualContext)
+ retrieveCurrentImage();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::destroyLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer) {
+ m_qtVideoLayer->removeFromSuperlayer();
+ m_qtVideoLayer = 0;
+ }
+
+ if (m_transformLayer)
+ m_transformLayer = 0;
+
+ if (m_imageQueue)
+ m_imageQueue = 0;
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool MediaPlayerPrivateQuickTimeVisualContext::supportsAcceleratedRendering() const
+{
+ return isReadyForRendering();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::acceleratedRenderingStateChanged()
+{
+ // Set up or change the rendering path if necessary.
+ setUpVideoRendering();
+}
+
+#endif
+
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h
new file mode 100644
index 0000000..a12d79e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 MediaPlayerPrivateQuickTimeVisualContext_h
+#define MediaPlayerPrivateQuickTimeVisualContext_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayerPrivate.h"
+#include "Timer.h"
+#include <wtf/Forward.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RetainPtr.h>
+
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
+typedef struct CGImage *CGImageRef;
+class QTMovie;
+class QTMovieVisualContext;
+class QTDecompressionSession;
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntSize;
+class IntRect;
+
+#if USE(ACCELERATED_COMPOSITING)
+class PlatformCALayer;
+class WKCAImageQueue;
+#endif
+
+class MediaPlayerPrivateQuickTimeVisualContext : public MediaPlayerPrivateInterface {
+public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+
+ ~MediaPlayerPrivateQuickTimeVisualContext();
+
+private:
+ MediaPlayerPrivateQuickTimeVisualContext(MediaPlayer*);
+
+ virtual bool supportsFullscreen() const;
+ virtual PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const;
+#endif
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+ bool hasAudio() const;
+
+ void load(const String& url);
+ void cancelLoad();
+ void loadInternal(const String& url);
+ void resumeLoad();
+
+ void play();
+ void pause();
+ void prepareToPlay();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float time);
+
+ void setRate(float);
+ void setVolume(float);
+ void setPreservesPitch(bool);
+
+ MediaPlayer::NetworkState networkState() const { return m_networkState; }
+ MediaPlayer::ReadyState readyState() const { return m_readyState; }
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setSize(const IntSize&);
+
+ void loadStateChanged();
+ void didEnd();
+
+ void paint(GraphicsContext*, const IntRect&);
+ void paintCompleted(GraphicsContext&, const IntRect&);
+
+ bool hasSingleSecurityOrigin() const;
+
+ bool hasClosedCaptions() const;
+ void setClosedCaptionsVisible(bool);
+
+ void setPreload(MediaPlayer::Preload);
+
+ void updateStates();
+ void doSeek();
+ void cancelSeek();
+ void seekTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*);
+ float maxTimeLoaded() const;
+ void sawUnsupportedTracks();
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer*);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual bool supportsAcceleratedRendering() const;
+ virtual void acceleratedRenderingStateChanged();
+#endif
+
+ enum MediaRenderingMode { MediaRenderingNone, MediaRenderingSoftwareRenderer, MediaRenderingMovieLayer };
+ MediaRenderingMode currentRenderingMode() const;
+ MediaRenderingMode preferredRenderingMode() const;
+ bool isReadyForRendering() const;
+
+ void setUpVideoRendering();
+ void tearDownVideoRendering();
+ bool hasSetUpVideoRendering() const;
+
+ void createLayerForMovie();
+ void destroyLayerForMovie();
+
+ void setUpCookiesForQuickTime(const String& url);
+ String rfc2616DateStringFromTime(CFAbsoluteTime);
+
+ void visualContextTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*);
+ void retrieveCurrentImage();
+
+ class MovieClient;
+ friend class MovieClient;
+ OwnPtr<MovieClient> m_movieClient;
+
+#if USE(ACCELERATED_COMPOSITING)
+ class LayerClient;
+ friend class LayerClient;
+ OwnPtr<LayerClient> m_layerClient;
+#endif
+
+ class VisualContextClient;
+ friend class VisualContextClient;
+ OwnPtr<VisualContextClient> m_visualContextClient;
+
+ void retrieveAndResetMovieTransform();
+
+ virtual float mediaTimeForTimeValue(float) const;
+
+ MediaPlayer* m_player;
+ RefPtr<QTMovie> m_movie;
+#if USE(ACCELERATED_COMPOSITING)
+ RefPtr<PlatformCALayer> m_qtVideoLayer;
+ RefPtr<PlatformCALayer> m_transformLayer;
+ OwnPtr<WKCAImageQueue> m_imageQueue;
+ OwnPtr<QTDecompressionSession> m_decompressionSession;
+ CGAffineTransform m_movieTransform;
+#endif
+ RefPtr<QTMovieVisualContext> m_visualContext;
+ float m_seekTo;
+ Timer<MediaPlayerPrivateQuickTimeVisualContext> m_seekTimer;
+ Timer<MediaPlayerPrivateQuickTimeVisualContext> m_visualContextTimer;
+ IntSize m_size;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ unsigned m_enabledTrackCount;
+ unsigned m_totalTrackCount;
+ bool m_hasUnsupportedTracks;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+ bool m_visible;
+ bool m_newFrameAvailable;
+ bool m_delayingLoad;
+ String m_movieURL;
+ MediaPlayer::Preload m_preload;
+#if DRAW_FRAME_RATE
+ double m_frameCountWhilePlaying;
+ double m_timeStartedPlaying;
+ double m_timeStoppedPlaying;
+#endif
+
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
new file mode 100644
index 0000000..431d624
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -0,0 +1,933 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+#include "MediaPlayerPrivateQuickTimeWin.h"
+
+#include "Cookie.h"
+#include "CookieJar.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "KURL.h"
+#include "MediaPlayerPrivateTaskTimer.h"
+#include "QTMovieTask.h"
+#include "ScrollView.h"
+#include "SoftLinking.h"
+#include "TimeRanges.h"
+#include "Timer.h"
+#include <Wininet.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/HashSet.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayerCACF.h"
+#include "PlatformCALayer.h"
+#endif
+
+#if DRAW_FRAME_RATE
+#include "Document.h"
+#include "Font.h"
+#include "RenderObject.h"
+#include "RenderStyle.h"
+#include "Windows.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+SOFT_LINK_LIBRARY(Wininet)
+SOFT_LINK(Wininet, InternetSetCookieExW, DWORD, WINAPI, (LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData, DWORD dwFlags, DWORD_PTR dwReserved), (lpszUrl, lpszCookieName, lpszCookieData, dwFlags, dwReserved))
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
+ : m_player(player)
+ , m_seekTo(-1)
+ , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_enabledTrackCount(0)
+ , m_totalTrackCount(0)
+ , m_hasUnsupportedTracks(false)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+ , m_visible(false)
+ , m_newFrameAvailable(false)
+#if DRAW_FRAME_RATE
+ , m_frameCountWhilePlaying(0)
+ , m_timeStartedPlaying(0)
+ , m_timeStoppedPlaying(0)
+#endif
+{
+}
+
+MediaPlayerPrivate::~MediaPlayerPrivate()
+{
+ tearDownVideoRendering();
+ m_qtGWorld->setMovie(0);
+}
+
+bool MediaPlayerPrivate::supportsFullscreen() const
+{
+ return true;
+}
+
+PlatformMedia MediaPlayerPrivate::platformMedia() const
+{
+ PlatformMedia p;
+ p.type = PlatformMedia::QTMovieGWorldType;
+ p.media.qtMovieGWorld = m_qtGWorld.get();
+ return p;
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayerPrivate::platformLayer() const
+{
+ return m_qtVideoLayer ? m_qtVideoLayer->platformLayer() : 0;
+}
+#endif
+
+String MediaPlayerPrivate::rfc2616DateStringFromTime(CFAbsoluteTime time)
+{
+ static const char* const dayStrings[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+ static const char* const monthStrings[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ static const CFStringRef dateFormatString = CFSTR("%s, %02d %s %04d %02d:%02d:%02d GMT");
+ static CFTimeZoneRef gmtTimeZone;
+ if (!gmtTimeZone)
+ gmtTimeZone = CFTimeZoneCopyDefault();
+
+ CFGregorianDate dateValue = CFAbsoluteTimeGetGregorianDate(time, gmtTimeZone);
+ if (!CFGregorianDateIsValid(dateValue, kCFGregorianAllUnits))
+ return String();
+
+ time = CFGregorianDateGetAbsoluteTime(dateValue, gmtTimeZone);
+ SInt32 day = CFAbsoluteTimeGetDayOfWeek(time, 0);
+
+ RetainPtr<CFStringRef> dateCFString(AdoptCF, CFStringCreateWithFormat(0, 0, dateFormatString, dayStrings[day - 1], dateValue.day,
+ monthStrings[dateValue.month - 1], dateValue.year, dateValue.hour, dateValue.minute, (int)dateValue.second));
+ return dateCFString.get();
+}
+
+static void addCookieParam(StringBuilder& cookieBuilder, const String& name, const String& value)
+{
+ if (name.isEmpty())
+ return;
+
+ // If this isn't the first parameter added, terminate the previous one.
+ if (cookieBuilder.length())
+ cookieBuilder.append("; ");
+
+ // Add parameter name, and value if there is one.
+ cookieBuilder.append(name);
+ if (!value.isEmpty()) {
+ cookieBuilder.append('=');
+ cookieBuilder.append(value);
+ }
+}
+
+
+void MediaPlayerPrivate::setUpCookiesForQuickTime(const String& url)
+{
+ // WebCore loaded the page with the movie URL with CFNetwork but QuickTime will
+ // use WinINet to download the movie, so we need to copy any cookies needed to
+ // download the movie into WinInet before asking QuickTime to open it.
+ Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0;
+ if (!frame || !frame->page() || !frame->page()->cookieEnabled())
+ return;
+
+ KURL movieURL = KURL(KURL(), url);
+ Vector<Cookie> documentCookies;
+ if (!getRawCookies(frame->document(), movieURL, documentCookies))
+ return;
+
+ for (size_t ndx = 0; ndx < documentCookies.size(); ndx++) {
+ const Cookie& cookie = documentCookies[ndx];
+
+ if (cookie.name.isEmpty())
+ continue;
+
+ // Build up the cookie string with as much information as we can get so WinINet
+ // knows what to do with it.
+ StringBuilder cookieBuilder;
+ addCookieParam(cookieBuilder, cookie.name, cookie.value);
+ addCookieParam(cookieBuilder, "path", cookie.path);
+ if (cookie.expires)
+ addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires));
+ if (cookie.httpOnly)
+ addCookieParam(cookieBuilder, "httpOnly", String());
+ cookieBuilder.append(';');
+
+ String cookieURL;
+ if (!cookie.domain.isEmpty()) {
+ StringBuilder urlBuilder;
+
+ urlBuilder.append(movieURL.protocol());
+ urlBuilder.append("://");
+ if (cookie.domain[0] == '.')
+ urlBuilder.append(cookie.domain.substring(1));
+ else
+ urlBuilder.append(cookie.domain);
+ if (cookie.path.length() > 1)
+ urlBuilder.append(cookie.path);
+
+ cookieURL = urlBuilder.toString();
+ } else
+ cookieURL = movieURL;
+
+ InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, cookieBuilder.toString().charactersWithNullTermination(), 0, 0);
+ }
+}
+
+void MediaPlayerPrivate::load(const String& url)
+{
+ if (!QTMovie::initializeQuickTime()) {
+ // FIXME: is this the right error to return?
+ m_networkState = MediaPlayer::DecodeError;
+ m_player->networkStateChanged();
+ return;
+ }
+
+ // Initialize the task timer.
+ MediaPlayerPrivateTaskTimer::initialize();
+
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+ }
+ cancelSeek();
+
+ setUpCookiesForQuickTime(url);
+
+ m_qtMovie = adoptRef(new QTMovie(this));
+ m_qtMovie->load(url.characters(), url.length(), m_player->preservesPitch());
+ m_qtMovie->setVolume(m_player->volume());
+
+ m_qtGWorld = adoptRef(new QTMovieGWorld(this));
+ m_qtGWorld->setMovie(m_qtMovie.get());
+ m_qtGWorld->setVisible(m_player->visible());
+}
+
+void MediaPlayerPrivate::play()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = true;
+#if DRAW_FRAME_RATE
+ m_frameCountWhilePlaying = 0;
+#endif
+
+ m_qtMovie->play();
+}
+
+void MediaPlayerPrivate::pause()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = WTF::currentTime();
+#endif
+ m_qtMovie->pause();
+}
+
+float MediaPlayerPrivate::duration() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->duration();
+}
+
+float MediaPlayerPrivate::currentTime() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->currentTime();
+}
+
+void MediaPlayerPrivate::seek(float time)
+{
+ cancelSeek();
+
+ if (!m_qtMovie)
+ return;
+
+ if (time > duration())
+ time = duration();
+
+ m_seekTo = time;
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else
+ m_seekTimer.start(0, 0.5f);
+}
+
+void MediaPlayerPrivate::doSeek()
+{
+ float oldRate = m_qtMovie->rate();
+ if (oldRate)
+ m_qtMovie->setRate(0);
+ m_qtMovie->setCurrentTime(m_seekTo);
+ float timeAfterSeek = currentTime();
+ // restore playback only if not at end, othewise QTMovie will loop
+ if (oldRate && timeAfterSeek < duration())
+ m_qtMovie->setRate(oldRate);
+ cancelSeek();
+}
+
+void MediaPlayerPrivate::cancelSeek()
+{
+ m_seekTo = -1;
+ m_seekTimer.stop();
+}
+
+void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
+{
+ if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ return;
+ }
+
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else {
+ MediaPlayer::NetworkState state = networkState();
+ if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ }
+ }
+}
+
+bool MediaPlayerPrivate::paused() const
+{
+ if (!m_qtMovie)
+ return true;
+ return (!m_qtMovie->rate());
+}
+
+bool MediaPlayerPrivate::seeking() const
+{
+ if (!m_qtMovie)
+ return false;
+ return m_seekTo >= 0;
+}
+
+IntSize MediaPlayerPrivate::naturalSize() const
+{
+ if (!m_qtMovie)
+ return IntSize();
+ int width;
+ int height;
+ m_qtMovie->getNaturalSize(width, height);
+ return IntSize(width, height);
+}
+
+bool MediaPlayerPrivate::hasVideo() const
+{
+ if (!m_qtMovie)
+ return false;
+ return m_qtMovie->hasVideo();
+}
+
+bool MediaPlayerPrivate::hasAudio() const
+{
+ if (!m_qtMovie)
+ return false;
+ return m_qtMovie->hasAudio();
+}
+
+void MediaPlayerPrivate::setVolume(float volume)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setVolume(volume);
+}
+
+void MediaPlayerPrivate::setRate(float rate)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setRate(rate);
+}
+
+void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setPreservesPitch(preservesPitch);
+}
+
+bool MediaPlayerPrivate::hasClosedCaptions() const
+{
+ if (!m_qtMovie)
+ return false;
+ return m_qtMovie->hasClosedCaptions();
+}
+
+void MediaPlayerPrivate::setClosedCaptionsVisible(bool visible)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setClosedCaptionsVisible(visible);
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
+{
+ RefPtr<TimeRanges> timeRanges = TimeRanges::create();
+ float loaded = maxTimeLoaded();
+ // rtsp streams are not buffered
+ if (!m_isStreaming && loaded > 0)
+ timeRanges->add(0, loaded);
+ return timeRanges.release();
+}
+
+float MediaPlayerPrivate::maxTimeSeekable() const
+{
+ // infinite duration means live stream
+ return !isfinite(duration()) ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivate::maxTimeLoaded() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->maxTimeLoaded();
+}
+
+unsigned MediaPlayerPrivate::bytesLoaded() const
+{
+ if (!m_qtMovie)
+ return 0;
+ float dur = duration();
+ float maxTime = maxTimeLoaded();
+ if (!dur)
+ return 0;
+ return totalBytes() * maxTime / dur;
+}
+
+unsigned MediaPlayerPrivate::totalBytes() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->dataSize();
+}
+
+void MediaPlayerPrivate::cancelLoad()
+{
+ if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
+ return;
+
+ tearDownVideoRendering();
+
+ // Cancel the load by destroying the movie.
+ m_qtMovie.clear();
+
+ updateStates();
+}
+
+void MediaPlayerPrivate::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError;
+
+ if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) {
+ m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount);
+ if (m_player->inMediaDocument()) {
+ if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) {
+ // This is a type of media that we do not handle directly with a <video>
+ // element, eg. QuickTime VR, a movie with a sprite track, etc. Tell the
+ // MediaPlayerClient that we won't support it.
+ sawUnsupportedTracks();
+ return;
+ }
+ } else if (!m_enabledTrackCount)
+ loadState = QTMovieLoadStateError;
+ }
+
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (loadState >= QTMovieLoadStatePlayable) {
+ // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+ } else if (loadState >= QTMovieLoadStateLoaded) {
+ m_readyState = MediaPlayer::HaveMetadata;
+ } else if (loadState > QTMovieLoadStateError) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveNothing;
+ } else {
+ if (m_player->inMediaDocument()) {
+ // Something went wrong in the loading of media within a standalone file.
+ // This can occur with chained ref movies that eventually resolve to a
+ // file we don't support.
+ sawUnsupportedTracks();
+ return;
+ }
+
+ float loaded = maxTimeLoaded();
+ if (!loaded)
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (!m_enabledTrackCount)
+ m_networkState = MediaPlayer::FormatError;
+ else {
+ // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
+ if (loaded > 0)
+ m_networkState = MediaPlayer::DecodeError;
+ else
+ m_readyState = MediaPlayer::HaveNothing;
+ }
+ }
+
+ if (isReadyForRendering() && !hasSetUpVideoRendering())
+ setUpVideoRendering();
+
+ if (seeking())
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (m_networkState != oldNetworkState)
+ m_player->networkStateChanged();
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+}
+
+bool MediaPlayerPrivate::isReadyForRendering() const
+{
+ return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
+}
+
+void MediaPlayerPrivate::sawUnsupportedTracks()
+{
+ m_qtMovie->setDisabled(true);
+ m_hasUnsupportedTracks = true;
+ m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player);
+}
+
+void MediaPlayerPrivate::didEnd()
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = WTF::currentTime();
+#endif
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::setSize(const IntSize& size)
+{
+ if (m_hasUnsupportedTracks || !m_qtMovie || m_size == size)
+ return;
+ m_size = size;
+ m_qtGWorld->setSize(size.width(), size.height());
+}
+
+void MediaPlayerPrivate::setVisible(bool visible)
+{
+ if (m_hasUnsupportedTracks || !m_qtMovie || m_visible == visible)
+ return;
+
+ m_qtGWorld->setVisible(visible);
+ m_visible = visible;
+ if (m_visible) {
+ if (isReadyForRendering())
+ setUpVideoRendering();
+ } else
+ tearDownVideoRendering();
+}
+
+void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ return;
+#endif
+ if (p->paintingDisabled() || !m_qtMovie || m_hasUnsupportedTracks)
+ return;
+
+ bool usingTempBitmap = false;
+ OwnPtr<GraphicsContext::WindowsBitmap> bitmap;
+ // FIXME: use LocalWindowsContext.
+ HDC hdc = p->getWindowsContext(r);
+ if (!hdc) {
+ // The graphics context doesn't have an associated HDC so create a temporary
+ // bitmap where QTMovieGWorld can draw the frame and we can copy it.
+ usingTempBitmap = true;
+ bitmap.set(p->createWindowsBitmap(r.size()));
+ hdc = bitmap->hdc();
+
+ // FIXME: is this necessary??
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -r.x();
+ xform.eDy = -r.y();
+ SetWorldTransform(hdc, &xform);
+ }
+
+ m_qtGWorld->paint(hdc, r.x(), r.y());
+ if (usingTempBitmap)
+ p->drawWindowsBitmap(bitmap.get(), r.topLeft());
+ else
+ p->releaseWindowsContext(hdc, r);
+
+ paintCompleted(*p, r);
+}
+
+void MediaPlayerPrivate::paintCompleted(GraphicsContext& context, const IntRect& rect)
+{
+ m_newFrameAvailable = false;
+
+#if DRAW_FRAME_RATE
+ if (m_frameCountWhilePlaying > 10) {
+ double interval = m_startedPlaying ? WTF::currentTime() - m_timeStartedPlaying : m_timeStoppedPlaying - m_timeStartedPlaying;
+ double frameRate = (m_frameCountWhilePlaying - 1) / interval;
+ CGContextRef cgContext = context.platformContext();
+ CGRect drawRect = rect;
+
+ char text[8];
+ _snprintf(text, sizeof(text), "%1.2f", frameRate);
+
+ static const int fontSize = 25;
+ static const int fontCharWidth = 12;
+ static const int boxHeight = 25;
+ static const int boxBorderWidth = 4;
+ drawRect.size.width = boxBorderWidth * 2 + fontCharWidth * strlen(text);
+ drawRect.size.height = boxHeight;
+
+ CGContextSaveGState(cgContext);
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ CGContextScaleCTM(cgContext, 1, -1);
+ CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, m_qtVideoLayer ? -rect.height() : 0);
+#else
+ CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, 0);
+#endif
+ static const CGFloat backgroundColor[4] = { 0.98, 0.98, 0.82, 0.8 };
+ CGContextSetFillColor(cgContext, backgroundColor);
+ CGContextFillRect(cgContext, drawRect);
+
+ static const CGFloat textColor[4] = { 0, 0, 0, 1 };
+ CGContextSetFillColor(cgContext, textColor);
+ CGContextSetTextMatrix(cgContext, CGAffineTransformMakeScale(1, -1));
+ CGContextSelectFont(cgContext, "Helvetica", fontSize, kCGEncodingMacRoman);
+
+ CGContextShowTextAtPoint(cgContext, drawRect.origin.x + boxBorderWidth, drawRect.origin.y + boxHeight - boxBorderWidth, text, strlen(text));
+
+ CGContextRestoreGState(cgContext);
+ }
+#endif
+}
+
+static HashSet<String> mimeTypeCache()
+{
+ DEFINE_STATIC_LOCAL(HashSet<String>, typeCache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ unsigned count = QTMovie::countSupportedTypes();
+ for (unsigned n = 0; n < count; n++) {
+ const UChar* character;
+ unsigned len;
+ QTMovie::getSupportedType(n, character, len);
+ if (len)
+ typeCache.add(String(character, len));
+ }
+
+ typeListInitialized = true;
+ }
+
+ return typeCache;
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+{
+ types = mimeTypeCache();
+}
+
+bool MediaPlayerPrivate::isAvailable()
+{
+ return QTMovie::initializeQuickTime();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
+ // extended MIME type
+ return mimeTypeCache().contains(type) ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
+void MediaPlayerPrivate::movieEnded(QTMovie* movie)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_qtMovie.get() == movie);
+ didEnd();
+}
+
+void MediaPlayerPrivate::movieLoadStateChanged(QTMovie* movie)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_qtMovie.get() == movie);
+ updateStates();
+}
+
+void MediaPlayerPrivate::movieTimeChanged(QTMovie* movie)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_qtMovie.get() == movie);
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::movieNewImageAvailable(QTMovieGWorld* movie)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_qtGWorld.get() == movie);
+#if DRAW_FRAME_RATE
+ if (m_startedPlaying) {
+ m_frameCountWhilePlaying++;
+ // To eliminate preroll costs from our calculation, our frame rate calculation excludes
+ // the first frame drawn after playback starts.
+ if (m_frameCountWhilePlaying == 1)
+ m_timeStartedPlaying = WTF::currentTime();
+ }
+#endif
+
+ m_newFrameAvailable = true;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ m_qtVideoLayer->setNeedsDisplay();
+ else
+#endif
+ m_player->repaint();
+}
+
+bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
+{
+ // We tell quicktime to disallow resources that come from different origins
+ // so we all media is single origin.
+ return true;
+}
+
+MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::currentRenderingMode() const
+{
+ if (!m_qtMovie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::preferredRenderingMode() const
+{
+ if (!m_player->frameView() || !m_qtMovie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+void MediaPlayerPrivate::setUpVideoRendering()
+{
+ MediaRenderingMode currentMode = currentRenderingMode();
+ MediaRenderingMode preferredMode = preferredRenderingMode();
+
+#if !USE(ACCELERATED_COMPOSITING)
+ ASSERT(preferredMode != MediaRenderingMovieLayer);
+#endif
+
+ if (currentMode == preferredMode && currentMode != MediaRenderingNone)
+ return;
+
+ if (currentMode != MediaRenderingNone)
+ tearDownVideoRendering();
+
+ if (preferredMode == MediaRenderingMovieLayer)
+ createLayerForMovie();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+#endif
+}
+
+void MediaPlayerPrivate::tearDownVideoRendering()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ destroyLayerForMovie();
+#endif
+}
+
+bool MediaPlayerPrivate::hasSetUpVideoRendering() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ return m_qtVideoLayer || currentRenderingMode() != MediaRenderingMovieLayer;
+#else
+ return true;
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+
+// Up-call from compositing layer drawing callback.
+void MediaPlayerPrivate::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect&)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(supportsAcceleratedRendering());
+
+ // No reason to replace the current layer image unless we have something new to show.
+ if (!m_newFrameAvailable)
+ return;
+
+ static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ void* buffer;
+ unsigned bitsPerPixel;
+ unsigned rowBytes;
+ unsigned width;
+ unsigned height;
+
+ m_qtGWorld->getCurrentFrameInfo(buffer, bitsPerPixel, rowBytes, width, height);
+ if (!buffer)
+ return;
+
+ RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, static_cast<UInt8*>(buffer), rowBytes * height, kCFAllocatorNull));
+ RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithCFData(data.get()));
+ RetainPtr<CGImageRef> frameImage(AdoptCF, CGImageCreate(width, height, 8, bitsPerPixel, rowBytes, colorSpace,
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst, provider.get(), 0, false, kCGRenderingIntentDefault));
+ if (!frameImage)
+ return;
+
+ IntRect rect(0, 0, m_size.width(), m_size.height());
+ CGContextDrawImage(context.platformContext(), rect, frameImage.get());
+ paintCompleted(context, rect);
+}
+#endif
+
+void MediaPlayerPrivate::createLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(supportsAcceleratedRendering());
+
+ if (!m_qtMovie || m_qtVideoLayer)
+ return;
+
+ // Create a GraphicsLayer that won't be inserted directly into the render tree, but will used
+ // as a wrapper for a PlatformCALayer which gets inserted as the content layer of the video
+ // renderer's GraphicsLayer.
+ m_qtVideoLayer.set(new GraphicsLayerCACF(this));
+ if (!m_qtVideoLayer)
+ return;
+
+ // Mark the layer as drawing itself, anchored in the top left, and bottom-up.
+ m_qtVideoLayer->setDrawsContent(true);
+ m_qtVideoLayer->setAnchorPoint(FloatPoint3D());
+ m_qtVideoLayer->setContentsOrientation(GraphicsLayer::CompositingCoordinatesBottomUp);
+#ifndef NDEBUG
+ m_qtVideoLayer->setName("Video layer");
+#endif
+ // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
+#endif
+}
+
+void MediaPlayerPrivate::destroyLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!m_qtVideoLayer)
+ return;
+ m_qtVideoLayer = 0;
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool MediaPlayerPrivate::supportsAcceleratedRendering() const
+{
+ return isReadyForRendering();
+}
+
+void MediaPlayerPrivate::acceleratedRenderingStateChanged()
+{
+ // Set up or change the rendering path if necessary.
+ setUpVideoRendering();
+}
+
+#endif
+
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
new file mode 100644
index 0000000..ab9b1f0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 MediaPlayerPrivateQuickTimeWin_h
+#define MediaPlayerPrivateQuickTimeWin_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayerPrivate.h"
+#include "Timer.h"
+#include <QTMovie.h>
+#include <QTMovieGWorld.h>
+#include <wtf/Forward.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RetainPtr.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayerClient.h"
+#endif
+
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
+typedef struct CGImage *CGImageRef;
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntSize;
+class IntRect;
+
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface, public QTMovieClient, public QTMovieGWorldClient
+#if USE(ACCELERATED_COMPOSITING)
+ , public GraphicsLayerClient
+#endif
+{
+public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+
+ ~MediaPlayerPrivate();
+
+private:
+
+#if USE(ACCELERATED_COMPOSITING)
+ // GraphicsLayerClient methods
+ virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip);
+ virtual void notifyAnimationStarted(const GraphicsLayer*, double time) { }
+ virtual void notifySyncRequired(const GraphicsLayer*) { }
+ virtual bool showDebugBorders() const { return false; }
+ virtual bool showRepaintCounter() const { return false; }
+#endif
+
+ MediaPlayerPrivate(MediaPlayer*);
+
+ virtual bool supportsFullscreen() const;
+ virtual PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+ bool hasAudio() const;
+
+ void load(const String& url);
+ void cancelLoad();
+
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float time);
+
+ void setRate(float);
+ void setVolume(float);
+ void setPreservesPitch(bool);
+
+ MediaPlayer::NetworkState networkState() const { return m_networkState; }
+ MediaPlayer::ReadyState readyState() const { return m_readyState; }
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setSize(const IntSize&);
+
+ void loadStateChanged();
+ void didEnd();
+
+ void paint(GraphicsContext*, const IntRect&);
+ void paintCompleted(GraphicsContext&, const IntRect&);
+
+ bool hasSingleSecurityOrigin() const;
+
+ bool hasClosedCaptions() const;
+ void setClosedCaptionsVisible(bool);
+
+ void updateStates();
+ void doSeek();
+ void cancelSeek();
+ void seekTimerFired(Timer<MediaPlayerPrivate>*);
+ float maxTimeLoaded() const;
+ void sawUnsupportedTracks();
+
+ virtual void movieEnded(QTMovie*);
+ virtual void movieLoadStateChanged(QTMovie*);
+ virtual void movieTimeChanged(QTMovie*);
+ virtual void movieNewImageAvailable(QTMovieGWorld*);
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer*);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual bool supportsAcceleratedRendering() const;
+ virtual void acceleratedRenderingStateChanged();
+#endif
+
+ enum MediaRenderingMode { MediaRenderingNone, MediaRenderingSoftwareRenderer, MediaRenderingMovieLayer };
+ MediaRenderingMode currentRenderingMode() const;
+ MediaRenderingMode preferredRenderingMode() const;
+ bool isReadyForRendering() const;
+
+ void setUpVideoRendering();
+ void tearDownVideoRendering();
+ bool hasSetUpVideoRendering() const;
+
+ void createLayerForMovie();
+ void destroyLayerForMovie();
+
+ void setUpCookiesForQuickTime(const String& url);
+ String rfc2616DateStringFromTime(CFAbsoluteTime);
+
+ MediaPlayer* m_player;
+ RefPtr<QTMovie> m_qtMovie;
+ RefPtr<QTMovieGWorld> m_qtGWorld;
+#if USE(ACCELERATED_COMPOSITING)
+ OwnPtr<GraphicsLayer> m_qtVideoLayer;
+#endif
+ float m_seekTo;
+ Timer<MediaPlayerPrivate> m_seekTimer;
+ IntSize m_size;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ unsigned m_enabledTrackCount;
+ unsigned m_totalTrackCount;
+ bool m_hasUnsupportedTracks;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+ bool m_visible;
+ bool m_newFrameAvailable;
+#if DRAW_FRAME_RATE
+ double m_frameCountWhilePlaying;
+ double m_timeStartedPlaying;
+ double m_timeStoppedPlaying;
+#endif
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp
new file mode 100644
index 0000000..770e73e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#include "MediaPlayerPrivateTaskTimer.h"
+
+#include "QTMovieTask.h"
+
+namespace WebCore {
+
+MediaPlayerPrivateTaskTimer* MediaPlayerPrivateTaskTimer::s_timer = 0;
+
+void MediaPlayerPrivateTaskTimer::initialize()
+{
+ if (s_timer)
+ return;
+
+ s_timer = new MediaPlayerPrivateTaskTimer;
+
+ QTMovieTask::sharedTask()->setTaskTimerFuncs(setDelay, stopTaskTimer);
+}
+
+void MediaPlayerPrivateTaskTimer::setDelay(double delayInSeconds)
+{
+ ASSERT(s_timer);
+
+ s_timer->startOneShot(delayInSeconds);
+}
+
+void MediaPlayerPrivateTaskTimer::stopTaskTimer()
+{
+ ASSERT(s_timer);
+
+ s_timer->stop();
+}
+
+void MediaPlayerPrivateTaskTimer::fired()
+{
+ QTMovieTask::sharedTask()->fireTaskClients();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h
new file mode 100644
index 0000000..10f861e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 MediaPlayerPrivateTaskTimer_h
+#define MediaPlayerPrivateTaskTimer_h
+
+#include "Timer.h"
+
+namespace WebCore {
+
+class MediaPlayerPrivateTaskTimer : TimerBase {
+public:
+ static void initialize();
+
+private:
+ static void setDelay(double);
+ static void stopTaskTimer();
+
+ void fired();
+
+ static MediaPlayerPrivateTaskTimer* s_timer;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTCFDictionary.cpp b/Source/WebCore/platform/graphics/win/QTCFDictionary.cpp
new file mode 100644
index 0000000..3c72792
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTCFDictionary.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#include "QTCFDictionary.h"
+
+#include <CFData.h>
+#include <windows.h>
+
+CFDataRef QTCFPropertyListCreateXMLData(CFAllocatorRef allocator, CFPropertyListRef propertyList)
+{
+
+ typedef CFDataRef (* pfnCFPropertyListCreateXMLData)(CFAllocatorRef allocator, CFPropertyListRef propertyList);
+ static pfnCFPropertyListCreateXMLData pCFPropertyListCreateXMLData = 0;
+ if (!pCFPropertyListCreateXMLData) {
+ HMODULE qtcfDLL = LoadLibraryW(L"QTCF.dll");
+ if (qtcfDLL)
+ pCFPropertyListCreateXMLData = reinterpret_cast<pfnCFPropertyListCreateXMLData>(GetProcAddress(qtcfDLL, "QTCF_CFPropertyListCreateXMLData"));
+ }
+
+ if (pCFPropertyListCreateXMLData)
+ return pCFPropertyListCreateXMLData(allocator, propertyList);
+ return 0;
+}
+
+CFDictionaryRef QTCFDictionaryCreateCopyWithDataCallback(CFAllocatorRef allocator, CFDictionaryRef dictionary, QTCFDictonaryCreateFromDataCallback callback)
+{
+ ASSERT(dictionary);
+ ASSERT(callback);
+
+ CFDataRef data = QTCFPropertyListCreateXMLData(kCFAllocatorDefault, dictionary);
+ if (!data)
+ return 0;
+ CFDictionaryRef outputDictionary = callback(allocator, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFRelease(data);
+
+ return outputDictionary;
+}
diff --git a/Source/WebCore/platform/graphics/win/QTCFDictionary.h b/Source/WebCore/platform/graphics/win/QTCFDictionary.h
new file mode 100644
index 0000000..ff34328
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTCFDictionary.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 QTCFDictionary_h
+#define QTCFDictionary_h
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+#include <CoreFoundation/CFBase.h>
+
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+
+typedef CFDictionaryRef (* QTCFDictonaryCreateFromDataCallback)(CFAllocatorRef, const UInt8*, CFIndex);
+
+QTMOVIEWIN_API CFDictionaryRef QTCFDictionaryCreateCopyWithDataCallback(CFAllocatorRef, CFDictionaryRef, QTCFDictonaryCreateFromDataCallback);
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTDecompressionSession.cpp b/Source/WebCore/platform/graphics/win/QTDecompressionSession.cpp
new file mode 100644
index 0000000..eeb3ca7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTDecompressionSession.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+#include "config.h"
+
+#include "QTDecompressionSession.h"
+
+#include <ImageCompression.h>
+#include <algorithm>
+
+class QTDecompressionSessionClient {
+public:
+ static void trackingCallback(void *decompressionTrackingRefCon, OSStatus,
+ ICMDecompressionTrackingFlags decompressionTrackingFlags, CVPixelBufferRef pixelBuffer,
+ TimeValue64, TimeValue64, ICMValidTimeFlags, void *, void *)
+ {
+ QTDecompressionSession* session = static_cast<QTDecompressionSession*>(decompressionTrackingRefCon);
+ ASSERT(session);
+
+ if (decompressionTrackingFlags & kICMDecompressionTracking_FrameDecoded)
+ session->m_latestFrame = QTPixelBuffer(pixelBuffer);
+ }
+};
+
+PassOwnPtr<QTDecompressionSession> QTDecompressionSession::create(unsigned long pixelFormat, size_t width, size_t height)
+{
+ return adoptPtr(new QTDecompressionSession(pixelFormat, width, height));
+}
+
+QTDecompressionSession::QTDecompressionSession(unsigned long pixelFormat, size_t width, size_t height)
+ : m_session(0)
+ , m_pixelFormat(pixelFormat)
+ , m_width(width)
+ , m_height(height)
+{
+ initializeSession();
+}
+
+QTDecompressionSession::~QTDecompressionSession()
+{
+ if (m_session)
+ ICMDecompressionSessionRelease(m_session);
+}
+
+void QTDecompressionSession::initializeSession()
+{
+ if (m_session)
+ return;
+
+ ICMPixelFormatInfo pixelFormatInfo = {sizeof(ICMPixelFormatInfo), 0};
+ if (ICMGetPixelFormatInfo(m_pixelFormat, &pixelFormatInfo) != noErr) {
+ // The ICM does not know anything about the pixelFormat contained in
+ // the pixel buffer, so it won't be able to convert it to RGBA.
+ return;
+ }
+
+ // The depth and cType fields of the ImageDescriptionHandle are filled
+ // out according to the instructions in Technical Q&A QA1183:
+ // http://developer.apple.com/library/mac/#qa/qa2001/qa1183.html
+ bool isIndexed = pixelFormatInfo.formatFlags & kICMPixelFormatIsIndexed;
+ bool isQD = pixelFormatInfo.formatFlags & kICMPixelFormatIsSupportedByQD;
+ bool isMonochrome = pixelFormatInfo.formatFlags & kICMPixelFormatIsMonochrome;
+ bool hasAlpha = pixelFormatInfo.formatFlags & kICMPixelFormatHasAlphaChannel;
+
+ unsigned int depth = 24; // The default depth is 24.
+ if (hasAlpha)
+ depth = 32; // Any pixel format with alpha gets a depth of 32.
+ else if (isMonochrome) {
+ // Grayscale pixel formats get depths 33 through 40, depending
+ // on their bits per pixel. Yes, this means that 16-bit grayscale
+ // and 8-bit grayscale have the same pixel depth.
+ depth = 32 + std::min<unsigned int>(8, pixelFormatInfo.bitsPerPixel[0]);
+ } else if (isIndexed) {
+ // Indexed pixel formats get a depth of 1 through 8, depending on
+ // the their bits per pixel.
+ depth = pixelFormatInfo.bitsPerPixel[0];
+ }
+
+ // If QuickDraw supports the given pixel format, the cType should be kRawCodecType.
+ // Otherwise, use the pixel format code for the cType. We are assuming the pixel
+ // buffer is uncompressed.
+ unsigned long cType = isQD ? kRawCodecType : m_pixelFormat;
+
+ ImageDescriptionHandle description = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
+ (**description).idSize = sizeof(ImageDescription);
+ (**description).cType = cType;
+ (**description).version = 2;
+ (**description).spatialQuality = codecLosslessQuality;
+ (**description).width = m_width;
+ (**description).height = m_height;
+ (**description).hRes = 72 << 16; // 72 DPI as a fixed-point number
+ (**description).vRes = 72 << 16; // 72 DPI as a fixed-point number
+ (**description).frameCount = 1;
+ (**description).depth = depth;
+ (**description).clutID = -1;
+
+ // Create the mandatory ICMDecompressionSessionOptions, but leave
+ // all the default values.
+ ICMDecompressionSessionOptionsRef options = 0;
+ ICMDecompressionSessionOptionsCreate(kCFAllocatorDefault, &options);
+
+ CFDictionaryRef pixelBufferAttributes = QTPixelBuffer::createPixelBufferAttributesDictionary(QTPixelBuffer::ConfigureForCGImage);
+
+ ICMDecompressionTrackingCallbackRecord callback = {
+ QTDecompressionSessionClient::trackingCallback,
+ this,
+ };
+
+ ICMDecompressionSessionCreate(kCFAllocatorDefault,
+ description,
+ options,
+ pixelBufferAttributes,
+ &callback,
+ &m_session);
+
+ if (pixelBufferAttributes)
+ CFRelease(pixelBufferAttributes);
+
+ ICMDecompressionSessionOptionsRelease(options);
+ DisposeHandle((Handle)description);
+}
+
+bool QTDecompressionSession::canDecompress(QTPixelBuffer inBuffer)
+{
+ return m_session
+ && inBuffer.pixelFormatType() == m_pixelFormat
+ && inBuffer.width() == m_width
+ && inBuffer.height() == m_height;
+}
+
+QTPixelBuffer QTDecompressionSession::decompress(QTPixelBuffer inBuffer)
+{
+ if (!canDecompress(inBuffer))
+ return QTPixelBuffer();
+
+ inBuffer.lockBaseAddress();
+ ICMDecompressionSessionDecodeFrame(m_session,
+ static_cast<UInt8*>(inBuffer.baseAddress()),
+ inBuffer.dataSize(),
+ 0, // frameOptions
+ 0, // frameTime
+ 0); // sourceFrameRefCon
+
+ // Because we passed in 0 for frameTime, the above function
+ // is synchronous, and the client callback will have been
+ // called before the function returns, and m_latestFrame
+ // will contain the newly decompressed frame.
+ return m_latestFrame;
+}
diff --git a/Source/WebCore/platform/graphics/win/QTDecompressionSession.h b/Source/WebCore/platform/graphics/win/QTDecompressionSession.h
new file mode 100644
index 0000000..67b6635
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTDecompressionSession.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 QTDecompressionSession_h
+#define QTDecompressionSession_h
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+#include "QTPixelBuffer.h"
+
+#include <WTF/PassOwnPtr.h>
+
+class QTDecompressionSessionClient;
+typedef struct OpaqueICMDecompressionSession* ICMDecompressionSessionRef;
+
+class QTMOVIEWIN_API QTDecompressionSession {
+public:
+ static PassOwnPtr<QTDecompressionSession> create(unsigned long pixelFormat, size_t width, size_t height);
+ ~QTDecompressionSession();
+
+ bool canDecompress(QTPixelBuffer);
+
+ // The resulting QTPixelBuffer will be a CG compatable ARGB pixel buffer.
+ QTPixelBuffer decompress(QTPixelBuffer);
+
+private:
+ friend class QTDecompressionSessionClient;
+ QTDecompressionSession(unsigned long pixelFormat, size_t width, size_t height);
+ void initializeSession();
+
+ unsigned long m_pixelFormat;
+ size_t m_width;
+ size_t m_height;
+ QTPixelBuffer m_latestFrame;
+ ICMDecompressionSessionRef m_session;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovie.cpp b/Source/WebCore/platform/graphics/win/QTMovie.cpp
new file mode 100644
index 0000000..efaf218
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovie.cpp
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+#include "config.h"
+
+#include "QTMovie.h"
+
+#include "QTMovieTask.h"
+#include "QTMovieWinTimer.h"
+#include <FixMath.h>
+#include <GXMath.h>
+#include <Movies.h>
+#include <QTML.h>
+#include <QuickTimeComponents.h>
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+static const long minimumQuickTimeVersion = 0x07300000; // 7.3
+
+static const long closedCaptionTrackType = 'clcp';
+static const long subTitleTrackType = 'sbtl';
+static const long mpeg4ObjectDescriptionTrackType = 'odsm';
+static const long mpeg4SceneDescriptionTrackType = 'sdsm';
+static const long closedCaptionDisplayPropertyID = 'disp';
+static LPCTSTR fullscreenQTMoviePointerProp = TEXT("fullscreenQTMoviePointer");
+
+// Resizing GWorlds is slow, give them a minimum size so size of small
+// videos can be animated smoothly
+static const int cGWorldMinWidth = 640;
+static const int cGWorldMinHeight = 360;
+
+static const float cNonContinuousTimeChange = 0.2f;
+
+union UppParam {
+ long longValue;
+ void* ptr;
+};
+
+static Vector<CFStringRef>* gSupportedTypes = 0;
+static SInt32 quickTimeVersion = 0;
+
+class QTMoviePrivate : public Noncopyable, public QTMovieTaskClient {
+public:
+ QTMoviePrivate();
+ ~QTMoviePrivate();
+ void task();
+ void startTask();
+ void endTask();
+
+ void createMovieController();
+ void cacheMovieScale();
+
+ QTMovie* m_movieWin;
+ Movie m_movie;
+ MovieController m_movieController;
+ bool m_tasking;
+ bool m_disabled;
+ Vector<QTMovieClient*> m_clients;
+ long m_loadState;
+ bool m_ended;
+ bool m_seeking;
+ float m_lastMediaTime;
+ double m_lastLoadStateCheckTime;
+ int m_width;
+ int m_height;
+ bool m_visible;
+ long m_loadError;
+ float m_widthScaleFactor;
+ float m_heightScaleFactor;
+ CFURLRef m_currentURL;
+ float m_timeToRestore;
+ float m_rateToRestore;
+#if !ASSERT_DISABLED
+ bool m_scaleCached;
+#endif
+};
+
+QTMoviePrivate::QTMoviePrivate()
+ : m_movieWin(0)
+ , m_movie(0)
+ , m_movieController(0)
+ , m_tasking(false)
+ , m_loadState(0)
+ , m_ended(false)
+ , m_seeking(false)
+ , m_lastMediaTime(0)
+ , m_lastLoadStateCheckTime(0)
+ , m_width(0)
+ , m_height(0)
+ , m_visible(false)
+ , m_loadError(0)
+ , m_widthScaleFactor(1)
+ , m_heightScaleFactor(1)
+ , m_currentURL(0)
+ , m_timeToRestore(-1.0f)
+ , m_rateToRestore(-1.0f)
+ , m_disabled(false)
+#if !ASSERT_DISABLED
+ , m_scaleCached(false)
+#endif
+{
+}
+
+QTMoviePrivate::~QTMoviePrivate()
+{
+ endTask();
+ if (m_movieController)
+ DisposeMovieController(m_movieController);
+ if (m_movie)
+ DisposeMovie(m_movie);
+ if (m_currentURL)
+ CFRelease(m_currentURL);
+}
+
+void QTMoviePrivate::startTask()
+{
+ if (!m_tasking) {
+ QTMovieTask::sharedTask()->addTaskClient(this);
+ m_tasking = true;
+ }
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMoviePrivate::endTask()
+{
+ if (m_tasking) {
+ QTMovieTask::sharedTask()->removeTaskClient(this);
+ m_tasking = false;
+ }
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMoviePrivate::task()
+{
+ ASSERT(m_tasking);
+
+ if (!m_loadError) {
+ if (m_movieController)
+ MCIdle(m_movieController);
+ else
+ MoviesTask(m_movie, 0);
+ }
+
+ // GetMovieLoadState documentation says that you should not call it more often than every quarter of a second.
+ if (systemTime() >= m_lastLoadStateCheckTime + 0.25 || m_loadError) {
+ // If load fails QT's load state is QTMovieLoadStateComplete.
+ // This is different from QTKit API and seems strange.
+ long loadState = m_loadError ? QTMovieLoadStateError : GetMovieLoadState(m_movie);
+ if (loadState != m_loadState) {
+ // we only need to erase the movie gworld when the load state changes to loaded while it
+ // is visible as the gworld is destroyed/created when visibility changes
+ bool shouldRestorePlaybackState = false;
+ bool movieNewlyPlayable = loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded;
+ m_loadState = loadState;
+ if (movieNewlyPlayable) {
+ cacheMovieScale();
+ shouldRestorePlaybackState = true;
+ }
+
+ if (!m_movieController && m_loadState >= QTMovieLoadStateLoaded)
+ createMovieController();
+
+ for (size_t i = 0; i < m_clients.size(); ++i)
+ m_clients[i]->movieLoadStateChanged(m_movieWin);
+
+ if (shouldRestorePlaybackState && m_timeToRestore != -1.0f) {
+ m_movieWin->setCurrentTime(m_timeToRestore);
+ m_timeToRestore = -1.0f;
+ m_movieWin->setRate(m_rateToRestore);
+ m_rateToRestore = -1.0f;
+ }
+
+ if (m_disabled) {
+ endTask();
+ return;
+ }
+ }
+ m_lastLoadStateCheckTime = systemTime();
+ }
+
+ bool ended = !!IsMovieDone(m_movie);
+ if (ended != m_ended) {
+ m_ended = ended;
+ if (ended) {
+ for (size_t i = 0; i < m_clients.size(); ++i)
+ m_clients[i]->movieEnded(m_movieWin);
+ }
+ }
+
+ float time = m_movieWin->currentTime();
+ if (time < m_lastMediaTime || time >= m_lastMediaTime + cNonContinuousTimeChange || m_seeking) {
+ m_seeking = false;
+ for (size_t i = 0; i < m_clients.size(); ++i)
+ m_clients[i]->movieTimeChanged(m_movieWin);
+ }
+ m_lastMediaTime = time;
+
+ if (m_loadError)
+ endTask();
+ else
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMoviePrivate::createMovieController()
+{
+ Rect bounds;
+ long flags;
+
+ if (!m_movie)
+ return;
+
+ if (m_movieController)
+ DisposeMovieController(m_movieController);
+
+ GetMovieBox(m_movie, &bounds);
+ flags = mcTopLeftMovie | mcNotVisible;
+ m_movieController = NewMovieController(m_movie, &bounds, flags);
+ if (!m_movieController)
+ return;
+
+ // Disable automatic looping.
+ MCDoAction(m_movieController, mcActionSetLooping, 0);
+}
+
+void QTMoviePrivate::cacheMovieScale()
+{
+ Rect naturalRect;
+ Rect initialRect;
+
+ GetMovieNaturalBoundsRect(m_movie, &naturalRect);
+ GetMovieBox(m_movie, &initialRect);
+
+ float naturalWidth = naturalRect.right - naturalRect.left;
+ float naturalHeight = naturalRect.bottom - naturalRect.top;
+
+ if (naturalWidth)
+ m_widthScaleFactor = (initialRect.right - initialRect.left) / naturalWidth;
+ if (naturalHeight)
+ m_heightScaleFactor = (initialRect.bottom - initialRect.top) / naturalHeight;
+#if !ASSERT_DISABLED
+ m_scaleCached = true;
+#endif
+}
+
+QTMovie::QTMovie(QTMovieClient* client)
+ : m_private(new QTMoviePrivate())
+{
+ m_private->m_movieWin = this;
+ if (client)
+ m_private->m_clients.append(client);
+ initializeQuickTime();
+}
+
+QTMovie::~QTMovie()
+{
+ delete m_private;
+}
+
+void QTMovie::disableComponent(uint32_t cd[5])
+{
+ ComponentDescription nullDesc = {'null', 'base', kAppleManufacturer, 0, 0};
+ Component nullComp = FindNextComponent(0, &nullDesc);
+ Component disabledComp = 0;
+
+ while (disabledComp = FindNextComponent(disabledComp, (ComponentDescription*)&cd[0]))
+ CaptureComponent(disabledComp, nullComp);
+}
+
+void QTMovie::addClient(QTMovieClient* client)
+{
+ if (client)
+ m_private->m_clients.append(client);
+}
+
+void QTMovie::removeClient(QTMovieClient* client)
+{
+ size_t indexOfClient = m_private->m_clients.find(client);
+ if (indexOfClient != notFound)
+ m_private->m_clients.remove(indexOfClient);
+}
+
+void QTMovie::play()
+{
+ m_private->m_timeToRestore = -1.0f;
+
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)GetMoviePreferredRate(m_private->m_movie));
+ else
+ StartMovie(m_private->m_movie);
+ m_private->startTask();
+}
+
+void QTMovie::pause()
+{
+ m_private->m_timeToRestore = -1.0f;
+
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPlay, 0);
+ else
+ StopMovie(m_private->m_movie);
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+float QTMovie::rate() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ return FixedToFloat(GetMovieRate(m_private->m_movie));
+}
+
+void QTMovie::setRate(float rate)
+{
+ if (!m_private->m_movie)
+ return;
+ m_private->m_timeToRestore = -1.0f;
+
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)FloatToFixed(rate));
+ else
+ SetMovieRate(m_private->m_movie, FloatToFixed(rate));
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+float QTMovie::duration() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ TimeValue val = GetMovieDuration(m_private->m_movie);
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ return static_cast<float>(val) / scale;
+}
+
+float QTMovie::currentTime() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ TimeValue val = GetMovieTime(m_private->m_movie, 0);
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ return static_cast<float>(val) / scale;
+}
+
+void QTMovie::setCurrentTime(float time) const
+{
+ if (!m_private->m_movie)
+ return;
+
+ m_private->m_timeToRestore = -1.0f;
+
+ m_private->m_seeking = true;
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ if (m_private->m_movieController) {
+ QTRestartAtTimeRecord restart = { time * scale , 0 };
+ MCDoAction(m_private->m_movieController, mcActionRestartAtTime, (void *)&restart);
+ } else
+ SetMovieTimeValue(m_private->m_movie, TimeValue(time * scale));
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMovie::setVolume(float volume)
+{
+ if (!m_private->m_movie)
+ return;
+ SetMovieVolume(m_private->m_movie, static_cast<short>(volume * 256));
+}
+
+void QTMovie::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_private->m_movie || !m_private->m_currentURL)
+ return;
+
+ OSErr error;
+ bool prop = false;
+
+ error = QTGetMovieProperty(m_private->m_movie, kQTPropertyClass_Audio, kQTAudioPropertyID_RateChangesPreservePitch,
+ sizeof(kQTAudioPropertyID_RateChangesPreservePitch), static_cast<QTPropertyValuePtr>(&prop), 0);
+
+ if (error || prop == preservesPitch)
+ return;
+
+ m_private->m_timeToRestore = currentTime();
+ m_private->m_rateToRestore = rate();
+ load(m_private->m_currentURL, preservesPitch);
+}
+
+unsigned QTMovie::dataSize() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ return GetMovieDataSize(m_private->m_movie, 0, GetMovieDuration(m_private->m_movie));
+}
+
+float QTMovie::maxTimeLoaded() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ TimeValue val;
+ GetMaxLoadedTimeInMovie(m_private->m_movie, &val);
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ return static_cast<float>(val) / scale;
+}
+
+long QTMovie::loadState() const
+{
+ return m_private->m_loadState;
+}
+
+void QTMovie::getNaturalSize(int& width, int& height)
+{
+ Rect rect = { 0, };
+
+ if (m_private->m_movie)
+ GetMovieNaturalBoundsRect(m_private->m_movie, &rect);
+ width = (rect.right - rect.left) * m_private->m_widthScaleFactor;
+ height = (rect.bottom - rect.top) * m_private->m_heightScaleFactor;
+}
+
+void QTMovie::load(const UChar* url, int len, bool preservesPitch)
+{
+ CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len);
+ CFURLRef cfURL = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0);
+
+ load(cfURL, preservesPitch);
+
+ CFRelease(cfURL);
+ CFRelease(urlStringRef);
+}
+
+void QTMovie::load(CFURLRef url, bool preservesPitch)
+{
+ if (!url)
+ return;
+
+ if (m_private->m_movie) {
+ m_private->endTask();
+ if (m_private->m_movieController)
+ DisposeMovieController(m_private->m_movieController);
+ m_private->m_movieController = 0;
+ DisposeMovie(m_private->m_movie);
+ m_private->m_movie = 0;
+ m_private->m_loadState = 0;
+ }
+
+ // Define a property array for NewMovieFromProperties. 8 should be enough for our needs.
+ QTNewMoviePropertyElement movieProps[8];
+ ItemCount moviePropCount = 0;
+
+ bool boolTrue = true;
+
+ // Disable streaming support for now.
+ CFStringRef scheme = CFURLCopyScheme(url);
+ bool isRTSP = CFStringHasPrefix(scheme, CFSTR("rtsp:"));
+ CFRelease(scheme);
+
+ if (isRTSP) {
+ m_private->m_loadError = noMovieFound;
+ goto end;
+ }
+
+ if (m_private->m_currentURL) {
+ if (m_private->m_currentURL != url) {
+ CFRelease(m_private->m_currentURL);
+ m_private->m_currentURL = url;
+ CFRetain(url);
+ }
+ } else {
+ m_private->m_currentURL = url;
+ CFRetain(url);
+ }
+
+ // Add the movie data location to the property array
+ movieProps[moviePropCount].propClass = kQTPropertyClass_DataLocation;
+ movieProps[moviePropCount].propID = kQTDataLocationPropertyID_CFURL;
+ movieProps[moviePropCount].propValueSize = sizeof(m_private->m_currentURL);
+ movieProps[moviePropCount].propValueAddress = &(m_private->m_currentURL);
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_DontAskUnresolvedDataRefs;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_AsyncOK;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty;
+ movieProps[moviePropCount].propID = kQTNewMoviePropertyID_Active;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty;
+ movieProps[moviePropCount].propID = kQTNewMoviePropertyID_DontInteractWithUser;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = '!url';
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = 'site';
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_Audio;
+ movieProps[moviePropCount].propID = kQTAudioPropertyID_RateChangesPreservePitch;
+ movieProps[moviePropCount].propValueSize = sizeof(preservesPitch);
+ movieProps[moviePropCount].propValueAddress = &preservesPitch;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ ASSERT(moviePropCount <= WTF_ARRAY_LENGTH(movieProps));
+ m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, 0, &m_private->m_movie);
+
+end:
+ m_private->startTask();
+ // get the load fail callback quickly
+ if (m_private->m_loadError)
+ QTMovieTask::sharedTask()->updateTaskTimer(0);
+ else {
+ OSType mode = kQTApertureMode_CleanAperture;
+
+ // Set the aperture mode property on a movie to signal that we want aspect ratio
+ // and clean aperture dimensions. Don't worry about errors, we can't do anything if
+ // the installed version of QT doesn't support it and it isn't serious enough to
+ // warrant failing.
+ QTSetMovieProperty(m_private->m_movie, kQTPropertyClass_Visual, kQTVisualPropertyID_ApertureMode, sizeof(mode), &mode);
+ }
+}
+
+void QTMovie::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount)
+{
+ if (!m_private->m_movie) {
+ totalTrackCount = 0;
+ enabledTrackCount = 0;
+ return;
+ }
+
+ static HashSet<OSType>* allowedTrackTypes = 0;
+ if (!allowedTrackTypes) {
+ allowedTrackTypes = new HashSet<OSType>;
+ allowedTrackTypes->add(VideoMediaType);
+ allowedTrackTypes->add(SoundMediaType);
+ allowedTrackTypes->add(TextMediaType);
+ allowedTrackTypes->add(BaseMediaType);
+ allowedTrackTypes->add(closedCaptionTrackType);
+ allowedTrackTypes->add(subTitleTrackType);
+ allowedTrackTypes->add(mpeg4ObjectDescriptionTrackType);
+ allowedTrackTypes->add(mpeg4SceneDescriptionTrackType);
+ allowedTrackTypes->add(TimeCodeMediaType);
+ allowedTrackTypes->add(TimeCode64MediaType);
+ }
+
+ long trackCount = GetMovieTrackCount(m_private->m_movie);
+ enabledTrackCount = trackCount;
+ totalTrackCount = trackCount;
+
+ // Track indexes are 1-based. yuck. These things must descend from old-
+ // school mac resources or something.
+ for (long trackIndex = 1; trackIndex <= trackCount; trackIndex++) {
+ // Grab the track at the current index. If there isn't one there, then
+ // we can move onto the next one.
+ Track currentTrack = GetMovieIndTrack(m_private->m_movie, trackIndex);
+ if (!currentTrack)
+ continue;
+
+ // Check to see if the track is disabled already, we should move along.
+ // We don't need to re-disable it.
+ if (!GetTrackEnabled(currentTrack))
+ continue;
+
+ // Grab the track's media. We're going to check to see if we need to
+ // disable the tracks. They could be unsupported.
+ Media trackMedia = GetTrackMedia(currentTrack);
+ if (!trackMedia)
+ continue;
+
+ // Grab the media type for this track. Make sure that we don't
+ // get an error in doing so. If we do, then something really funky is
+ // wrong.
+ OSType mediaType;
+ GetMediaHandlerDescription(trackMedia, &mediaType, nil, nil);
+ OSErr mediaErr = GetMoviesError();
+ if (mediaErr != noErr)
+ continue;
+
+ if (!allowedTrackTypes->contains(mediaType)) {
+
+ // Different mpeg variants import as different track types so check for the "mpeg
+ // characteristic" instead of hard coding the (current) list of mpeg media types.
+ if (GetMovieIndTrackType(m_private->m_movie, 1, 'mpeg', movieTrackCharacteristic | movieTrackEnabledOnly))
+ continue;
+
+ SetTrackEnabled(currentTrack, false);
+ --enabledTrackCount;
+ }
+
+ // Grab the track reference count for chapters. This will tell us if it
+ // has chapter tracks in it. If there aren't any references, then we
+ // can move on the next track.
+ long referenceCount = GetTrackReferenceCount(currentTrack, kTrackReferenceChapterList);
+ if (referenceCount <= 0)
+ continue;
+
+ long referenceIndex = 0;
+ while (1) {
+ // If we get nothing here, we've overstepped our bounds and can stop
+ // looking. Chapter indices here are 1-based as well - hence, the
+ // pre-increment.
+ referenceIndex++;
+ Track chapterTrack = GetTrackReference(currentTrack, kTrackReferenceChapterList, referenceIndex);
+ if (!chapterTrack)
+ break;
+
+ // Try to grab the media for the track.
+ Media chapterMedia = GetTrackMedia(chapterTrack);
+ if (!chapterMedia)
+ continue;
+
+ // Grab the media type for this track. Make sure that we don't
+ // get an error in doing so. If we do, then something really
+ // funky is wrong.
+ OSType mediaType;
+ GetMediaHandlerDescription(chapterMedia, &mediaType, nil, nil);
+ OSErr mediaErr = GetMoviesError();
+ if (mediaErr != noErr)
+ continue;
+
+ // Check to see if the track is a video track. We don't care about
+ // other non-video tracks.
+ if (mediaType != VideoMediaType)
+ continue;
+
+ // Check to see if the track is already disabled. If it is, we
+ // should move along.
+ if (!GetTrackEnabled(chapterTrack))
+ continue;
+
+ // Disabled the evil, evil track.
+ SetTrackEnabled(chapterTrack, false);
+ --enabledTrackCount;
+ }
+ }
+}
+
+bool QTMovie::isDisabled() const
+{
+ return m_private->m_disabled;
+}
+
+void QTMovie::setDisabled(bool b)
+{
+ m_private->m_disabled = b;
+}
+
+
+bool QTMovie::hasVideo() const
+{
+ if (!m_private->m_movie)
+ return false;
+ return (GetMovieIndTrackType(m_private->m_movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly));
+}
+
+bool QTMovie::hasAudio() const
+{
+ if (!m_private->m_movie)
+ return false;
+ return (GetMovieIndTrackType(m_private->m_movie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly));
+}
+
+QTTrackArray QTMovie::videoTracks() const
+{
+ QTTrackArray tracks;
+ long trackIndex = 1;
+
+ while (Track theTrack = GetMovieIndTrackType(m_private->m_movie, trackIndex++, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly))
+ tracks.append(QTTrack::create(theTrack));
+
+ return tracks;
+}
+
+bool QTMovie::hasClosedCaptions() const
+{
+ if (!m_private->m_movie)
+ return false;
+ return GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType);
+}
+
+void QTMovie::setClosedCaptionsVisible(bool visible)
+{
+ if (!m_private->m_movie)
+ return;
+
+ Track ccTrack = GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType);
+ if (!ccTrack)
+ return;
+
+ Boolean doDisplay = visible;
+ QTSetTrackProperty(ccTrack, closedCaptionTrackType, closedCaptionDisplayPropertyID, sizeof(doDisplay), &doDisplay);
+}
+
+long QTMovie::timeScale() const
+{
+ if (!m_private->m_movie)
+ return 0;
+
+ return GetMovieTimeScale(m_private->m_movie);
+}
+
+static void initializeSupportedTypes()
+{
+ if (gSupportedTypes)
+ return;
+
+ gSupportedTypes = new Vector<CFStringRef>;
+ if (quickTimeVersion < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Returning empty list of supported media MIME types.", quickTimeVersion, minimumQuickTimeVersion);
+ return;
+ }
+
+ // QuickTime doesn't have an importer for video/quicktime. Add it manually.
+ gSupportedTypes->append(CFSTR("video/quicktime"));
+
+ for (int index = 0; index < 2; index++) {
+ ComponentDescription findCD;
+
+ // look at all movie importers that can import in place and are installed.
+ findCD.componentType = MovieImportType;
+ findCD.componentSubType = 0;
+ findCD.componentManufacturer = 0;
+ findCD.componentFlagsMask = cmpIsMissing | movieImportSubTypeIsFileExtension | canMovieImportInPlace | dontAutoFileMovieImport;
+
+ // look at those registered by HFS file types the first time through, by file extension the second time
+ findCD.componentFlags = canMovieImportInPlace | (index ? movieImportSubTypeIsFileExtension : 0);
+
+ long componentCount = CountComponents(&findCD);
+ if (!componentCount)
+ continue;
+
+ Component comp = 0;
+ while (comp = FindNextComponent(comp, &findCD)) {
+ // Does this component have a MIME type container?
+ ComponentDescription infoCD;
+ OSErr err = GetComponentInfo(comp, &infoCD, nil /*name*/, nil /*info*/, nil /*icon*/);
+ if (err)
+ continue;
+ if (!(infoCD.componentFlags & hasMovieImportMIMEList))
+ continue;
+ QTAtomContainer mimeList = 0;
+ err = MovieImportGetMIMETypeList((ComponentInstance)comp, &mimeList);
+ if (err || !mimeList)
+ continue;
+
+ // Grab every type from the container.
+ QTLockContainer(mimeList);
+ int typeCount = QTCountChildrenOfType(mimeList, kParentAtomIsContainer, kMimeInfoMimeTypeTag);
+ for (int typeIndex = 1; typeIndex <= typeCount; typeIndex++) {
+ QTAtom mimeTag = QTFindChildByIndex(mimeList, 0, kMimeInfoMimeTypeTag, typeIndex, 0);
+ if (!mimeTag)
+ continue;
+ char* atomData;
+ long typeLength;
+ if (noErr != QTGetAtomDataPtr(mimeList, mimeTag, &typeLength, &atomData))
+ continue;
+
+ char typeBuffer[256];
+ if (typeLength >= sizeof(typeBuffer))
+ continue;
+ memcpy(typeBuffer, atomData, typeLength);
+ typeBuffer[typeLength] = 0;
+
+ // Only add "audio/..." and "video/..." types.
+ if (strncmp(typeBuffer, "audio/", 6) && strncmp(typeBuffer, "video/", 6))
+ continue;
+
+ CFStringRef cfMimeType = CFStringCreateWithCString(0, typeBuffer, kCFStringEncodingUTF8);
+ if (!cfMimeType)
+ continue;
+
+ // Only add each type once.
+ bool alreadyAdded = false;
+ for (int addedIndex = 0; addedIndex < gSupportedTypes->size(); addedIndex++) {
+ CFStringRef type = gSupportedTypes->at(addedIndex);
+ if (kCFCompareEqualTo == CFStringCompare(cfMimeType, type, kCFCompareCaseInsensitive)) {
+ alreadyAdded = true;
+ break;
+ }
+ }
+ if (!alreadyAdded)
+ gSupportedTypes->append(cfMimeType);
+ else
+ CFRelease(cfMimeType);
+ }
+ DisposeHandle(mimeList);
+ }
+ }
+}
+
+unsigned QTMovie::countSupportedTypes()
+{
+ initializeSupportedTypes();
+ return static_cast<unsigned>(gSupportedTypes->size());
+}
+
+void QTMovie::getSupportedType(unsigned index, const UChar*& str, unsigned& len)
+{
+ initializeSupportedTypes();
+ ASSERT(index < gSupportedTypes->size());
+
+ // Allocate sufficient buffer to hold any MIME type
+ static UniChar* staticBuffer = 0;
+ if (!staticBuffer)
+ staticBuffer = new UniChar[32];
+
+ CFStringRef cfstr = gSupportedTypes->at(index);
+ len = CFStringGetLength(cfstr);
+ CFRange range = { 0, len };
+ CFStringGetCharacters(cfstr, range, staticBuffer);
+ str = reinterpret_cast<const UChar*>(staticBuffer);
+
+}
+
+CGAffineTransform QTMovie::getTransform() const
+{
+ ASSERT(m_private->m_movie);
+ MatrixRecord m = {0};
+ GetMovieMatrix(m_private->m_movie, &m);
+
+ ASSERT(!m.matrix[0][2]);
+ ASSERT(!m.matrix[1][2]);
+ CGAffineTransform transform = CGAffineTransformMake(
+ Fix2X(m.matrix[0][0]),
+ Fix2X(m.matrix[0][1]),
+ Fix2X(m.matrix[1][0]),
+ Fix2X(m.matrix[1][1]),
+ Fix2X(m.matrix[2][0]),
+ Fix2X(m.matrix[2][1]));
+ return transform;
+}
+
+void QTMovie::setTransform(CGAffineTransform t)
+{
+ ASSERT(m_private->m_movie);
+ MatrixRecord m = {{
+ {X2Fix(t.a), X2Fix(t.b), 0},
+ {X2Fix(t.c), X2Fix(t.d), 0},
+ {X2Fix(t.tx), X2Fix(t.ty), fract1},
+ }};
+
+ SetMovieMatrix(m_private->m_movie, &m);
+ m_private->cacheMovieScale();
+}
+
+void QTMovie::resetTransform()
+{
+ ASSERT(m_private->m_movie);
+ SetMovieMatrix(m_private->m_movie, 0);
+ m_private->cacheMovieScale();
+}
+
+
+bool QTMovie::initializeQuickTime()
+{
+ static bool initialized = false;
+ static bool initializationSucceeded = false;
+ if (!initialized) {
+ initialized = true;
+ // Initialize and check QuickTime version
+ OSErr result = InitializeQTML(kInitializeQTMLEnableDoubleBufferedSurface);
+ if (result == noErr)
+ result = Gestalt(gestaltQuickTime, &quickTimeVersion);
+ if (result != noErr) {
+ LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support.");
+ return false;
+ }
+ if (quickTimeVersion < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", quickTimeVersion, minimumQuickTimeVersion);
+ return false;
+ }
+ EnterMovies();
+ initializationSucceeded = true;
+ }
+ return initializationSucceeded;
+}
+
+Movie QTMovie::getMovieHandle() const
+{
+ return m_private->m_movie;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ return TRUE;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ return FALSE;
+ }
+ ASSERT_NOT_REACHED();
+ return FALSE;
+}
diff --git a/Source/WebCore/platform/graphics/win/QTMovie.h b/Source/WebCore/platform/graphics/win/QTMovie.h
new file mode 100644
index 0000000..5e4c4e7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovie.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 QTMovie_h
+#define QTMovie_h
+
+#include "QTTrack.h"
+#include <WTF/Vector.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTMovie;
+class QTMoviePrivate;
+typedef struct MovieType** Movie;
+typedef Vector<RefPtr<QTTrack>> QTTrackArray;
+
+class QTMovieClient {
+public:
+ virtual void movieEnded(QTMovie*) = 0;
+ virtual void movieLoadStateChanged(QTMovie*) = 0;
+ virtual void movieTimeChanged(QTMovie*) = 0;
+};
+
+enum {
+ QTMovieLoadStateError = -1L,
+ QTMovieLoadStateLoaded = 2000L,
+ QTMovieLoadStatePlayable = 10000L,
+ QTMovieLoadStatePlaythroughOK = 20000L,
+ QTMovieLoadStateComplete = 100000L
+};
+
+typedef const struct __CFURL * CFURLRef;
+
+class QTMOVIEWIN_API QTMovie : public RefCounted<QTMovie> {
+public:
+ static bool initializeQuickTime();
+ static void taskTimerFired();
+
+ static void disableComponent(uint32_t[5]);
+
+ QTMovie(QTMovieClient*);
+ ~QTMovie();
+
+ void addClient(QTMovieClient*);
+ void removeClient(QTMovieClient*);
+
+ void load(const UChar* url, int len, bool preservesPitch);
+ void load(CFURLRef, bool preservesPitch);
+
+ long loadState() const;
+ float maxTimeLoaded() const;
+
+ void play();
+ void pause();
+
+ float rate() const;
+ void setRate(float);
+
+ float duration() const;
+ float currentTime() const;
+ void setCurrentTime(float) const;
+
+ void setVolume(float);
+ void setPreservesPitch(bool);
+
+ unsigned dataSize() const;
+
+ void getNaturalSize(int& width, int& height);
+
+ void disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount);
+
+ bool isDisabled() const;
+ void setDisabled(bool);
+
+ bool hasVideo() const;
+ bool hasAudio() const;
+
+ QTTrackArray videoTracks() const;
+
+ bool hasClosedCaptions() const;
+ void setClosedCaptionsVisible(bool);
+
+ static unsigned countSupportedTypes();
+ static void getSupportedType(unsigned index, const UChar*& str, unsigned& len);
+
+ CGAffineTransform getTransform() const;
+ void setTransform(CGAffineTransform);
+ void resetTransform();
+
+ Movie getMovieHandle() const;
+
+ long timeScale() const;
+
+private:
+ QTMoviePrivate* m_private;
+ friend class QTMoviePrivate;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp b/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp
new file mode 100644
index 0000000..e13f732
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+#include "config.h"
+
+#include "QTMovieGWorld.h"
+
+#include "QTMovieTask.h"
+#include <GXMath.h>
+#include <Movies.h>
+#include <QTML.h>
+#include <QuickTimeComponents.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+static const long minimumQuickTimeVersion = 0x07300000; // 7.3
+
+static LPCTSTR fullscreenQTMovieGWorldPointerProp = TEXT("fullscreenQTMovieGWorldPointer");
+
+// Resizing GWorlds is slow, give them a minimum size so size of small
+// videos can be animated smoothly
+static const int cGWorldMinWidth = 640;
+static const int cGWorldMinHeight = 360;
+
+static const float cNonContinuousTimeChange = 0.2f;
+
+union UppParam {
+ long longValue;
+ void* ptr;
+};
+
+static MovieDrawingCompleteUPP gMovieDrawingCompleteUPP = 0;
+static HashSet<QTMovieGWorldPrivate*>* gTaskList;
+static Vector<CFStringRef>* gSupportedTypes = 0;
+static SInt32 quickTimeVersion = 0;
+
+class QTMovieGWorldPrivate : public QTMovieClient {
+public:
+ QTMovieGWorldPrivate(QTMovieGWorld* movieWin);
+ virtual ~QTMovieGWorldPrivate();
+
+ void registerDrawingCallback();
+ void unregisterDrawingCallback();
+ void drawingComplete();
+ void updateGWorld();
+ void createGWorld();
+ void deleteGWorld();
+ void clearGWorld();
+ void updateMovieSize();
+
+ void setSize(int, int);
+
+ virtual void movieEnded(QTMovie*);
+ virtual void movieLoadStateChanged(QTMovie*);
+ virtual void movieTimeChanged(QTMovie*);
+
+ QTMovieGWorld* m_movieWin;
+ RefPtr<QTMovie> m_qtMovie;
+ Movie m_movie;
+ QTMovieGWorldClient* m_client;
+ long m_loadState;
+ int m_width;
+ int m_height;
+ bool m_visible;
+ GWorldPtr m_gWorld;
+ int m_gWorldWidth;
+ int m_gWorldHeight;
+ GWorldPtr m_savedGWorld;
+ float m_widthScaleFactor;
+ float m_heightScaleFactor;
+#if !ASSERT_DISABLED
+ bool m_scaleCached;
+#endif
+ WindowPtr m_fullscreenWindow;
+ GWorldPtr m_fullscreenOrigGWorld;
+ Rect m_fullscreenRect;
+ QTMovieGWorldFullscreenClient* m_fullscreenClient;
+ char* m_fullscreenRestoreState;
+ bool m_disabled;
+};
+
+QTMovieGWorldPrivate::QTMovieGWorldPrivate(QTMovieGWorld* movieWin)
+ : m_movieWin(movieWin)
+ , m_movie(0)
+ , m_client(0)
+ , m_loadState(0)
+ , m_width(0)
+ , m_height(0)
+ , m_visible(false)
+ , m_gWorld(0)
+ , m_gWorldWidth(0)
+ , m_gWorldHeight(0)
+ , m_savedGWorld(0)
+ , m_widthScaleFactor(1)
+ , m_heightScaleFactor(1)
+#if !ASSERT_DISABLED
+ , m_scaleCached(false)
+#endif
+ , m_fullscreenWindow(0)
+ , m_fullscreenOrigGWorld(0)
+ , m_fullscreenClient(0)
+ , m_fullscreenRestoreState(0)
+ , m_disabled(false)
+ , m_qtMovie(0)
+{
+ Rect rect = { 0, 0, 0, 0 };
+ m_fullscreenRect = rect;
+}
+
+QTMovieGWorldPrivate::~QTMovieGWorldPrivate()
+{
+ ASSERT(!m_fullscreenWindow);
+
+ if (m_gWorld)
+ deleteGWorld();
+}
+
+pascal OSErr movieDrawingCompleteProc(Movie movie, long data)
+{
+ UppParam param;
+ param.longValue = data;
+ QTMovieGWorldPrivate* mp = static_cast<QTMovieGWorldPrivate*>(param.ptr);
+ if (mp)
+ mp->drawingComplete();
+ return 0;
+}
+
+void QTMovieGWorldPrivate::registerDrawingCallback()
+{
+ if (!gMovieDrawingCompleteUPP)
+ gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc);
+
+ UppParam param;
+ param.ptr = this;
+ SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, gMovieDrawingCompleteUPP, param.longValue);
+}
+
+void QTMovieGWorldPrivate::unregisterDrawingCallback()
+{
+ SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, 0, 0);
+}
+
+void QTMovieGWorldPrivate::drawingComplete()
+{
+ if (!m_gWorld || m_movieWin->m_private->m_disabled || m_loadState < QTMovieLoadStateLoaded)
+ return;
+ m_client->movieNewImageAvailable(m_movieWin);
+}
+
+void QTMovieGWorldPrivate::updateGWorld()
+{
+ bool shouldBeVisible = m_visible;
+ if (!m_height || !m_width)
+ shouldBeVisible = false;
+
+ if (shouldBeVisible && !m_gWorld)
+ createGWorld();
+ else if (!shouldBeVisible && m_gWorld)
+ deleteGWorld();
+ else if (m_gWorld && (m_width > m_gWorldWidth || m_height > m_gWorldHeight)) {
+ // need a bigger, better gWorld
+ deleteGWorld();
+ createGWorld();
+ }
+}
+
+void QTMovieGWorldPrivate::createGWorld()
+{
+ ASSERT(!m_gWorld);
+ if (!m_movie || m_loadState < QTMovieLoadStateLoaded)
+ return;
+
+ m_gWorldWidth = max(cGWorldMinWidth, m_width);
+ m_gWorldHeight = max(cGWorldMinHeight, m_height);
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = m_gWorldWidth;
+ bounds.bottom = m_gWorldHeight;
+ OSErr err = QTNewGWorld(&m_gWorld, k32BGRAPixelFormat, &bounds, 0, 0, 0);
+ if (err)
+ return;
+ GetMovieGWorld(m_movie, &m_savedGWorld, 0);
+ SetMovieGWorld(m_movie, m_gWorld, 0);
+ bounds.right = m_width;
+ bounds.bottom = m_height;
+ SetMovieBox(m_movie, &bounds);
+}
+
+void QTMovieGWorldPrivate::clearGWorld()
+{
+ if (!m_movie || !m_gWorld)
+ return;
+
+ GrafPtr savePort;
+ GetPort(&savePort);
+ MacSetPort((GrafPtr)m_gWorld);
+
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = m_gWorldWidth;
+ bounds.bottom = m_gWorldHeight;
+ EraseRect(&bounds);
+
+ MacSetPort(savePort);
+}
+
+void QTMovieGWorldPrivate::setSize(int width, int height)
+{
+ if (m_width == width && m_height == height)
+ return;
+ m_width = width;
+ m_height = height;
+
+ // Do not change movie box before reaching load state loaded as we grab
+ // the initial size when task() sees that state for the first time, and
+ // we need the initial size to be able to scale movie properly.
+ if (!m_movie || m_loadState < QTMovieLoadStateLoaded)
+ return;
+
+#if !ASSERT_DISABLED
+ ASSERT(m_scaleCached);
+#endif
+
+ updateMovieSize();
+}
+
+void QTMovieGWorldPrivate::updateMovieSize()
+{
+ if (!m_movie || m_loadState < QTMovieLoadStateLoaded)
+ return;
+
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = m_width;
+ bounds.bottom = m_height;
+ SetMovieBox(m_movie, &bounds);
+ updateGWorld();
+}
+
+
+void QTMovieGWorldPrivate::deleteGWorld()
+{
+ ASSERT(m_gWorld);
+ if (m_movie)
+ SetMovieGWorld(m_movie, m_savedGWorld, 0);
+ m_savedGWorld = 0;
+ DisposeGWorld(m_gWorld);
+ m_gWorld = 0;
+ m_gWorldWidth = 0;
+ m_gWorldHeight = 0;
+}
+
+void QTMovieGWorldPrivate::movieEnded(QTMovie*)
+{
+ // Do nothing
+}
+
+void QTMovieGWorldPrivate::movieLoadStateChanged(QTMovie* movie)
+{
+ long loadState = GetMovieLoadState(movie->getMovieHandle());
+ if (loadState != m_loadState) {
+
+ // we only need to erase the movie gworld when the load state changes to loaded while it
+ // is visible as the gworld is destroyed/created when visibility changes
+ bool movieNewlyPlayable = loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded;
+ m_loadState = loadState;
+
+ if (movieNewlyPlayable) {
+ updateMovieSize();
+ if (m_visible)
+ clearGWorld();
+ }
+ }
+}
+
+void QTMovieGWorldPrivate::movieTimeChanged(QTMovie*)
+{
+ // Do nothing
+}
+
+QTMovieGWorld::QTMovieGWorld(QTMovieGWorldClient* client)
+ : m_private(new QTMovieGWorldPrivate(this))
+{
+ m_private->m_client = client;
+}
+
+QTMovieGWorld::~QTMovieGWorld()
+{
+ delete m_private;
+}
+
+void QTMovieGWorld::setSize(int width, int height)
+{
+ m_private->setSize(width, height);
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMovieGWorld::setVisible(bool b)
+{
+ m_private->m_visible = b;
+ m_private->updateGWorld();
+}
+
+void QTMovieGWorld::getCurrentFrameInfo(void*& buffer, unsigned& bitsPerPixel, unsigned& rowBytes, unsigned& width, unsigned& height)
+{
+ if (!m_private->m_gWorld) {
+ buffer = 0;
+ bitsPerPixel = 0;
+ rowBytes = 0;
+ width = 0;
+ height = 0;
+ return;
+ }
+ PixMapHandle offscreenPixMap = GetGWorldPixMap(m_private->m_gWorld);
+ buffer = (*offscreenPixMap)->baseAddr;
+ bitsPerPixel = (*offscreenPixMap)->pixelSize;
+ rowBytes = (*offscreenPixMap)->rowBytes & 0x3FFF;
+ width = m_private->m_width;
+ height = m_private->m_height;
+}
+
+void QTMovieGWorld::paint(HDC hdc, int x, int y)
+{
+ if (!m_private->m_gWorld)
+ return;
+
+ HDC hdcSrc = static_cast<HDC>(GetPortHDC(reinterpret_cast<GrafPtr>(m_private->m_gWorld)));
+ if (!hdcSrc)
+ return;
+
+ // FIXME: If we could determine the movie has no alpha, we could use BitBlt for those cases, which might be faster.
+ BLENDFUNCTION blendFunction;
+ blendFunction.BlendOp = AC_SRC_OVER;
+ blendFunction.BlendFlags = 0;
+ blendFunction.SourceConstantAlpha = 255;
+ blendFunction.AlphaFormat = AC_SRC_ALPHA;
+ AlphaBlend(hdc, x, y, m_private->m_width, m_private->m_height, hdcSrc,
+ 0, 0, m_private->m_width, m_private->m_height, blendFunction);
+}
+
+void QTMovieGWorld::setDisabled(bool b)
+{
+ m_private->m_disabled = b;
+}
+
+bool QTMovieGWorld::isDisabled() const
+{
+ return m_private->m_disabled;
+}
+
+LRESULT QTMovieGWorld::fullscreenWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ QTMovieGWorld* movie = static_cast<QTMovieGWorld*>(GetProp(wnd, fullscreenQTMovieGWorldPointerProp));
+
+ if (message == WM_DESTROY)
+ RemoveProp(wnd, fullscreenQTMovieGWorldPointerProp);
+
+ if (!movie)
+ return DefWindowProc(wnd, message, wParam, lParam);
+
+ return movie->m_private->m_fullscreenClient->fullscreenClientWndProc(wnd, message, wParam, lParam);
+}
+
+HWND QTMovieGWorld::enterFullscreen(QTMovieGWorldFullscreenClient* client)
+{
+ m_private->m_fullscreenClient = client;
+
+ BeginFullScreen(&m_private->m_fullscreenRestoreState, 0, 0, 0, &m_private->m_fullscreenWindow, 0, fullScreenAllowEvents);
+ QTMLSetWindowWndProc(m_private->m_fullscreenWindow, fullscreenWndProc);
+ CreatePortAssociation(GetPortNativeWindow(m_private->m_fullscreenWindow), 0, 0);
+
+ GetMovieBox(m_private->m_movie, &m_private->m_fullscreenRect);
+ GetMovieGWorld(m_private->m_movie, &m_private->m_fullscreenOrigGWorld, 0);
+ SetMovieGWorld(m_private->m_movie, reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow), GetGWorldDevice(reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow)));
+
+ // Set the size of the box to preserve aspect ratio
+ Rect rect = m_private->m_fullscreenWindow->portRect;
+
+ float movieRatio = static_cast<float>(m_private->m_width) / m_private->m_height;
+ int windowWidth = rect.right - rect.left;
+ int windowHeight = rect.bottom - rect.top;
+ float windowRatio = static_cast<float>(windowWidth) / windowHeight;
+ int actualWidth = (windowRatio > movieRatio) ? (windowHeight * movieRatio) : windowWidth;
+ int actualHeight = (windowRatio < movieRatio) ? (windowWidth / movieRatio) : windowHeight;
+ int offsetX = (windowWidth - actualWidth) / 2;
+ int offsetY = (windowHeight - actualHeight) / 2;
+
+ rect.left = offsetX;
+ rect.right = offsetX + actualWidth;
+ rect.top = offsetY;
+ rect.bottom = offsetY + actualHeight;
+
+ SetMovieBox(m_private->m_movie, &rect);
+ ShowHideTaskBar(true);
+
+ // Set the 'this' pointer on the HWND
+ HWND wnd = static_cast<HWND>(GetPortNativeWindow(m_private->m_fullscreenWindow));
+ SetProp(wnd, fullscreenQTMovieGWorldPointerProp, static_cast<HANDLE>(this));
+
+ return wnd;
+}
+
+void QTMovieGWorld::exitFullscreen()
+{
+ if (!m_private->m_fullscreenWindow)
+ return;
+
+ HWND wnd = static_cast<HWND>(GetPortNativeWindow(m_private->m_fullscreenWindow));
+ DestroyPortAssociation(reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow));
+ SetMovieGWorld(m_private->m_movie, m_private->m_fullscreenOrigGWorld, 0);
+ EndFullScreen(m_private->m_fullscreenRestoreState, 0L);
+ SetMovieBox(m_private->m_movie, &m_private->m_fullscreenRect);
+ m_private->m_fullscreenWindow = 0;
+}
+
+void QTMovieGWorld::setMovie(PassRefPtr<QTMovie> movie)
+{
+ if (m_private->m_qtMovie) {
+ m_private->unregisterDrawingCallback();
+ m_private->m_qtMovie->removeClient(m_private);
+ m_private->m_qtMovie = 0;
+ m_private->m_movie = 0;
+ }
+
+ m_private->m_qtMovie = movie;
+
+ if (m_private->m_qtMovie) {
+ m_private->m_qtMovie->addClient(m_private);
+ m_private->m_movie = m_private->m_qtMovie->getMovieHandle();
+ m_private->registerDrawingCallback();
+ }
+}
+
+QTMovie* QTMovieGWorld::movie() const
+{
+ return m_private->m_qtMovie.get();
+}
diff --git a/Source/WebCore/platform/graphics/win/QTMovieGWorld.h b/Source/WebCore/platform/graphics/win/QTMovieGWorld.h
new file mode 100644
index 0000000..495fe25
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieGWorld.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 QTMovieGWorld_h
+#define QTMovieGWorld_h
+
+
+#include "QTMovie.h"
+#include <Unicode.h>
+#include <WTF/RefCounted.h>
+#include <WTF/RefPtr.h>
+#include <windows.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTMovieGWorld;
+class QTMovieGWorldPrivate;
+
+class QTMovieGWorldClient {
+public:
+ virtual void movieNewImageAvailable(QTMovieGWorld*) = 0;
+};
+
+class QTMovieGWorldFullscreenClient {
+public:
+ virtual LRESULT fullscreenClientWndProc(HWND, UINT message, WPARAM, LPARAM) = 0;
+};
+
+class QTMOVIEWIN_API QTMovieGWorld : public RefCounted<QTMovieGWorld> {
+public:
+ QTMovieGWorld(QTMovieGWorldClient*);
+ ~QTMovieGWorld();
+
+ void getNaturalSize(int& width, int& height);
+ void setSize(int width, int height);
+
+ void setVisible(bool);
+ void paint(HDC, int x, int y);
+ void getCurrentFrameInfo(void*& buffer, unsigned& bitsPerPixel, unsigned& rowBytes, unsigned& width, unsigned& height);
+
+ void setDisabled(bool);
+ bool isDisabled() const;
+
+ // Returns the full-screen window created
+ HWND enterFullscreen(QTMovieGWorldFullscreenClient*);
+ void exitFullscreen();
+
+ void setMovie(PassRefPtr<QTMovie>);
+ QTMovie* movie() const;
+
+private:
+ static LRESULT fullscreenWndProc(HWND, UINT message, WPARAM, LPARAM);
+
+ QTMovieGWorldPrivate* m_private;
+ friend class QTMovieGWorldPrivate;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovieTask.cpp b/Source/WebCore/platform/graphics/win/QTMovieTask.cpp
new file mode 100644
index 0000000..8713588
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieTask.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+#include "config.h"
+
+#include "QTMovieTask.h"
+
+// Put Movies.h first so build failures here point clearly to QuickTime
+#include <Movies.h>
+
+#include <wtf/HashSet.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+QTMovieTask::QTMovieTask()
+ : m_setTaskTimerDelay(0)
+ , m_stopTaskTimer(0)
+{
+}
+
+QTMovieTask::~QTMovieTask()
+{
+}
+
+QTMovieTask* QTMovieTask::sharedTask()
+{
+ static QTMovieTask* s_sharedTask = new QTMovieTask;
+ return s_sharedTask;
+}
+
+void QTMovieTask::updateTaskTimer(double maxInterval, double minInterval)
+{
+ ASSERT(m_setTaskTimerDelay);
+ if (!m_setTaskTimerDelay)
+ return;
+
+ ASSERT(m_stopTaskTimer);
+ if (!m_taskList.size() && m_stopTaskTimer) {
+ m_stopTaskTimer();
+ return;
+ }
+
+ long intervalInMS;
+ OSStatus status = QTGetTimeUntilNextTask(&intervalInMS, 1000);
+ double interval = intervalInMS / 1000.0;
+ if (interval < minInterval)
+ interval = minInterval;
+ if (interval > maxInterval)
+ interval = maxInterval;
+ m_setTaskTimerDelay(interval);
+}
+
+void QTMovieTask::fireTaskClients()
+{
+ Vector<QTMovieTaskClient*> clients;
+ copyToVector(m_taskList, clients);
+ for (Vector<QTMovieTaskClient*>::iterator i = clients.begin(); i != clients.end(); ++i)
+ (*i)->task();
+}
+
+void QTMovieTask::addTaskClient(QTMovieTaskClient* client)
+{
+ ASSERT(client);
+ if (!client)
+ return;
+
+ m_taskList.add(client);
+}
+
+void QTMovieTask::removeTaskClient(QTMovieTaskClient* client)
+{
+ ASSERT(client);
+ if (!client)
+ return;
+
+ m_taskList.remove(client);
+}
+
+void QTMovieTask::setTaskTimerFuncs(SetTaskTimerDelayFunc setTaskTimerDelay, StopTaskTimerFunc stopTaskTimer)
+{
+ m_setTaskTimerDelay = setTaskTimerDelay;
+ m_stopTaskTimer = stopTaskTimer;
+}
+
diff --git a/Source/WebCore/platform/graphics/win/QTMovieTask.h b/Source/WebCore/platform/graphics/win/QTMovieTask.h
new file mode 100644
index 0000000..e394d6e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieTask.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 QTMovieTask_h
+#define QTMovieTask_h
+
+#include <WTF/HashSet.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTMovieTaskClient {
+public:
+ virtual void task() = 0;
+};
+
+typedef void (*SetTaskTimerDelayFunc)(double);
+typedef void (*StopTaskTimerFunc)();
+
+class QTMOVIEWIN_API QTMovieTask {
+public:
+ static QTMovieTask* sharedTask();
+
+ void addTaskClient(QTMovieTaskClient* client);
+ void removeTaskClient(QTMovieTaskClient*);
+ void fireTaskClients();
+
+ void updateTaskTimer(double maxInterval = 1.0, double minInterval = 1.0 / 30);
+ void setTaskTimerFuncs(SetTaskTimerDelayFunc setTaskTimerDelay, StopTaskTimerFunc stopTaskTimer);
+
+protected:
+ QTMovieTask();
+ ~QTMovieTask();
+
+ SetTaskTimerDelayFunc m_setTaskTimerDelay;
+ StopTaskTimerFunc m_stopTaskTimer;
+ HashSet<QTMovieTaskClient*> m_taskList;
+
+private:
+ QTMovieTask(const QTMovieTask&);
+ QTMovieTask& operator=(const QTMovieTask&);
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovieVisualContext.cpp b/Source/WebCore/platform/graphics/win/QTMovieVisualContext.cpp
new file mode 100644
index 0000000..0fcc7e2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieVisualContext.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+#include "config.h"
+
+#include "QTMovieVisualContext.h"
+
+#include "QTMovieTask.h"
+#include <CVBase.h>
+#include <CVHostTime.h>
+#include <ImageCompression.h>
+#include <Movies.h>
+#include <windows.h>
+
+struct QTCVTimeStamp {
+ CVTimeStamp t;
+};
+
+class QTMovieVisualContextPriv {
+public:
+ QTMovieVisualContextPriv(QTMovieVisualContext* parent, QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType);
+ ~QTMovieVisualContextPriv();
+
+ bool isImageAvailableForTime(const QTCVTimeStamp*) const;
+ QTPixelBuffer imageForTime(const QTCVTimeStamp*);
+ void task();
+
+ QTVisualContextRef visualContextRef();
+
+ void setMovie(PassRefPtr<QTMovie>);
+ QTMovie* movie() const;
+
+ static void imageAvailableCallback(QTVisualContextRef visualContext, const CVTimeStamp *timeStamp, void *refCon);
+
+private:
+ QTMovieVisualContext* m_parent;
+ QTMovieVisualContextClient* m_client;
+ QTVisualContextRef m_visualContext;
+ RefPtr<QTMovie> m_movie;
+
+};
+
+static CFDictionaryRef createPixelBufferOptionsDictionary(QTPixelBuffer::Type contextType)
+{
+ const void* key = kQTVisualContextPixelBufferAttributesKey;
+ const void* value = QTPixelBuffer::createPixelBufferAttributesDictionary(contextType);
+ CFDictionaryRef pixelBufferOptions = CFDictionaryCreate(kCFAllocatorDefault, &key, &value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFRelease(value);
+ return pixelBufferOptions;
+}
+
+static CFDictionaryRef pixelBufferCreationOptions(QTPixelBuffer::Type contextType)
+{
+ if (contextType == QTPixelBuffer::ConfigureForCAImageQueue) {
+ static CFDictionaryRef imageQueueOptions = createPixelBufferOptionsDictionary(contextType);
+ return imageQueueOptions;
+ }
+
+ ASSERT(contextType == QTPixelBuffer::ConfigureForCGImage);
+ static CFDictionaryRef cgImageOptions = createPixelBufferOptionsDictionary(contextType);
+ return cgImageOptions;
+}
+
+QTMovieVisualContextPriv::QTMovieVisualContextPriv(QTMovieVisualContext* parent, QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType)
+ : m_parent(parent)
+ , m_client(client)
+ , m_visualContext(0)
+{
+ typedef OSStatus ( __cdecl *pfnQTPixelBufferContextCreate)(CFAllocatorRef, CFDictionaryRef, QTVisualContextRef*);
+ static pfnQTPixelBufferContextCreate pPixelBufferContextCreate = 0;
+ if (!pPixelBufferContextCreate) {
+ HMODULE qtmlDLL = ::LoadLibraryW(L"QTMLClient.dll");
+ if (!qtmlDLL)
+ return;
+ pPixelBufferContextCreate = reinterpret_cast<pfnQTPixelBufferContextCreate>(GetProcAddress(qtmlDLL, "QTPixelBufferContextCreate"));
+ if (!pPixelBufferContextCreate)
+ return;
+ }
+
+ OSStatus status = pPixelBufferContextCreate(kCFAllocatorDefault, pixelBufferCreationOptions(contextType), &m_visualContext);
+ if (status == noErr && m_visualContext)
+ QTVisualContextSetImageAvailableCallback(m_visualContext, &QTMovieVisualContextPriv::imageAvailableCallback, static_cast<void*>(this));
+}
+
+QTMovieVisualContextPriv::~QTMovieVisualContextPriv()
+{
+ if (m_visualContext)
+ QTVisualContextSetImageAvailableCallback(m_visualContext, 0, 0);
+}
+
+bool QTMovieVisualContextPriv::isImageAvailableForTime(const QTCVTimeStamp* timeStamp) const
+{
+ if (!m_visualContext)
+ return false;
+
+ return QTVisualContextIsNewImageAvailable(m_visualContext, reinterpret_cast<const CVTimeStamp*>(timeStamp));
+}
+
+QTPixelBuffer QTMovieVisualContextPriv::imageForTime(const QTCVTimeStamp* timeStamp)
+{
+ QTPixelBuffer pixelBuffer;
+ if (m_visualContext) {
+ CVImageBufferRef newImage = 0;
+ OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, kCFAllocatorDefault, reinterpret_cast<const CVTimeStamp*>(timeStamp), &newImage);
+ if (status == noErr)
+ pixelBuffer.adopt(newImage);
+ }
+ return pixelBuffer;
+}
+
+void QTMovieVisualContextPriv::task()
+{
+ if (m_visualContext)
+ QTVisualContextTask(m_visualContext);
+}
+
+QTVisualContextRef QTMovieVisualContextPriv::visualContextRef()
+{
+ return m_visualContext;
+}
+
+void QTMovieVisualContextPriv::setMovie(PassRefPtr<QTMovie> movie)
+{
+ if (movie == m_movie)
+ return;
+
+ if (m_movie) {
+ SetMovieVisualContext(m_movie->getMovieHandle(), 0);
+ m_movie = 0;
+ }
+
+ if (movie)
+ OSStatus status = SetMovieVisualContext(movie->getMovieHandle(), m_visualContext);
+
+ m_movie = movie;
+}
+
+QTMovie* QTMovieVisualContextPriv::movie() const
+{
+ return m_movie.get();
+}
+
+void QTMovieVisualContextPriv::imageAvailableCallback(QTVisualContextRef visualContext, const CVTimeStamp *timeStamp, void *refCon)
+{
+ if (!refCon)
+ return;
+
+ QTMovieVisualContextPriv* vc = static_cast<QTMovieVisualContextPriv*>(refCon);
+ if (!vc->m_client)
+ return;
+
+ vc->m_client->imageAvailableForTime(reinterpret_cast<const QTCVTimeStamp*>(timeStamp));
+}
+
+PassRefPtr<QTMovieVisualContext> QTMovieVisualContext::create(QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType)
+{
+ return adoptRef(new QTMovieVisualContext(client, contextType));
+}
+
+QTMovieVisualContext::QTMovieVisualContext(QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType)
+ : m_private(new QTMovieVisualContextPriv(this, client, contextType))
+{
+}
+
+QTMovieVisualContext::~QTMovieVisualContext()
+{
+}
+
+bool QTMovieVisualContext::isImageAvailableForTime(const QTCVTimeStamp* timeStamp) const
+{
+ return m_private->isImageAvailableForTime(timeStamp);
+}
+
+QTPixelBuffer QTMovieVisualContext::imageForTime(const QTCVTimeStamp* timeStamp)
+{
+ return m_private->imageForTime(timeStamp);
+}
+
+void QTMovieVisualContext::task()
+{
+ m_private->task();
+}
+
+QTVisualContextRef QTMovieVisualContext::visualContextRef()
+{
+ return m_private->visualContextRef();
+}
+
+void QTMovieVisualContext::setMovie(PassRefPtr<QTMovie> movie)
+{
+ m_private->setMovie(movie);
+}
+
+QTMovie* QTMovieVisualContext::movie() const
+{
+ return m_private->movie();
+}
+
+double QTMovieVisualContext::currentHostTime()
+{
+ return CVGetCurrentHostTime() / CVGetHostClockFrequency();
+}
diff --git a/Source/WebCore/platform/graphics/win/QTMovieVisualContext.h b/Source/WebCore/platform/graphics/win/QTMovieVisualContext.h
new file mode 100644
index 0000000..8410208
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieVisualContext.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 QTMovieVisualContext_h
+#define QTMovieVisualContext_h
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+#include "QTMovie.h"
+#include "QTMovieTask.h"
+#include "QTPixelBuffer.h"
+#include <WTF/OwnPtr.h>
+#include <WTF/RefCounted.h>
+
+typedef const struct __CFDictionary* CFDictionaryRef;
+typedef struct OpaqueQTVisualContext* QTVisualContextRef;
+
+// QTCVTimeStamp is a struct containing only a CVTimeStamp. This is to
+// work around the inability of CVTimeStamp to be forward declared, in
+// addition to it being declared in different header files when building
+// the QTMovieWin and WebCore projects.
+struct QTCVTimeStamp;
+
+class QTMovieVisualContextClient {
+public:
+ virtual void imageAvailableForTime(const QTCVTimeStamp*) = 0;
+};
+
+class QTMOVIEWIN_API QTMovieVisualContext : public RefCounted<QTMovieVisualContext> {
+public:
+ static PassRefPtr<QTMovieVisualContext> create(QTMovieVisualContextClient*, QTPixelBuffer::Type);
+ ~QTMovieVisualContext();
+
+ bool isImageAvailableForTime(const QTCVTimeStamp*) const;
+ QTPixelBuffer imageForTime(const QTCVTimeStamp*);
+ void task();
+
+ QTVisualContextRef visualContextRef();
+
+ void setMovie(PassRefPtr<QTMovie>);
+ QTMovie* movie() const;
+
+ static double currentHostTime();
+
+protected:
+ QTMovieVisualContext(QTMovieVisualContextClient*, QTPixelBuffer::Type);
+ void setupVisualContext();
+
+ friend class QTMovieVisualContextPriv;
+ OwnPtr<QTMovieVisualContextPriv> m_private;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovieWinTimer.cpp b/Source/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
new file mode 100644
index 0000000..f6103ea
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+#include "config.h"
+
+#include <windows.h>
+
+#include "QTMovieWinTimer.h"
+
+#include <wtf/Assertions.h>
+
+// This file is used by the QuickTime access DLL. It copies some WebCore code
+// which can't be used directly due to dependency issues.
+
+// FIXME: Find a way to do timers that can manage <10ms resolution properly too.
+
+static UINT_PTR timerID;
+static void (*sharedTimerFiredFunction)();
+
+static HINSTANCE instanceHandle = 0;
+
+static HWND timerWindowHandle = 0;
+static UINT timerFiredMessage = 0;
+static const LPCWSTR kTimerWindowClassName = L"TimerWindowClass";
+static bool processingCustomTimerMessage = false;
+
+static LRESULT CALLBACK TimerWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == timerFiredMessage) {
+ processingCustomTimerMessage = true;
+ sharedTimerFiredFunction();
+ processingCustomTimerMessage = false;
+ } else if (message == WM_TIMER && wParam == timerID) {
+ stopSharedTimer();
+ sharedTimerFiredFunction();
+ } else
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ return 0;
+}
+
+static void initializeOffScreenTimerWindow()
+{
+ if (timerWindowHandle)
+ return;
+
+ WNDCLASSEX wcex;
+ memset(&wcex, 0, sizeof(WNDCLASSEX));
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = TimerWindowWndProc;
+ wcex.hInstance = instanceHandle;
+ wcex.lpszClassName = kTimerWindowClassName;
+ RegisterClassEx(&wcex);
+
+ timerWindowHandle = CreateWindow(kTimerWindowClassName, 0, 0,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, instanceHandle, 0);
+ timerFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.TimerFired");
+}
+
+void setSharedTimerFiredFunction(void (*f)())
+{
+ sharedTimerFiredFunction = f;
+}
+
+void setSharedTimerFireDelay(double interval)
+{
+ ASSERT(sharedTimerFiredFunction);
+
+ unsigned intervalInMS;
+ if (interval < 0)
+ intervalInMS = 0;
+ else {
+ interval *= 1000;
+ if (interval > USER_TIMER_MAXIMUM)
+ intervalInMS = USER_TIMER_MAXIMUM;
+ else
+ intervalInMS = (unsigned)interval;
+ }
+
+ stopSharedTimer();
+ initializeOffScreenTimerWindow();
+
+ // We don't allow nested PostMessages, since the custom messages will effectively starve
+ // painting and user input. (Win32 has a tri-level queue with application messages >
+ // user input > WM_PAINT/WM_TIMER.)
+ // In addition, if the queue contains input events that have been there since the last call to
+ // GetQueueStatus, PeekMessage or GetMessage we favor timers.
+ if (intervalInMS < USER_TIMER_MINIMUM
+ && !processingCustomTimerMessage
+ && !LOWORD(::GetQueueStatus(QS_ALLINPUT))) {
+ // Windows SetTimer does not allow timeouts smaller than 10ms (USER_TIMER_MINIMUM)
+ PostMessage(timerWindowHandle, timerFiredMessage, 0, 0);
+ } else
+ timerID = SetTimer(timerWindowHandle, timerFiredMessage, intervalInMS, 0);
+}
+
+void stopSharedTimer()
+{
+ if (timerID) {
+ KillTimer(timerWindowHandle, timerID);
+ timerID = 0;
+ }
+}
+
+void setSharedTimerInstanceHandle(HINSTANCE handle)
+{
+ instanceHandle = handle;
+}
+
+double systemTime()
+{
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ ULARGE_INTEGER t;
+ memcpy(&t, &ft, sizeof(t));
+ return t.QuadPart * 0.0000001 - 11644473600.0;
+}
diff --git a/Source/WebCore/platform/graphics/win/QTMovieWinTimer.h b/Source/WebCore/platform/graphics/win/QTMovieWinTimer.h
new file mode 100644
index 0000000..976b310
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieWinTimer.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 QTMovieWinTimer_h
+#define QTMovieWinTimer_h
+
+// This header should not be included from WebCore.
+// It is used by the QuickTime access DLL. It copies some WebCore code
+// which can't be used directly due to dependency issues.
+
+void setSharedTimerFiredFunction(void (*)());
+void setSharedTimerFireDelay(double delay);
+void stopSharedTimer();
+void setSharedTimerInstanceHandle(HINSTANCE handle);
+double systemTime();
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTPixelBuffer.cpp b/Source/WebCore/platform/graphics/win/QTPixelBuffer.cpp
new file mode 100644
index 0000000..44a1b0e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTPixelBuffer.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+#include "config.h"
+
+#include "QTPixelBuffer.h"
+
+#include <CFNumber.h>
+#include <CFString.h>
+#include <CGColorSpace.h>
+#include <CGImage.h>
+#include <CVPixelBuffer.h>
+#include <QuickDraw.h>
+#include <memory.h>
+
+static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, CFStringRef inKey, SInt32 inValue)
+{
+ CFNumberRef number;
+
+ number = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue);
+ if (!number)
+ return coreFoundationUnknownErr;
+
+ CFDictionarySetValue(inDict, inKey, number);
+ CFRelease(number);
+
+ return noErr;
+}
+
+CFDictionaryRef QTPixelBuffer::createPixelBufferAttributesDictionary(QTPixelBuffer::Type contextType)
+{
+ static const CFStringRef kDirect3DCompatibilityKey = CFSTR("Direct3DCompatibility");
+
+ CFMutableDictionaryRef pixelBufferAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (contextType == QTPixelBuffer::ConfigureForCAImageQueue) {
+ // Ask for D3D compatible pixel buffers so no further work is needed.
+ CFDictionarySetValue(pixelBufferAttributes, kDirect3DCompatibilityKey, kCFBooleanTrue);
+ } else {
+ // Use the k32BGRAPixelFormat, as QuartzCore will be able to use the pixels directly,
+ // without needing an additional copy or rendering pass.
+ SetNumberValue(pixelBufferAttributes, kCVPixelBufferPixelFormatTypeKey, k32BGRAPixelFormat);
+
+ // Set kCVPixelBufferBytesPerRowAlignmentKey to 16 to ensure that each row of pixels
+ // starts at a 16 byte aligned address for most efficient data reading.
+ SetNumberValue(pixelBufferAttributes, kCVPixelBufferBytesPerRowAlignmentKey, 16);
+ CFDictionarySetValue(pixelBufferAttributes, kCVPixelBufferCGImageCompatibilityKey, kCFBooleanTrue);
+ }
+ return pixelBufferAttributes;
+}
+
+QTPixelBuffer::QTPixelBuffer()
+ : m_pixelBuffer(0)
+{
+}
+
+QTPixelBuffer::QTPixelBuffer(const QTPixelBuffer& p)
+ : m_pixelBuffer(p.m_pixelBuffer)
+{
+ CVPixelBufferRetain(m_pixelBuffer);
+}
+
+QTPixelBuffer::QTPixelBuffer(CVPixelBufferRef ref)
+ : m_pixelBuffer(ref)
+{
+ CVPixelBufferRetain(m_pixelBuffer);
+}
+
+QTPixelBuffer::~QTPixelBuffer()
+{
+ clear();
+}
+
+QTPixelBuffer& QTPixelBuffer::operator=(const QTPixelBuffer& p)
+{
+ set(p.m_pixelBuffer);
+ return *this;
+}
+
+void QTPixelBuffer::set(CVPixelBufferRef ref)
+{
+ CVPixelBufferRetain(ref);
+ CVPixelBufferRelease(m_pixelBuffer);
+ m_pixelBuffer = ref;
+}
+
+CVPixelBufferRef QTPixelBuffer::pixelBufferRef()
+{
+ return m_pixelBuffer;
+}
+
+void QTPixelBuffer::adopt(CVPixelBufferRef ref)
+{
+ if (ref == m_pixelBuffer)
+ return;
+ CVPixelBufferRelease(m_pixelBuffer);
+ m_pixelBuffer = ref;
+}
+
+void QTPixelBuffer::clear()
+{
+ CVPixelBufferRelease(m_pixelBuffer);
+ m_pixelBuffer = 0;
+}
+
+CVReturn QTPixelBuffer::lockBaseAddress()
+{
+ return CVPixelBufferLockBaseAddress(m_pixelBuffer, 0);
+}
+
+CVReturn QTPixelBuffer::unlockBaseAddress()
+{
+ return CVPixelBufferUnlockBaseAddress(m_pixelBuffer, 0);
+}
+
+void* QTPixelBuffer::baseAddress()
+{
+ return CVPixelBufferGetBaseAddress(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::width() const
+{
+ return CVPixelBufferGetWidth(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::height() const
+{
+ return CVPixelBufferGetHeight(m_pixelBuffer);
+}
+
+unsigned long QTPixelBuffer::pixelFormatType() const
+{
+ return CVPixelBufferGetPixelFormatType(m_pixelBuffer);
+}
+
+bool QTPixelBuffer::pixelFormatIs32ARGB() const
+{
+ return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32ARGBPixelFormat;
+}
+
+bool QTPixelBuffer::pixelFormatIs32BGRA() const
+{
+ return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32BGRAPixelFormat;
+}
+
+size_t QTPixelBuffer::bytesPerRow() const
+{
+ return CVPixelBufferGetBytesPerRow(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::dataSize() const
+{
+ return CVPixelBufferGetDataSize(m_pixelBuffer);
+}
+
+bool QTPixelBuffer::isPlanar() const
+{
+ return CVPixelBufferIsPlanar(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::planeCount() const
+{
+ return CVPixelBufferGetPlaneCount(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::widthOfPlane(size_t plane) const
+{
+ return CVPixelBufferGetWidthOfPlane(m_pixelBuffer, plane);
+}
+
+size_t QTPixelBuffer::heightOfPlane(size_t plane) const
+{
+ return CVPixelBufferGetHeightOfPlane(m_pixelBuffer, plane);
+}
+
+void* QTPixelBuffer::baseAddressOfPlane(size_t plane) const
+{
+ return CVPixelBufferGetBaseAddressOfPlane(m_pixelBuffer, plane);
+}
+
+size_t QTPixelBuffer::bytesPerRowOfPlane(size_t plane) const
+{
+ return CVPixelBufferGetBytesPerRowOfPlane(m_pixelBuffer, plane);
+}
+
+void QTPixelBuffer::getExtendedPixels(size_t* left, size_t* right, size_t* top, size_t* bottom) const
+{
+ return CVPixelBufferGetExtendedPixels(m_pixelBuffer, left, right, top, bottom);
+}
+
+CFDictionaryRef QTPixelBuffer::attachments() const
+{
+ return CVBufferGetAttachments(m_pixelBuffer, kCVAttachmentMode_ShouldPropagate);
+}
+
+void QTPixelBuffer::retainCallback(void* refcon)
+{
+ CVPixelBufferRetain(static_cast<CVPixelBufferRef>(refcon));
+}
+
+void QTPixelBuffer::releaseCallback(void* refcon)
+{
+ CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
+}
+
+void QTPixelBuffer::imageQueueReleaseCallback(unsigned int type, uint64_t id, void* refcon)
+{
+ CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
+}
+
+void QTPixelBuffer::dataProviderReleaseBytePointerCallback(void* refcon, const void* pointer)
+{
+ CVPixelBufferUnlockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0);
+}
+
+const void* QTPixelBuffer::dataProviderGetBytePointerCallback(void* refcon)
+{
+ CVPixelBufferLockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0);
+ return CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon));
+}
+
+size_t QTPixelBuffer::dataProviderGetBytesAtPositionCallback(void* refcon, void* buffer, size_t position, size_t count)
+{
+ char* data = (char*)CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon));
+ size_t size = CVPixelBufferGetDataSize(static_cast<CVPixelBufferRef>(refcon));
+ if (size - position < count)
+ count = size - position;
+
+ memcpy(buffer, data+position, count);
+ return count;
+}
+
+void QTPixelBuffer::dataProviderReleaseInfoCallback(void* refcon)
+{
+ CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
+}
diff --git a/Source/WebCore/platform/graphics/win/QTPixelBuffer.h b/Source/WebCore/platform/graphics/win/QTPixelBuffer.h
new file mode 100644
index 0000000..13630da
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTPixelBuffer.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 QTPixelBuffer_h
+#define QTPixelBuffer_h
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+#include <stdint.h>
+
+typedef struct __CVBuffer *CVBufferRef;
+typedef CVBufferRef CVPixelBufferRef;
+typedef struct CGImage* CGImageRef;
+typedef int32_t CVReturn;
+typedef const struct __CFDictionary * CFDictionaryRef;
+
+// QTPixelBuffer wraps QuickTime's implementation of CVPixelBuffer, so its functions are
+// safe to call within WebKit.
+class QTMOVIEWIN_API QTPixelBuffer {
+public:
+ enum Type { ConfigureForCGImage, ConfigureForCAImageQueue };
+ static CFDictionaryRef createPixelBufferAttributesDictionary(Type);
+
+ QTPixelBuffer();
+ QTPixelBuffer(const QTPixelBuffer&);
+ QTPixelBuffer(CVPixelBufferRef);
+ QTPixelBuffer& operator=(const QTPixelBuffer&);
+ ~QTPixelBuffer();
+
+ void set(CVPixelBufferRef);
+ CVPixelBufferRef pixelBufferRef();
+ void adopt(CVPixelBufferRef);
+ void clear();
+
+ CVReturn lockBaseAddress();
+ CVReturn unlockBaseAddress();
+ void* baseAddress();
+
+ size_t width() const;
+ size_t height() const;
+ unsigned long pixelFormatType() const;
+ bool pixelFormatIs32ARGB() const;
+ bool pixelFormatIs32BGRA() const;
+ size_t bytesPerRow() const;
+ size_t dataSize() const;
+
+ bool isPlanar() const;
+ size_t planeCount() const;
+ size_t widthOfPlane(size_t) const;
+ size_t heightOfPlane(size_t) const;
+ void* baseAddressOfPlane(size_t) const;
+ size_t bytesPerRowOfPlane(size_t) const;
+
+ void getExtendedPixels(size_t* left, size_t* right, size_t* top, size_t* bottom) const;
+ CFDictionaryRef attachments() const;
+
+ // Generic CFRetain/CFRelease callbacks
+ static void releaseCallback(void* refcon);
+ static void retainCallback(void* refcon);
+
+ // CAImageQueue callbacks
+ static void imageQueueReleaseCallback(unsigned int type, uint64_t id, void* refcon);
+
+ // CGDataProvider callbacks
+ static void dataProviderReleaseBytePointerCallback(void* refcon, const void* pointer);
+ static const void* dataProviderGetBytePointerCallback(void* refcon);
+ static size_t dataProviderGetBytesAtPositionCallback(void* refcon, void* buffer, size_t position, size_t count);
+ static void dataProviderReleaseInfoCallback(void* refcon);
+
+private:
+ CVPixelBufferRef m_pixelBuffer;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTTrack.cpp b/Source/WebCore/platform/graphics/win/QTTrack.cpp
new file mode 100644
index 0000000..09142bc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTTrack.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+#include "config.h"
+
+#include "QTTrack.h"
+
+#include <Movies.h>
+#include <QTML.h>
+
+using namespace std;
+
+class QTTrackPrivate : public Noncopyable {
+public:
+ QTTrackPrivate();
+ ~QTTrackPrivate();
+
+ QTTrack* m_track;
+ Track m_trackHandle;
+};
+
+QTTrackPrivate::QTTrackPrivate()
+ : m_track(0)
+ , m_trackHandle(0)
+{
+}
+
+QTTrackPrivate::~QTTrackPrivate()
+{
+ m_trackHandle = 0;
+}
+
+PassRefPtr<QTTrack> QTTrack::create(Track trackHandle)
+{
+ return adoptRef(new QTTrack(trackHandle));
+}
+
+QTTrack::QTTrack(Track trackHandle)
+ : m_private(new QTTrackPrivate())
+{
+ m_private->m_track = this;
+ m_private->m_trackHandle = trackHandle;
+}
+
+QTTrack::~QTTrack()
+{
+ delete m_private;
+}
+
+bool QTTrack::isEnabled() const
+{
+ ASSERT(m_private->m_track);
+ return GetTrackEnabled(m_private->m_trackHandle);
+}
+
+void QTTrack::setEnabled(bool enabled)
+{
+ ASSERT(m_private->m_trackHandle);
+ SetTrackEnabled(m_private->m_trackHandle, enabled);
+}
+
+CGAffineTransform QTTrack::getTransform() const
+{
+ ASSERT(m_private->m_trackHandle);
+ MatrixRecord m = {0};
+ GetTrackMatrix(m_private->m_trackHandle, &m);
+
+ ASSERT(!m.matrix[0][2]);
+ ASSERT(!m.matrix[1][2]);
+ CGAffineTransform transform = CGAffineTransformMake(
+ Fix2X(m.matrix[0][0]),
+ Fix2X(m.matrix[0][1]),
+ Fix2X(m.matrix[1][0]),
+ Fix2X(m.matrix[1][1]),
+ Fix2X(m.matrix[2][0]),
+ Fix2X(m.matrix[2][1]));
+
+ return transform;
+}
+
+void QTTrack::setTransform(CGAffineTransform t)
+{
+ ASSERT(m_private->m_trackHandle);
+ MatrixRecord m = {{
+ {X2Fix(t.a), X2Fix(t.b), 0},
+ {X2Fix(t.c), X2Fix(t.d), 0},
+ {X2Fix(t.tx), X2Fix(t.ty), fract1},
+ }};
+
+ SetTrackMatrix(m_private->m_trackHandle, &m);
+}
+
+void QTTrack::resetTransform()
+{
+ ASSERT(m_private->m_trackHandle);
+ SetTrackMatrix(m_private->m_trackHandle, 0);
+}
+
diff --git a/Source/WebCore/platform/graphics/win/QTTrack.h b/Source/WebCore/platform/graphics/win/QTTrack.h
new file mode 100644
index 0000000..bda5644
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTTrack.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 QTTrack_h
+#define QTTrack_h
+
+#include <Unicode.h>
+#include <windows.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+// We must include this after <Unicode.h>, or the definition of OSErr will change:
+#include <CoreGraphics/CGAffineTransform.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTTrack;
+class QTTrackPrivate;
+typedef struct TrackType** Track;
+
+class QTMOVIEWIN_API QTTrack : public RefCounted<QTTrack> {
+public:
+ static PassRefPtr<QTTrack> create(Track);
+ ~QTTrack();
+
+ CGAffineTransform getTransform() const;
+ void setTransform(CGAffineTransform);
+ void resetTransform();
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ Track getTrackHandle() const;
+private:
+ QTTrack(Track);
+ QTTrackPrivate* m_private;
+ friend class QTTrackPrivate;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/RefCountedGDIHandle.h b/Source/WebCore/platform/graphics/win/RefCountedGDIHandle.h
new file mode 100644
index 0000000..65f66f1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/RefCountedGDIHandle.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RefCountedGDIHandle_h
+#define RefCountedGDIHandle_h
+
+#include <windows.h>
+#include <wtf/HashFunctions.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+template <typename T> class RefCountedGDIHandle : public RefCounted<RefCountedGDIHandle<T> > {
+public:
+ static PassRefPtr<RefCountedGDIHandle> create(T handle)
+ {
+ return adoptRef(new RefCountedGDIHandle<T>(handle));
+ }
+
+ static PassRefPtr<RefCountedGDIHandle<T> > createDeleted()
+ {
+ return adoptRef(new RefCountedGDIHandle<T>(reinterpret_cast<T>(-1)));
+ }
+
+ ~RefCountedGDIHandle()
+ {
+ if (m_handle != reinterpret_cast<T>(-1))
+ WTF::deleteOwnedPtr(m_handle);
+ }
+
+ T handle() const
+ {
+ return m_handle;
+ }
+
+ unsigned hash() const
+ {
+ return WTF::PtrHash<T>::hash(m_handle);
+ }
+
+private:
+ RefCountedGDIHandle(T handle)
+ : m_handle(handle)
+ {
+ }
+
+ T m_handle;
+};
+
+} // namespace WebCore
+
+#endif // RefCountedGDIHandle_h
diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
new file mode 100644
index 0000000..20d42ff
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include <winsock2.h>
+#include "Font.h"
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include "PlatformString.h"
+#include <wtf/MathExtras.h>
+#include <wtf/RetainPtr.h>
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <mlang.h>
+#include <tchar.h>
+
+namespace WebCore {
+
+using std::max;
+
+static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return unitsPerEm ? x / static_cast<float>(unitsPerEm) : x; }
+
+void SimpleFontData::platformInit()
+{
+ m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f;
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+ m_isSystemFont = false;
+
+ if (m_platformData.useGDI())
+ return initGDIFont();
+
+ CGFontRef font = m_platformData.cgFont();
+ int iAscent = CGFontGetAscent(font);
+ int iDescent = CGFontGetDescent(font);
+ int iLineGap = CGFontGetLeading(font);
+ m_unitsPerEm = CGFontGetUnitsPerEm(font);
+ float pointSize = m_platformData.size();
+ float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize;
+ float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize;
+ float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize;
+
+ if (!isCustomFont()) {
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont());
+ int faceLength = GetTextFace(dc, 0, 0);
+ Vector<TCHAR> faceName(faceLength);
+ GetTextFace(dc, faceLength, faceName.data());
+ m_isSystemFont = !_tcscmp(faceName.data(), _T("Lucida Grande"));
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ if (shouldApplyMacAscentHack()) {
+ // This code comes from FontDataMac.mm. We only ever do this when running regression tests so that our metrics will match Mac.
+
+ // We need to adjust Times, Helvetica, and Courier to closely match the
+ // vertical metrics of their Microsoft counterparts that are the de facto
+ // web standard. The AppKit adjustment of 20% is too big and is
+ // incorrectly added to line spacing, so we use a 15% adjustment instead
+ // and add it to the ascent.
+ if (!_tcscmp(faceName.data(), _T("Times")) || !_tcscmp(faceName.data(), _T("Helvetica")) || !_tcscmp(faceName.data(), _T("Courier")))
+ fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f);
+ }
+ }
+
+ m_ascent = lroundf(fAscent);
+ m_descent = lroundf(fDescent);
+ m_lineGap = lroundf(fLineGap);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font.
+ // Unfortunately, NSFont will round this for us so we don't quite get the right value.
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+ Glyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0;
+ if (xGlyph) {
+ CGRect xBox;
+ CGFontGetGlyphBBoxes(font, &xGlyph, 1, &xBox);
+ // Use the maximum of either width or height because "x" is nearly square
+ // and web pages that foolishly use this metric for width will be laid out
+ // poorly if we return an accurate height. Classic case is Times 13 point,
+ // which has an "x" that is 7x6 pixels.
+ m_xHeight = scaleEmToUnits(max(CGRectGetMaxX(xBox), CGRectGetMaxY(xBox)), m_unitsPerEm) * pointSize;
+ } else {
+ int iXHeight = CGFontGetXHeight(font);
+ m_xHeight = scaleEmToUnits(iXHeight, m_unitsPerEm) * pointSize;
+ }
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ // GDI Fonts init charwidths in initGDIFont.
+ if (!m_platformData.useGDI()) {
+ m_avgCharWidth = 0.f;
+ m_maxCharWidth = 0.f;
+ initCharWidths();
+ }
+}
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const
+{
+ if (m_platformData.useGDI())
+ return boundsForGDIGlyph(glyph);
+
+ CGRect box;
+ CGFontGetGlyphBBoxes(m_platformData.cgFont(), &glyph, 1, &box);
+ float pointSize = m_platformData.size();
+ CGFloat scale = pointSize / unitsPerEm();
+ FloatRect boundingBox = CGRectApplyAffineTransform(box, CGAffineTransformMakeScale(scale, -scale));
+ if (m_syntheticBoldOffset)
+ boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset);
+
+ return boundingBox;
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (m_platformData.useGDI())
+ return widthForGDIGlyph(glyph);
+
+ CGFontRef font = m_platformData.cgFont();
+ float pointSize = m_platformData.size();
+ CGSize advance;
+ CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
+
+ // FIXME: Need to add real support for printer fonts.
+ bool isPrinterFont = false;
+ wkGetGlyphAdvances(font, m, m_isSystemFont, isPrinterFont, glyph, advance);
+
+ return advance.width + m_syntheticBoldOffset;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
new file mode 100644
index 0000000..62ea060
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include <windows.h>
+
+#include "Font.h"
+#include "FontCache.h"
+#include "FontDescription.h"
+#include <cairo.h>
+#include <cairo-win32.h>
+#include <mlang.h>
+#include <tchar.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+ m_isSystemFont = false;
+
+ m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f;
+
+ if (m_platformData.useGDI())
+ return initGDIFont();
+
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ cairo_scaled_font_t* scaledFont = m_platformData.scaledFont();
+ const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_platformData.size();
+
+ cairo_win32_scaled_font_select_font(scaledFont, hdc);
+
+ TEXTMETRIC textMetrics;
+ GetTextMetrics(hdc, &textMetrics);
+ m_ascent = lroundf(textMetrics.tmAscent * metricsMultiplier);
+ m_descent = lroundf(textMetrics.tmDescent * metricsMultiplier);
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts.
+ m_lineGap = lroundf(textMetrics.tmExternalLeading * metricsMultiplier);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+ m_avgCharWidth = lroundf(textMetrics.tmAveCharWidth * metricsMultiplier);
+ m_maxCharWidth = lroundf(textMetrics.tmMaxCharWidth * metricsMultiplier);
+
+ OUTLINETEXTMETRIC metrics;
+ if (GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics) > 0) {
+ // This is a TrueType font. We might be able to get an accurate xHeight
+ GLYPHMETRICS gm;
+ MAT2 mat = { 1, 0, 0, 1 };
+ DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
+ if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
+ m_xHeight = gm.gmptGlyphOrigin.y * metricsMultiplier;
+ }
+
+ cairo_win32_scaled_font_done_font(scaledFont);
+
+ m_isSystemFont = false;
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ // charwidths are set in platformInit.
+}
+
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const
+{
+ if (m_platformData.useGDI())
+ return boundsForGDIGlyph(glyph);
+ //FIXME: Implement this
+ return FloatRect();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (m_platformData.useGDI())
+ return widthForGDIGlyph(glyph);
+
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ cairo_scaled_font_t* scaledFont = m_platformData.scaledFont();
+ cairo_win32_scaled_font_select_font(scaledFont, hdc);
+
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
+
+ cairo_win32_scaled_font_done_font(scaledFont);
+
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
+
+ const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_platformData.size();
+ return width * metricsMultiplier;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
new file mode 100644
index 0000000..60afe6a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include <winsock2.h>
+#include "Font.h"
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include <wtf/MathExtras.h>
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+#include <mlang.h>
+#include <tchar.h>
+
+#if PLATFORM(CG)
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
+
+namespace WebCore {
+
+using std::max;
+
+const float cSmallCapsFontSizeMultiplier = 0.7f;
+
+static bool g_shouldApplyMacAscentHack;
+
+void SimpleFontData::setShouldApplyMacAscentHack(bool b)
+{
+ g_shouldApplyMacAscentHack = b;
+}
+
+bool SimpleFontData::shouldApplyMacAscentHack()
+{
+ return g_shouldApplyMacAscentHack;
+}
+
+void SimpleFontData::initGDIFont()
+{
+ if (!m_platformData.size()) {
+ m_ascent = 0;
+ m_descent = 0;
+ m_lineGap = 0;
+ m_lineSpacing = 0;
+ m_avgCharWidth = 0;
+ m_maxCharWidth = 0;
+ m_xHeight = 0;
+ m_unitsPerEm = 0;
+ return;
+ }
+
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
+ OUTLINETEXTMETRIC metrics;
+ GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
+ TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
+ m_ascent = textMetrics.tmAscent;
+ m_descent = textMetrics.tmDescent;
+ m_lineGap = textMetrics.tmExternalLeading;
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+ m_avgCharWidth = textMetrics.tmAveCharWidth;
+ m_maxCharWidth = textMetrics.tmMaxCharWidth;
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
+
+ GLYPHMETRICS gm;
+ MAT2 mat = { 1, 0, 0, 1 };
+ DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
+ if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
+ m_xHeight = gm.gmptGlyphOrigin.y;
+
+ m_unitsPerEm = metrics.otmEMSquare;
+
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ return;
+}
+
+void SimpleFontData::platformDestroy()
+{
+ ScriptFreeCache(&m_scriptCache);
+ delete m_scriptFontProperties;
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ float scaledSize = scaleFactor * m_platformData.size();
+ if (isCustomFont()) {
+ FontPlatformData scaledFont(m_platformData);
+ scaledFont.setSize(scaledSize);
+ return new SimpleFontData(scaledFont, true, false);
+ }
+
+ LOGFONT winfont;
+ GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont);
+ winfont.lfHeight = -lroundf(scaledSize * (m_platformData.useGDI() ? 1 : 32));
+ HFONT hfont = CreateFontIndirect(&winfont);
+ return new SimpleFontData(FontPlatformData(hfont, scaledSize, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI()), isCustomFont(), false);
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, cSmallCapsFontSizeMultiplier);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ // FIXME: Support custom fonts.
+ if (isCustomFont())
+ return false;
+
+ // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC
+ // merely by testing code page intersection. This seems suspect though. Can't a font only partially
+ // cover a given code page?
+ IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
+ if (!langFontLink)
+ return false;
+
+ HDC dc = GetDC(0);
+
+ DWORD acpCodePages;
+ langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
+
+ DWORD fontCodePages;
+ langFontLink->GetFontCodePages(dc, m_platformData.hfont(), &fontCodePages);
+
+ DWORD actualCodePages;
+ long numCharactersProcessed;
+ long offset = 0;
+ while (offset < length) {
+ langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed);
+ if ((actualCodePages & fontCodePages) == 0)
+ return false;
+ offset += numCharactersProcessed;
+ }
+
+ ReleaseDC(0, dc);
+
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ if (isCustomFont()) {
+ m_treatAsFixedPitch = false;
+ return;
+ }
+
+ // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
+ HDC dc = GetDC(0);
+ SaveDC(dc);
+ SelectObject(dc, m_platformData.hfont());
+
+ // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
+ // is *not* fixed pitch. Unbelievable but true.
+ TEXTMETRIC tm;
+ GetTextMetrics(dc, &tm);
+ m_treatAsFixedPitch = ((tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
+
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+}
+
+FloatRect SimpleFontData::boundsForGDIGlyph(Glyph glyph) const
+{
+ HDC hdc = GetDC(0);
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
+
+ GLYPHMETRICS gdiMetrics;
+ static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 };
+ GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity);
+
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ return FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y,
+ gdiMetrics.gmBlackBoxX + m_syntheticBoldOffset, gdiMetrics.gmBlackBoxY);
+}
+
+float SimpleFontData::widthForGDIGlyph(Glyph glyph) const
+{
+ HDC hdc = GetDC(0);
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
+
+ GLYPHMETRICS gdiMetrics;
+ static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 };
+ GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity);
+
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ return gdiMetrics.gmCellIncX + m_syntheticBoldOffset;
+}
+
+SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const
+{
+ if (!m_scriptFontProperties) {
+ m_scriptFontProperties = new SCRIPT_FONTPROPERTIES;
+ memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES));
+ m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
+ HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties);
+ if (result == E_PENDING) {
+ HDC dc = GetDC(0);
+ SaveDC(dc);
+ SelectObject(dc, m_platformData.hfont());
+ ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties);
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+ }
+ }
+ return m_scriptFontProperties;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp b/Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
new file mode 100644
index 0000000..47806a2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "TransformationMatrix.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+TransformationMatrix::operator XFORM() const
+{
+ XFORM xform;
+ xform.eM11 = a();
+ xform.eM12 = b();
+ xform.eM21 = c();
+ xform.eM22 = d();
+ xform.eDx = e();
+ xform.eDy = f();
+
+ return xform;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/UniscribeController.cpp b/Source/WebCore/platform/graphics/win/UniscribeController.cpp
new file mode 100644
index 0000000..ab32150
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/UniscribeController.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "UniscribeController.h"
+#include "Font.h"
+#include "SimpleFontData.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+// FIXME: Rearchitect this to be more like WidthIterator in Font.cpp. Have an advance() method
+// that does stuff in that method instead of doing everything in the constructor. Have advance()
+// take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when
+// measuring.
+UniscribeController::UniscribeController(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts)
+ : m_font(*font)
+ , m_run(run)
+ , m_fallbackFonts(fallbackFonts)
+ , m_minGlyphBoundingBoxX(numeric_limits<float>::max())
+ , m_maxGlyphBoundingBoxX(numeric_limits<float>::min())
+ , m_minGlyphBoundingBoxY(numeric_limits<float>::max())
+ , m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
+ , m_end(run.length())
+ , m_currentCharacter(0)
+ , m_runWidthSoFar(0)
+ , m_padding(run.padding())
+ , m_computingOffsetPosition(false)
+ , m_includePartialGlyphs(false)
+ , m_offsetX(0)
+ , m_offsetPosition(0)
+{
+ if (!m_padding)
+ m_padPerSpace = 0;
+ else {
+ float numSpaces = 0;
+ for (int s = 0; s < m_run.length(); s++) {
+ if (Font::treatAsSpace(m_run[s]))
+ numSpaces++;
+ }
+
+ if (numSpaces == 0)
+ m_padPerSpace = 0;
+ else
+ m_padPerSpace = m_padding / numSpaces;
+ }
+
+ // Null out our uniscribe structs
+ resetControlAndState();
+}
+
+int UniscribeController::offsetForPosition(int x, bool includePartialGlyphs)
+{
+ m_computingOffsetPosition = true;
+ m_includePartialGlyphs = includePartialGlyphs;
+ m_offsetX = x;
+ m_offsetPosition = 0;
+ advance(m_run.length());
+ if (m_computingOffsetPosition) {
+ // The point is to the left or to the right of the entire run.
+ if (m_offsetX >= m_runWidthSoFar && m_run.ltr() || m_offsetX < 0 && m_run.rtl())
+ m_offsetPosition = m_end;
+ }
+ m_computingOffsetPosition = false;
+ return m_offsetPosition;
+}
+
+void UniscribeController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
+{
+ // FIXME: We really want to be using a newer version of Uniscribe that supports the new OpenType
+ // functions. Those functions would allow us to turn off kerning and ligatures. Without being able
+ // to do that, we will have buggy line breaking and metrics when simple and complex text are close
+ // together (the complex code path will narrow the text because of kerning and ligatures and then
+ // when bidi processing splits into multiple runs, the simple portions will get wider and cause us to
+ // spill off the edge of a line).
+ if (static_cast<int>(offset) > m_end)
+ offset = m_end;
+
+ // Itemize the string.
+ const UChar* cp = m_run.data(m_currentCharacter);
+ int length = offset - m_currentCharacter;
+ if (length <= 0)
+ return;
+
+ unsigned baseCharacter = m_currentCharacter;
+
+ // We break up itemization of the string by fontData and (if needed) the use of small caps.
+
+ // FIXME: It's inconsistent that we use logical order when itemizing, since this
+ // does not match normal RTL.
+
+ // FIXME: This function should decode surrogate pairs. Currently it makes little difference that
+ // it does not because the font cache on Windows does not support non-BMP characters.
+ Vector<UChar, 256> smallCapsBuffer;
+ if (m_font.isSmallCaps())
+ smallCapsBuffer.resize(length);
+
+ unsigned indexOfFontTransition = m_run.rtl() ? length - 1 : 0;
+ const UChar* curr = m_run.rtl() ? cp + length - 1 : cp;
+ const UChar* end = m_run.rtl() ? cp - 1 : cp + length;
+
+ const SimpleFontData* fontData;
+ const SimpleFontData* nextFontData = m_font.glyphDataForCharacter(*curr, false).fontData;
+
+ UChar newC = 0;
+
+ bool isSmallCaps;
+ bool nextIsSmallCaps = m_font.isSmallCaps() && !(U_GET_GC_MASK(*curr) & U_GC_M_MASK) && (newC = u_toupper(*curr)) != *curr;
+
+ if (nextIsSmallCaps)
+ smallCapsBuffer[curr - cp] = newC;
+
+ while (true) {
+ curr = m_run.rtl() ? curr - 1 : curr + 1;
+ if (curr == end)
+ break;
+
+ fontData = nextFontData;
+ isSmallCaps = nextIsSmallCaps;
+ int index = curr - cp;
+ UChar c = *curr;
+
+ bool forceSmallCaps = isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK);
+ nextFontData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps ? SmallCapsVariant : AutoVariant).fontData;
+ if (m_font.isSmallCaps()) {
+ nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c;
+ if (nextIsSmallCaps)
+ smallCapsBuffer[index] = forceSmallCaps ? c : newC;
+ }
+
+ if (m_fallbackFonts && nextFontData != fontData && fontData != m_font.primaryFont())
+ m_fallbackFonts->add(fontData);
+
+ if (nextFontData != fontData || nextIsSmallCaps != isSmallCaps) {
+ int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition;
+ int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition;
+ m_currentCharacter = baseCharacter + itemStart;
+ itemizeShapeAndPlace((isSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, fontData, glyphBuffer);
+ indexOfFontTransition = index;
+ }
+ }
+
+ int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : length - indexOfFontTransition;
+ if (itemLength) {
+ if (m_fallbackFonts && nextFontData != m_font.primaryFont())
+ m_fallbackFonts->add(nextFontData);
+
+ int itemStart = m_run.rtl() ? 0 : indexOfFontTransition;
+ m_currentCharacter = baseCharacter + itemStart;
+ itemizeShapeAndPlace((nextIsSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, nextFontData, glyphBuffer);
+ }
+
+ m_currentCharacter = baseCharacter + length;
+}
+
+void UniscribeController::itemizeShapeAndPlace(const UChar* cp, unsigned length, const SimpleFontData* fontData, GlyphBuffer* glyphBuffer)
+{
+ // ScriptItemize (in Windows XP versions prior to SP2) can overflow by 1. This is why there is an extra empty item
+ // hanging out at the end of the array
+ m_items.resize(6);
+ int numItems = 0;
+ while (ScriptItemize(cp, length, m_items.size() - 1, &m_control, &m_state, m_items.data(), &numItems) == E_OUTOFMEMORY) {
+ m_items.resize(m_items.size() * 2);
+ resetControlAndState();
+ }
+ m_items.resize(numItems + 1);
+
+ if (m_run.rtl()) {
+ for (int i = m_items.size() - 2; i >= 0; i--) {
+ if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer))
+ return;
+ }
+ } else {
+ for (unsigned i = 0; i < m_items.size() - 1; i++) {
+ if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer))
+ return;
+ }
+ }
+}
+
+void UniscribeController::resetControlAndState()
+{
+ memset(&m_control, 0, sizeof(SCRIPT_CONTROL));
+ memset(&m_state, 0, sizeof(SCRIPT_STATE));
+
+ // Set up the correct direction for the run.
+ m_state.uBidiLevel = m_run.rtl();
+
+ // Lock the correct directional override.
+ m_state.fOverrideDirection = m_run.directionalOverride();
+}
+
+bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const SimpleFontData* fontData, GlyphBuffer* glyphBuffer)
+{
+ // Determine the string for this item.
+ const UChar* str = cp + m_items[i].iCharPos;
+ int len = m_items[i+1].iCharPos - m_items[i].iCharPos;
+ SCRIPT_ITEM item = m_items[i];
+
+ // Set up buffers to hold the results of shaping the item.
+ Vector<WORD> glyphs;
+ Vector<WORD> clusters;
+ Vector<SCRIPT_VISATTR> visualAttributes;
+ clusters.resize(len);
+
+ // Shape the item.
+ // The recommended size for the glyph buffer is 1.5 * the character length + 16 in the uniscribe docs.
+ // Apparently this is a good size to avoid having to make repeated calls to ScriptShape.
+ glyphs.resize(1.5 * len + 16);
+ visualAttributes.resize(glyphs.size());
+
+ if (!shape(str, len, item, fontData, glyphs, clusters, visualAttributes))
+ return true;
+
+ // We now have a collection of glyphs.
+ Vector<GOFFSET> offsets;
+ Vector<int> advances;
+ offsets.resize(glyphs.size());
+ advances.resize(glyphs.size());
+ int glyphCount = 0;
+ HRESULT placeResult = ScriptPlace(0, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(),
+ &item.a, advances.data(), offsets.data(), 0);
+ if (placeResult == E_PENDING) {
+ // The script cache isn't primed with enough info yet. We need to select our HFONT into
+ // a DC and pass the DC in to ScriptPlace.
+ HDC hdc = GetDC(0);
+ HFONT hfont = fontData->platformData().hfont();
+ HFONT oldFont = (HFONT)SelectObject(hdc, hfont);
+ placeResult = ScriptPlace(hdc, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(),
+ &item.a, advances.data(), offsets.data(), 0);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ }
+
+ if (FAILED(placeResult) || glyphs.isEmpty())
+ return true;
+
+ // Convert all chars that should be treated as spaces to use the space glyph.
+ // We also create a map that allows us to quickly go from space glyphs or rounding
+ // hack glyphs back to their corresponding characters.
+ Vector<int> spaceCharacters(glyphs.size());
+ spaceCharacters.fill(-1);
+ Vector<int> roundingHackCharacters(glyphs.size());
+ roundingHackCharacters.fill(-1);
+ Vector<int> roundingHackWordBoundaries(glyphs.size());
+ roundingHackWordBoundaries.fill(-1);
+
+ const float cLogicalScale = fontData->platformData().useGDI() ? 1.0f : 32.0f;
+ unsigned logicalSpaceWidth = fontData->spaceWidth() * cLogicalScale;
+ float roundedSpaceWidth = roundf(fontData->spaceWidth());
+
+ for (int k = 0; k < len; k++) {
+ UChar ch = *(str + k);
+ bool treatAsSpace = Font::treatAsSpace(ch);
+ bool treatAsZeroWidthSpace = ch == zeroWidthSpace || Font::treatAsZeroWidthSpace(ch);
+ if (treatAsSpace || treatAsZeroWidthSpace) {
+ // Substitute in the space glyph at the appropriate place in the glyphs
+ // array.
+ glyphs[clusters[k]] = fontData->spaceGlyph();
+ advances[clusters[k]] = treatAsSpace ? logicalSpaceWidth : 0;
+ if (treatAsSpace)
+ spaceCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos;
+ }
+
+ if (Font::isRoundingHackCharacter(ch))
+ roundingHackCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos;
+
+ int boundary = k + m_currentCharacter + item.iCharPos;
+ if (boundary < m_run.length()) {
+ // When at the last character in the str, don't look one past the end for a rounding hack character.
+ // Instead look ahead to the first character of next item, if there is a next one.
+ if (k + 1 == len) {
+ if (i + 2 < m_items.size() // Check for at least 2 items remaining. The last item is a terminating item containing no characters.
+ && Font::isRoundingHackCharacter(*(cp + m_items[i + 1].iCharPos)))
+ roundingHackWordBoundaries[clusters[k]] = boundary;
+ } else if (Font::isRoundingHackCharacter(*(str + k + 1)))
+ roundingHackWordBoundaries[clusters[k]] = boundary;
+ }
+ }
+
+ // Populate our glyph buffer with this information.
+ bool hasExtraSpacing = m_font.letterSpacing() || m_font.wordSpacing() || m_padding;
+
+ float leftEdge = m_runWidthSoFar;
+
+ for (unsigned k = 0; k < glyphs.size(); k++) {
+ Glyph glyph = glyphs[k];
+ float advance = advances[k] / cLogicalScale;
+ float offsetX = offsets[k].du / cLogicalScale;
+ float offsetY = offsets[k].dv / cLogicalScale;
+
+ // Match AppKit's rules for the integer vs. non-integer rendering modes.
+ float roundedAdvance = roundf(advance);
+ if (!m_font.isPrinterFont() && !fontData->isSystemFont()) {
+ advance = roundedAdvance;
+ offsetX = roundf(offsetX);
+ offsetY = roundf(offsetY);
+ }
+
+ advance += fontData->syntheticBoldOffset();
+
+ // We special case spaces in two ways when applying word rounding.
+ // First, we round spaces to an adjusted width in all fonts.
+ // Second, in fixed-pitch fonts we ensure that all glyphs that
+ // match the width of the space glyph have the same width as the space glyph.
+ if (roundedAdvance == roundedSpaceWidth && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) &&
+ m_run.applyWordRounding())
+ advance = fontData->adjustedSpaceWidth();
+
+ if (hasExtraSpacing) {
+ // If we're a glyph with an advance, go ahead and add in letter-spacing.
+ // That way we weed out zero width lurkers. This behavior matches the fast text code path.
+ if (advance && m_font.letterSpacing())
+ advance += m_font.letterSpacing();
+
+ // Handle justification and word-spacing.
+ int characterIndex = spaceCharacters[k];
+ // characterIndex is left at the initial value of -1 for glyphs that do not map back to treated-as-space characters.
+ if (characterIndex != -1) {
+ // Account for padding. WebCore uses space padding to justify text.
+ // We distribute the specified padding over the available spaces in the run.
+ if (m_padding) {
+ // Use leftover padding if not evenly divisible by number of spaces.
+ if (m_padding < m_padPerSpace) {
+ advance += m_padding;
+ m_padding = 0;
+ } else {
+ float previousPadding = m_padding;
+ m_padding -= m_padPerSpace;
+ advance += roundf(previousPadding) - roundf(m_padding);
+ }
+ }
+
+ // Account for word-spacing.
+ if (characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing())
+ advance += m_font.wordSpacing();
+ }
+ }
+
+ // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters
+ // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
+ // We adjust the width of the last character of a "word" to ensure an integer width.
+ // Force characters that are used to determine word boundaries for the rounding hack
+ // to be integer width, so the following words will start on an integer boundary.
+ int roundingHackIndex = roundingHackCharacters[k];
+ if (m_run.applyWordRounding() && roundingHackIndex != -1)
+ advance = ceilf(advance);
+
+ // Check to see if the next character is a "rounding hack character", if so, adjust the
+ // width so that the total run width will be on an integer boundary.
+ int position = m_currentCharacter + len;
+ bool lastGlyph = (k == glyphs.size() - 1) && (m_run.rtl() ? i == 0 : i == m_items.size() - 2) && (position >= m_end);
+ if ((m_run.applyWordRounding() && roundingHackWordBoundaries[k] != -1) ||
+ (m_run.applyRunRounding() && lastGlyph)) {
+ float totalWidth = m_runWidthSoFar + advance;
+ advance += ceilf(totalWidth) - totalWidth;
+ }
+
+ m_runWidthSoFar += advance;
+
+ // FIXME: We need to take the GOFFSETS for combining glyphs and store them in the glyph buffer
+ // as well, so that when the time comes to draw those glyphs, we can apply the appropriate
+ // translation.
+ if (glyphBuffer) {
+ FloatSize size(offsetX, -offsetY);
+ glyphBuffer->add(glyph, fontData, advance, &size);
+ }
+
+ FloatRect glyphBounds = fontData->boundsForGlyph(glyph);
+ glyphBounds.move(m_glyphOrigin.x(), m_glyphOrigin.y());
+ m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphBounds.x());
+ m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.right());
+ m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphBounds.y());
+ m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.bottom());
+ m_glyphOrigin.move(advance + offsetX, -offsetY);
+
+ // Mutate the glyph array to contain our altered advances.
+ if (m_computingOffsetPosition)
+ advances[k] = advance;
+ }
+
+ while (m_computingOffsetPosition && m_offsetX >= leftEdge && m_offsetX < m_runWidthSoFar) {
+ // The position is somewhere inside this run.
+ int trailing = 0;
+ ScriptXtoCP(m_offsetX - leftEdge, clusters.size(), glyphs.size(), clusters.data(), visualAttributes.data(),
+ advances.data(), &item.a, &m_offsetPosition, &trailing);
+ if (trailing && m_includePartialGlyphs && m_offsetPosition < len - 1) {
+ m_offsetPosition += m_currentCharacter + m_items[i].iCharPos;
+ m_offsetX += m_run.rtl() ? -trailing : trailing;
+ } else {
+ m_computingOffsetPosition = false;
+ m_offsetPosition += m_currentCharacter + m_items[i].iCharPos;
+ if (trailing && m_includePartialGlyphs)
+ m_offsetPosition++;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, const SimpleFontData* fontData,
+ Vector<WORD>& glyphs, Vector<WORD>& clusters,
+ Vector<SCRIPT_VISATTR>& visualAttributes)
+{
+ HDC hdc = 0;
+ HFONT oldFont = 0;
+ HRESULT shapeResult = E_PENDING;
+ int glyphCount = 0;
+ do {
+ shapeResult = ScriptShape(hdc, fontData->scriptCache(), str, len, glyphs.size(), &item.a,
+ glyphs.data(), clusters.data(), visualAttributes.data(), &glyphCount);
+ if (shapeResult == E_PENDING) {
+ // The script cache isn't primed with enough info yet. We need to select our HFONT into
+ // a DC and pass the DC in to ScriptShape.
+ ASSERT(!hdc);
+ hdc = GetDC(0);
+ HFONT hfont = fontData->platformData().hfont();
+ oldFont = (HFONT)SelectObject(hdc, hfont);
+ } else if (shapeResult == E_OUTOFMEMORY) {
+ // Need to resize our buffers.
+ glyphs.resize(glyphs.size() * 2);
+ visualAttributes.resize(glyphs.size());
+ }
+ } while (shapeResult == E_PENDING || shapeResult == E_OUTOFMEMORY);
+
+ if (hdc) {
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ }
+
+ if (FAILED(shapeResult))
+ return false;
+
+ glyphs.shrink(glyphCount);
+ visualAttributes.shrink(glyphCount);
+
+ return true;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/UniscribeController.h b/Source/WebCore/platform/graphics/win/UniscribeController.h
new file mode 100644
index 0000000..162ddbe
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/UniscribeController.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 UniscribeController_h
+#define UniscribeController_h
+
+#include <usp10.h>
+#include "Font.h"
+#include "GlyphBuffer.h"
+#include "Vector.h"
+
+namespace WebCore {
+
+class UniscribeController {
+public:
+ UniscribeController(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0);
+
+ // Advance and measure/place up to the specified character.
+ void advance(unsigned to, GlyphBuffer* = 0);
+
+ // Compute the character offset for a given x coordinate.
+ int offsetForPosition(int x, bool includePartialGlyphs);
+
+ // Returns the width of everything we've consumed so far.
+ float runWidthSoFar() const { return m_runWidthSoFar; }
+
+ float minGlyphBoundingBoxX() const { return m_minGlyphBoundingBoxX; }
+ float maxGlyphBoundingBoxX() const { return m_maxGlyphBoundingBoxX; }
+ float minGlyphBoundingBoxY() const { return m_minGlyphBoundingBoxY; }
+ float maxGlyphBoundingBoxY() const { return m_maxGlyphBoundingBoxY; }
+
+private:
+ void resetControlAndState();
+
+ void itemizeShapeAndPlace(const UChar*, unsigned length, const SimpleFontData*, GlyphBuffer*);
+ bool shapeAndPlaceItem(const UChar*, unsigned index, const SimpleFontData*, GlyphBuffer*);
+ bool shape(const UChar* str, int len, SCRIPT_ITEM item, const SimpleFontData* fontData,
+ Vector<WORD>& glyphs, Vector<WORD>& clusters,
+ Vector<SCRIPT_VISATTR>& visualAttributes);
+
+ const Font& m_font;
+ const TextRun& m_run;
+ HashSet<const SimpleFontData*>* m_fallbackFonts;
+ FloatPoint m_glyphOrigin;
+ float m_minGlyphBoundingBoxX;
+ float m_maxGlyphBoundingBoxX;
+ float m_minGlyphBoundingBoxY;
+ float m_maxGlyphBoundingBoxY;
+
+ SCRIPT_CONTROL m_control;
+ SCRIPT_STATE m_state;
+ Vector<SCRIPT_ITEM> m_items;
+
+ unsigned m_currentCharacter;
+ int m_end;
+
+ float m_runWidthSoFar;
+ float m_padding;
+ float m_padPerSpace;
+
+ bool m_computingOffsetPosition;
+ bool m_includePartialGlyphs;
+ float m_offsetX;
+ int m_offsetPosition;
+};
+
+}
+#endif
diff --git a/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp b/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp
new file mode 100644
index 0000000..d75c854
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WKCACFContextFlusher.h"
+
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+WKCACFContextFlusher& WKCACFContextFlusher::shared()
+{
+ DEFINE_STATIC_LOCAL(WKCACFContextFlusher, flusher, ());
+ return flusher;
+}
+
+WKCACFContextFlusher::WKCACFContextFlusher()
+{
+}
+
+WKCACFContextFlusher::~WKCACFContextFlusher()
+{
+}
+
+void WKCACFContextFlusher::addContext(WKCACFContext* context)
+{
+ ASSERT(context);
+
+ m_contexts.add(context);
+}
+
+void WKCACFContextFlusher::removeContext(WKCACFContext* context)
+{
+ ASSERT(context);
+
+ m_contexts.remove(context);
+}
+
+void WKCACFContextFlusher::flushAllContexts()
+{
+ // addContext might get called beneath CACFContextFlush, and we don't want m_contexts to change while
+ // we're iterating over it, so we move the contexts into a local ContextSet and iterate over that instead.
+ ContextSet contextsToFlush;
+ contextsToFlush.swap(m_contexts);
+
+ ContextSet::const_iterator end = contextsToFlush.end();
+ for (ContextSet::const_iterator it = contextsToFlush.begin(); it != end; ++it)
+ wkCACFContextFlush(*it);
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.h b/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.h
new file mode 100644
index 0000000..17ec41d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 WKCACFContextFlusher_h
+#define WKCACFContextFlusher_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include <wtf/Noncopyable.h>
+
+#include <wtf/HashSet.h>
+
+struct WKCACFContext;
+
+namespace WebCore {
+
+class WKCACFContextFlusher : public Noncopyable {
+public:
+ static WKCACFContextFlusher& shared();
+
+ void addContext(WKCACFContext*);
+ void removeContext(WKCACFContext*);
+
+ void flushAllContexts();
+
+private:
+ WKCACFContextFlusher();
+ ~WKCACFContextFlusher();
+
+ typedef HashSet<WKCACFContext*> ContextSet;
+ ContextSet m_contexts;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WKCACFContextFlusher_h
diff --git a/Source/WebCore/platform/graphics/win/WKCACFLayer.cpp b/Source/WebCore/platform/graphics/win/WKCACFLayer.cpp
new file mode 100644
index 0000000..a8714e3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFLayer.cpp
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WKCACFLayer.h"
+
+#include "WKCACFLayerRenderer.h"
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <stdio.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+using namespace std;
+
+#ifndef NDEBUG
+void WKCACFLayer::internalCheckLayerConsistency()
+{
+ ASSERT(layer());
+ size_t n = sublayerCount();
+ for (size_t i = 0; i < n; ++i) {
+ // This will ASSERT in internalSublayerAtIndex if this entry doesn't have proper user data
+ WKCACFLayer* sublayer = internalSublayerAtIndex(i);
+
+ // Make sure we don't have any null entries in the list
+ ASSERT(sublayer);
+
+ // Make sure the each layer has a corresponding CACFLayer
+ ASSERT(sublayer->layer());
+ }
+}
+#endif
+
+static void displayCallback(CACFLayerRef layer, CGContextRef context)
+{
+ ASSERT_ARG(layer, WKCACFLayer::layer(layer));
+ WKCACFLayer::layer(layer)->drawInContext(context);
+}
+
+static CFStringRef toCACFLayerType(WKCACFLayer::LayerType type)
+{
+ switch (type) {
+ case WKCACFLayer::Layer: return kCACFLayer;
+ case WKCACFLayer::TransformLayer: return kCACFTransformLayer;
+ default: return 0;
+ }
+}
+
+static CFStringRef toCACFContentsGravityType(WKCACFLayer::ContentsGravityType type)
+{
+ switch (type) {
+ case WKCACFLayer::Center: return kCACFGravityCenter;
+ case WKCACFLayer::Top: return kCACFGravityTop;
+ case WKCACFLayer::Bottom: return kCACFGravityBottom;
+ case WKCACFLayer::Left: return kCACFGravityLeft;
+ case WKCACFLayer::Right: return kCACFGravityRight;
+ case WKCACFLayer::TopLeft: return kCACFGravityTopLeft;
+ case WKCACFLayer::TopRight: return kCACFGravityTopRight;
+ case WKCACFLayer::BottomLeft: return kCACFGravityBottomLeft;
+ case WKCACFLayer::BottomRight: return kCACFGravityBottomRight;
+ case WKCACFLayer::Resize: return kCACFGravityResize;
+ case WKCACFLayer::ResizeAspect: return kCACFGravityResizeAspect;
+ case WKCACFLayer::ResizeAspectFill: return kCACFGravityResizeAspectFill;
+ default: return 0;
+ }
+}
+
+static WKCACFLayer::ContentsGravityType fromCACFContentsGravityType(CFStringRef string)
+{
+ if (CFEqual(string, kCACFGravityTop))
+ return WKCACFLayer::Top;
+
+ if (CFEqual(string, kCACFGravityBottom))
+ return WKCACFLayer::Bottom;
+
+ if (CFEqual(string, kCACFGravityLeft))
+ return WKCACFLayer::Left;
+
+ if (CFEqual(string, kCACFGravityRight))
+ return WKCACFLayer::Right;
+
+ if (CFEqual(string, kCACFGravityTopLeft))
+ return WKCACFLayer::TopLeft;
+
+ if (CFEqual(string, kCACFGravityTopRight))
+ return WKCACFLayer::TopRight;
+
+ if (CFEqual(string, kCACFGravityBottomLeft))
+ return WKCACFLayer::BottomLeft;
+
+ if (CFEqual(string, kCACFGravityBottomRight))
+ return WKCACFLayer::BottomRight;
+
+ if (CFEqual(string, kCACFGravityResize))
+ return WKCACFLayer::Resize;
+
+ if (CFEqual(string, kCACFGravityResizeAspect))
+ return WKCACFLayer::ResizeAspect;
+
+ if (CFEqual(string, kCACFGravityResizeAspectFill))
+ return WKCACFLayer::ResizeAspectFill;
+
+ return WKCACFLayer::Center;
+}
+
+static CFStringRef toCACFFilterType(WKCACFLayer::FilterType type)
+{
+ switch (type) {
+ case WKCACFLayer::Linear: return kCACFFilterLinear;
+ case WKCACFLayer::Nearest: return kCACFFilterNearest;
+ case WKCACFLayer::Trilinear: return kCACFFilterTrilinear;
+ default: return 0;
+ }
+}
+
+static WKCACFLayer::FilterType fromCACFFilterType(CFStringRef string)
+{
+ if (CFEqual(string, kCACFFilterNearest))
+ return WKCACFLayer::Nearest;
+
+ if (CFEqual(string, kCACFFilterTrilinear))
+ return WKCACFLayer::Trilinear;
+
+ return WKCACFLayer::Linear;
+}
+
+PassRefPtr<WKCACFLayer> WKCACFLayer::create(LayerType type)
+{
+ if (!WKCACFLayerRenderer::acceleratedCompositingAvailable())
+ return 0;
+ return adoptRef(new WKCACFLayer(type));
+}
+
+// FIXME: It might be good to have a way of ensuring that all WKCACFLayers eventually
+// get destroyed in debug builds. A static counter could accomplish this pretty easily.
+
+WKCACFLayer::WKCACFLayer(LayerType type)
+ : m_layer(AdoptCF, CACFLayerCreate(toCACFLayerType(type)))
+ , m_layoutClient(0)
+ , m_needsDisplayOnBoundsChange(false)
+{
+ CACFLayerSetUserData(layer(), this);
+ CACFLayerSetDisplayCallback(layer(), displayCallback);
+}
+
+WKCACFLayer::~WKCACFLayer()
+{
+ // Our superlayer should be holding a reference to us, so there should be no way for us to be destroyed while we still have a superlayer.
+ ASSERT(!superlayer());
+
+ // Get rid of the children so we don't have any dangling references around
+ removeAllSublayers();
+
+#ifndef NDEBUG
+ CACFLayerSetUserData(layer(), reinterpret_cast<void*>(0xDEADBEEF));
+#else
+ CACFLayerSetUserData(layer(), 0);
+#endif
+ CACFLayerSetDisplayCallback(layer(), 0);
+}
+
+void WKCACFLayer::becomeRootLayerForContext(WKCACFContext* context)
+{
+ wkCACFContextSetLayer(context, layer());
+ setNeedsCommit();
+}
+
+void WKCACFLayer::setNeedsCommit()
+{
+ WKCACFLayer* root = rootLayer();
+
+ // Call setNeedsRender on the root layer, which will cause a render to
+ // happen in WKCACFLayerRenderer
+ root->setNeedsRender();
+}
+
+bool WKCACFLayer::isTransformLayer() const
+{
+ return CACFLayerGetClass(layer()) == kCACFTransformLayer;
+}
+
+void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer)
+{
+ insertSublayer(sublayer, sublayerCount());
+}
+
+void WKCACFLayer::internalInsertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index)
+{
+ index = min(index, sublayerCount() + 1);
+ sublayer->removeFromSuperlayer();
+ CACFLayerInsertSublayer(layer(), sublayer->layer(), index);
+ setNeedsCommit();
+ checkLayerConsistency();
+}
+
+void WKCACFLayer::insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference)
+{
+ if (!reference) {
+ insertSublayer(sublayer, 0);
+ return;
+ }
+
+ int referenceIndex = internalIndexOfSublayer(reference);
+ if (referenceIndex == -1) {
+ addSublayer(sublayer);
+ return;
+ }
+
+ insertSublayer(sublayer, referenceIndex + 1);
+}
+
+void WKCACFLayer::insertSublayerBelowLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference)
+{
+ if (!reference) {
+ insertSublayer(sublayer, 0);
+ return;
+ }
+
+ int referenceIndex = internalIndexOfSublayer(reference);
+ if (referenceIndex == -1) {
+ addSublayer(sublayer);
+ return;
+ }
+
+ insertSublayer(sublayer, referenceIndex);
+}
+
+void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer> newLayer)
+{
+ ASSERT_ARG(reference, reference);
+ ASSERT_ARG(reference, reference->superlayer() == this);
+
+ if (reference == newLayer)
+ return;
+
+ int referenceIndex = internalIndexOfSublayer(reference);
+ ASSERT(referenceIndex != -1);
+ if (referenceIndex == -1)
+ return;
+
+ reference->removeFromSuperlayer();
+
+ if (newLayer) {
+ newLayer->removeFromSuperlayer();
+ insertSublayer(newLayer, referenceIndex);
+ }
+}
+
+size_t WKCACFLayer::internalSublayerCount() const
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(layer());
+ return sublayers ? CFArrayGetCount(sublayers) : 0;
+}
+
+void WKCACFLayer::adoptSublayers(WKCACFLayer* source)
+{
+ // We will use setSublayers() because it properly nulls
+ // out the superlayer pointer.
+ Vector<RefPtr<WKCACFLayer> > sublayers;
+ size_t n = source->sublayerCount();
+
+ for (size_t i = 0; i < n; ++i)
+ sublayers.append(source->internalSublayerAtIndex(i));
+
+ setSublayers(sublayers);
+ source->checkLayerConsistency();
+}
+
+void WKCACFLayer::removeFromSuperlayer()
+{
+ WKCACFLayer* superlayer = this->superlayer();
+ CACFLayerRemoveFromSuperlayer(layer());
+ checkLayerConsistency();
+
+ if (superlayer)
+ superlayer->setNeedsCommit();
+}
+
+WKCACFLayer* WKCACFLayer::internalSublayerAtIndex(int index) const
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(layer());
+ if (!sublayers || index < 0 || CFArrayGetCount(sublayers) <= index)
+ return 0;
+
+ return layer(static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index))));
+}
+
+int WKCACFLayer::internalIndexOfSublayer(const WKCACFLayer* reference)
+{
+ CACFLayerRef ref = reference->layer();
+ if (!ref)
+ return -1;
+
+ CFArrayRef sublayers = CACFLayerGetSublayers(layer());
+ if (!sublayers)
+ return -1;
+
+ size_t n = CFArrayGetCount(sublayers);
+
+ for (size_t i = 0; i < n; ++i)
+ if (CFArrayGetValueAtIndex(sublayers, i) == ref)
+ return i;
+
+ return -1;
+}
+
+WKCACFLayer* WKCACFLayer::ancestorOrSelfWithSuperlayer(WKCACFLayer* superlayer) const
+{
+ WKCACFLayer* layer = const_cast<WKCACFLayer*>(this);
+ for (WKCACFLayer* ancestor = this->superlayer(); ancestor; layer = ancestor, ancestor = ancestor->superlayer()) {
+ if (ancestor == superlayer)
+ return layer;
+ }
+ return 0;
+}
+
+void WKCACFLayer::setBounds(const CGRect& rect)
+{
+ if (CGRectEqualToRect(rect, bounds()))
+ return;
+
+ CACFLayerSetBounds(layer(), rect);
+ setNeedsCommit();
+
+ if (m_needsDisplayOnBoundsChange)
+ setNeedsDisplay();
+
+ if (m_layoutClient)
+ setNeedsLayout();
+}
+
+void WKCACFLayer::setFrame(const CGRect& rect)
+{
+ CGRect oldFrame = frame();
+ if (CGRectEqualToRect(rect, oldFrame))
+ return;
+
+ CACFLayerSetFrame(layer(), rect);
+ setNeedsCommit();
+
+ if (m_needsDisplayOnBoundsChange && !CGSizeEqualToSize(rect.size, oldFrame.size))
+ setNeedsDisplay();
+
+ if (m_layoutClient)
+ setNeedsLayout();
+}
+
+void WKCACFLayer::setContentsGravity(ContentsGravityType type)
+{
+ CACFLayerSetContentsGravity(layer(), toCACFContentsGravityType(type));
+ setNeedsCommit();
+}
+
+WKCACFLayer::ContentsGravityType WKCACFLayer::contentsGravity() const
+{
+ return fromCACFContentsGravityType(CACFLayerGetContentsGravity(layer()));
+}
+
+void WKCACFLayer::setMagnificationFilter(FilterType type)
+{
+ CACFLayerSetMagnificationFilter(layer(), toCACFFilterType(type));
+ setNeedsCommit();
+}
+
+WKCACFLayer::FilterType WKCACFLayer::magnificationFilter() const
+{
+ return fromCACFFilterType(CACFLayerGetMagnificationFilter(layer()));
+}
+
+void WKCACFLayer::setMinificationFilter(FilterType type)
+{
+ CACFLayerSetMinificationFilter(layer(), toCACFFilterType(type));
+ setNeedsCommit();
+}
+
+WKCACFLayer::FilterType WKCACFLayer::minificationFilter() const
+{
+ return fromCACFFilterType(CACFLayerGetMinificationFilter(layer()));
+}
+
+WKCACFLayer* WKCACFLayer::rootLayer() const
+{
+ WKCACFLayer* layer = const_cast<WKCACFLayer*>(this);
+ for (WKCACFLayer* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { }
+ return layer;
+}
+
+void WKCACFLayer::internalRemoveAllSublayers()
+{
+ CACFLayerSetSublayers(layer(), 0);
+ setNeedsCommit();
+}
+
+void WKCACFLayer::internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers)
+{
+ // Remove all the current sublayers and add the passed layers
+ CACFLayerSetSublayers(layer(), 0);
+
+ // Perform removeFromSuperLayer in a separate pass. CACF requires superlayer to
+ // be null or CACFLayerInsertSublayer silently fails.
+ for (size_t i = 0; i < sublayers.size(); i++)
+ CACFLayerRemoveFromSuperlayer(sublayers[i]->layer());
+
+ for (size_t i = 0; i < sublayers.size(); i++)
+ CACFLayerInsertSublayer(layer(), sublayers[i]->layer(), i);
+
+ setNeedsCommit();
+}
+
+WKCACFLayer* WKCACFLayer::superlayer() const
+{
+ CACFLayerRef super = CACFLayerGetSuperlayer(layer());
+ if (!super)
+ return 0;
+ return WKCACFLayer::layer(super);
+}
+
+void WKCACFLayer::internalSetNeedsDisplay(const CGRect* dirtyRect)
+{
+ CACFLayerSetNeedsDisplay(layer(), dirtyRect);
+}
+
+void WKCACFLayer::setLayoutClient(WKCACFLayerLayoutClient* layoutClient)
+{
+ if (layoutClient == m_layoutClient)
+ return;
+
+ m_layoutClient = layoutClient;
+ CACFLayerSetLayoutCallback(layer(), m_layoutClient ? layoutSublayersProc : 0);
+}
+
+void WKCACFLayer::layoutSublayersProc(CACFLayerRef caLayer)
+{
+ WKCACFLayer* layer = WKCACFLayer::layer(caLayer);
+ if (layer && layer->m_layoutClient)
+ layer->m_layoutClient->layoutSublayersOfLayer(layer);
+}
+
+#ifndef NDEBUG
+static void printIndent(int indent)
+{
+ for ( ; indent > 0; --indent)
+ fprintf(stderr, " ");
+}
+
+static void printTransform(const CATransform3D& transform)
+{
+ fprintf(stderr, "[%g %g %g %g; %g %g %g %g; %g %g %g %g; %g %g %g %g]",
+ transform.m11, transform.m12, transform.m13, transform.m14,
+ transform.m21, transform.m22, transform.m23, transform.m24,
+ transform.m31, transform.m32, transform.m33, transform.m34,
+ transform.m41, transform.m42, transform.m43, transform.m44);
+}
+
+void WKCACFLayer::printTree() const
+{
+ // Print heading info
+ CGRect rootBounds = bounds();
+ fprintf(stderr, "\n\n** Render tree at time %g (bounds %g, %g %gx%g) **\n\n",
+ currentTime(), rootBounds.origin.x, rootBounds.origin.y, rootBounds.size.width, rootBounds.size.height);
+
+ // Print layer tree from the root
+ printLayer(0);
+}
+
+void WKCACFLayer::printLayer(int indent) const
+{
+ CGPoint layerPosition = position();
+ CGPoint layerAnchorPoint = anchorPoint();
+ CGRect layerBounds = bounds();
+ printIndent(indent);
+ fprintf(stderr, "(%s [%g %g %g] [%g %g %g %g] [%g %g %g] superlayer=%p\n",
+ isTransformLayer() ? "transform-layer" : "layer",
+ layerPosition.x, layerPosition.y, zPosition(),
+ layerBounds.origin.x, layerBounds.origin.y, layerBounds.size.width, layerBounds.size.height,
+ layerAnchorPoint.x, layerAnchorPoint.y, anchorPointZ(), superlayer());
+
+ // Print name if needed
+ String layerName = name();
+ if (!layerName.isEmpty()) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(name %s)\n", layerName.utf8().data());
+ }
+
+ // Print masksToBounds if needed
+ bool layerMasksToBounds = masksToBounds();
+ if (layerMasksToBounds) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(masksToBounds true)\n");
+ }
+
+ // Print opacity if needed
+ float layerOpacity = opacity();
+ if (layerOpacity != 1) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(opacity %hf)\n", layerOpacity);
+ }
+
+ // Print sublayerTransform if needed
+ CATransform3D layerTransform = sublayerTransform();
+ if (!CATransform3DIsIdentity(layerTransform)) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(sublayerTransform ");
+ printTransform(layerTransform);
+ fprintf(stderr, ")\n");
+ }
+
+ // Print transform if needed
+ layerTransform = transform();
+ if (!CATransform3DIsIdentity(layerTransform)) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(transform ");
+ printTransform(layerTransform);
+ fprintf(stderr, ")\n");
+ }
+
+ // Print contents if needed
+ CFTypeRef layerContents = contents();
+ if (layerContents) {
+ if (CFGetTypeID(layerContents) == CGImageGetTypeID()) {
+ CGImageRef imageContents = static_cast<CGImageRef>(const_cast<void*>(layerContents));
+ printIndent(indent + 1);
+ fprintf(stderr, "(contents (image [%d %d]))\n",
+ CGImageGetWidth(imageContents), CGImageGetHeight(imageContents));
+ }
+ }
+
+ // Print sublayers if needed
+ int n = sublayerCount();
+ if (n > 0) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(sublayers\n");
+ for (int i = 0; i < n; ++i)
+ internalSublayerAtIndex(i)->printLayer(indent + 2);
+
+ printIndent(indent + 1);
+ fprintf(stderr, ")\n");
+ }
+
+ printIndent(indent);
+ fprintf(stderr, ")\n");
+}
+#endif // #ifndef NDEBUG
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WKCACFLayer.h b/Source/WebCore/platform/graphics/win/WKCACFLayer.h
new file mode 100644
index 0000000..4c6639a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFLayer.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 WKCACFLayer_h
+#define WKCACFLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include <wtf/RefCounted.h>
+
+#include <QuartzCore/CACFLayer.h>
+#include <QuartzCore/CACFVector.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include "TransformationMatrix.h"
+
+struct WKCACFContext;
+
+namespace WebCore {
+
+class WKCACFLayer;
+
+class WKCACFLayerLayoutClient {
+public:
+ virtual void layoutSublayersOfLayer(WKCACFLayer*) = 0;
+protected:
+ virtual ~WKCACFLayerLayoutClient() {}
+};
+
+class WKCACFLayer : public RefCounted<WKCACFLayer> {
+public:
+ enum LayerType { Layer, TransformLayer };
+ enum FilterType { Linear, Nearest, Trilinear };
+ enum ContentsGravityType { Center, Top, Bottom, Left, Right, TopLeft, TopRight,
+ BottomLeft, BottomRight, Resize, ResizeAspect, ResizeAspectFill };
+
+ static PassRefPtr<WKCACFLayer> create(LayerType);
+ static WKCACFLayer* layer(CACFLayerRef layer)
+ {
+ ASSERT(CACFLayerGetUserData(layer) != reinterpret_cast<void*>(0xDEADBEEF));
+ return static_cast<WKCACFLayer*>(CACFLayerGetUserData(layer));
+ }
+
+ virtual ~WKCACFLayer();
+
+ virtual void setNeedsRender() { }
+
+ virtual void drawInContext(PlatformGraphicsContext*) { }
+
+ void setLayoutClient(WKCACFLayerLayoutClient*);
+ WKCACFLayerLayoutClient* layoutClient() const { return m_layoutClient; }
+ void setNeedsLayout() { CACFLayerSetNeedsLayout(layer()); }
+
+ void setNeedsDisplay(const CGRect* dirtyRect = 0)
+ {
+ internalSetNeedsDisplay(dirtyRect);
+ setNeedsCommit();
+ }
+
+ // Makes this layer the root when the passed context is rendered
+ void becomeRootLayerForContext(WKCACFContext*);
+
+ static RetainPtr<CFTypeRef> cfValue(float value) { return RetainPtr<CFTypeRef>(AdoptCF, CFNumberCreate(0, kCFNumberFloat32Type, &value)); }
+ static RetainPtr<CFTypeRef> cfValue(const TransformationMatrix& value)
+ {
+ CATransform3D t;
+ t.m11 = value.m11();
+ t.m12 = value.m12();
+ t.m13 = value.m13();
+ t.m14 = value.m14();
+ t.m21 = value.m21();
+ t.m22 = value.m22();
+ t.m23 = value.m23();
+ t.m24 = value.m24();
+ t.m31 = value.m31();
+ t.m32 = value.m32();
+ t.m33 = value.m33();
+ t.m34 = value.m34();
+ t.m41 = value.m41();
+ t.m42 = value.m42();
+ t.m43 = value.m43();
+ t.m44 = value.m44();
+ return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreateTransform(t));
+ }
+ static RetainPtr<CFTypeRef> cfValue(const FloatPoint& value)
+ {
+ CGPoint p;
+ p.x = value.x(); p.y = value.y();
+ return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreatePoint(p));
+ }
+ static RetainPtr<CFTypeRef> cfValue(const FloatRect& rect)
+ {
+ CGRect r;
+ r.origin.x = rect.x();
+ r.origin.y = rect.y();
+ r.size.width = rect.width();
+ r.size.height = rect.height();
+ CGFloat v[4] = { CGRectGetMinX(r), CGRectGetMinY(r), CGRectGetMaxX(r), CGRectGetMaxY(r) };
+ return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreate(4, v));
+ }
+ static RetainPtr<CFTypeRef> cfValue(const Color& color)
+ {
+ return RetainPtr<CFTypeRef>(AdoptCF, CGColorCreateGenericRGB(color.red(), color.green(), color.blue(), color.alpha()));
+ }
+
+ bool isTransformLayer() const;
+
+ void addSublayer(PassRefPtr<WKCACFLayer> sublayer);
+ void insertSublayerAboveLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference);
+ void insertSublayerBelowLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference);
+ void replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer>);
+ void adoptSublayers(WKCACFLayer* source);
+
+ void removeAllSublayers() { internalRemoveAllSublayers(); }
+ void setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers)
+ {
+ internalSetSublayers(sublayers);
+ checkLayerConsistency();
+ }
+
+ void insertSublayer(PassRefPtr<WKCACFLayer> layer, size_t index) { internalInsertSublayer(layer, index); }
+
+ size_t sublayerCount() const { return internalSublayerCount(); }
+
+ void removeFromSuperlayer();
+
+ WKCACFLayer* ancestorOrSelfWithSuperlayer(WKCACFLayer*) const;
+
+ void setAnchorPoint(const CGPoint& p) { CACFLayerSetAnchorPoint(layer(), p); setNeedsCommit(); }
+ CGPoint anchorPoint() const { return CACFLayerGetAnchorPoint(layer()); }
+
+ void setAnchorPointZ(CGFloat z) { CACFLayerSetAnchorPointZ(layer(), z); setNeedsCommit(); }
+ CGFloat anchorPointZ() const { return CACFLayerGetAnchorPointZ(layer()); }
+
+ void setBackgroundColor(CGColorRef color) { CACFLayerSetBackgroundColor(layer(), color); setNeedsCommit(); }
+ CGColorRef backgroundColor() const { return CACFLayerGetBackgroundColor(layer()); }
+
+ void setBorderColor(CGColorRef color) { CACFLayerSetBorderColor(layer(), color); setNeedsCommit(); }
+ CGColorRef borderColor() const { return CACFLayerGetBorderColor(layer()); }
+
+ void setBorderWidth(CGFloat width) { CACFLayerSetBorderWidth(layer(), width); setNeedsCommit(); }
+ CGFloat borderWidth() const { return CACFLayerGetBorderWidth(layer()); }
+
+ virtual void setBounds(const CGRect&);
+ CGRect bounds() const { return CACFLayerGetBounds(layer()); }
+
+ void setContents(CFTypeRef contents) { CACFLayerSetContents(layer(), contents); setNeedsCommit(); }
+ CFTypeRef contents() const { return CACFLayerGetContents(layer()); }
+
+ void setContentsRect(const CGRect& contentsRect) { CACFLayerSetContentsRect(layer(), contentsRect); setNeedsCommit(); }
+ CGRect contentsRect() const { return CACFLayerGetContentsRect(layer()); }
+
+ void setContentsGravity(ContentsGravityType);
+ ContentsGravityType contentsGravity() const;
+
+ void setDoubleSided(bool b) { CACFLayerSetDoubleSided(layer(), b); setNeedsCommit(); }
+ bool doubleSided() const { return CACFLayerIsDoubleSided(layer()); }
+
+ void setEdgeAntialiasingMask(uint32_t mask) { CACFLayerSetEdgeAntialiasingMask(layer(), mask); setNeedsCommit(); }
+ uint32_t edgeAntialiasingMask() const { return CACFLayerGetEdgeAntialiasingMask(layer()); }
+
+ virtual void setFrame(const CGRect&);
+ CGRect frame() const { return CACFLayerGetFrame(layer()); }
+
+ void setHidden(bool hidden) { CACFLayerSetHidden(layer(), hidden); setNeedsCommit(); }
+ bool isHidden() const { return CACFLayerIsHidden(layer()); }
+
+ void setMasksToBounds(bool b) { CACFLayerSetMasksToBounds(layer(), b); }
+ bool masksToBounds() const { return CACFLayerGetMasksToBounds(layer()); }
+
+ void setMagnificationFilter(FilterType);
+ FilterType magnificationFilter() const;
+
+ void setMinificationFilter(FilterType);
+ FilterType minificationFilter() const;
+
+ void setMinificationFilterBias(float bias) { CACFLayerSetMinificationFilterBias(layer(), bias); }
+ float minificationFilterBias() const { return CACFLayerGetMinificationFilterBias(layer()); }
+
+ void setName(const String& name) { CACFLayerSetName(layer(), RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get()); }
+ String name() const { return CACFLayerGetName(layer()); }
+
+ void setNeedsDisplayOnBoundsChange(bool needsDisplay) { m_needsDisplayOnBoundsChange = needsDisplay; }
+
+ void setOpacity(float opacity) { CACFLayerSetOpacity(layer(), opacity); setNeedsCommit(); }
+ float opacity() const { return CACFLayerGetOpacity(layer()); }
+
+ void setOpaque(bool b) { CACFLayerSetOpaque(layer(), b); setNeedsCommit(); }
+ bool opaque() const { return CACFLayerIsOpaque(layer()); }
+
+ void setPosition(const CGPoint& position) { CACFLayerSetPosition(layer(), position); setNeedsCommit(); }
+ CGPoint position() const { return CACFLayerGetPosition(layer()); }
+
+ void setZPosition(CGFloat position) { CACFLayerSetZPosition(layer(), position); setNeedsCommit(); }
+ CGFloat zPosition() const { return CACFLayerGetZPosition(layer()); }
+
+ void setSpeed(float speed) { CACFLayerSetSpeed(layer(), speed); }
+ CFTimeInterval speed() const { return CACFLayerGetSpeed(layer()); }
+
+ void setTimeOffset(CFTimeInterval t) { CACFLayerSetTimeOffset(layer(), t); }
+ CFTimeInterval timeOffset() const { return CACFLayerGetTimeOffset(layer()); }
+
+ WKCACFLayer* rootLayer() const;
+
+ void setSublayerTransform(const CATransform3D& transform) { CACFLayerSetSublayerTransform(layer(), transform); setNeedsCommit(); }
+ CATransform3D sublayerTransform() const { return CACFLayerGetSublayerTransform(layer()); }
+
+ WKCACFLayer* superlayer() const;
+
+ void setTransform(const CATransform3D& transform) { CACFLayerSetTransform(layer(), transform); setNeedsCommit(); }
+ CATransform3D transform() const { return CACFLayerGetTransform(layer()); }
+
+ void setGeometryFlipped(bool flipped) { CACFLayerSetGeometryFlipped(layer(), flipped); setNeedsCommit(); }
+ bool geometryFlipped() const { return CACFLayerIsGeometryFlipped(layer()); }
+
+#ifndef NDEBUG
+ // Print the tree from the root. Also does consistency checks
+ void printTree() const;
+#endif
+
+protected:
+ WKCACFLayer(LayerType);
+
+ void setNeedsCommit();
+
+ CACFLayerRef layer() const { return m_layer.get(); }
+ // This should only be called from removeFromSuperlayer.
+ void removeSublayer(const WKCACFLayer*);
+
+ void checkLayerConsistency()
+ {
+#ifndef NDEBUG
+ internalCheckLayerConsistency();
+#endif
+ }
+
+ // Methods to be overridden for sublayer and rendering management
+ virtual WKCACFLayer* internalSublayerAtIndex(int) const;
+
+ // Returns the index of the passed layer in this layer's sublayers list
+ // or -1 if not found
+ virtual int internalIndexOfSublayer(const WKCACFLayer*);
+
+ virtual size_t internalSublayerCount() const;
+ virtual void internalInsertSublayer(PassRefPtr<WKCACFLayer>, size_t index);
+ virtual void internalRemoveAllSublayers();
+ virtual void internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >&);
+
+ virtual void internalSetNeedsDisplay(const CGRect* dirtyRect);
+
+#ifndef NDEBUG
+ virtual void internalCheckLayerConsistency();
+#endif
+
+#ifndef NDEBUG
+ // Print this layer and its children to the console
+ void printLayer(int indent) const;
+#endif
+
+private:
+ static void layoutSublayersProc(CACFLayerRef);
+
+ RetainPtr<CACFLayerRef> m_layer;
+ WKCACFLayerLayoutClient* m_layoutClient;
+ bool m_needsDisplayOnBoundsChange;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WKCACFLayer_h
diff --git a/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
new file mode 100644
index 0000000..4c5e61d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#ifndef NDEBUG
+#define D3D_DEBUG_INFO
+#endif
+
+#include "WKCACFLayerRenderer.h"
+
+#include "PlatformCALayer.h"
+#include "WKCACFContextFlusher.h"
+#include "WebCoreInstanceHandle.h"
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <limits.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/HashMap.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/StdLibExtras.h>
+#include <d3d9.h>
+#include <d3dx9.h>
+
+using namespace std;
+
+#pragma comment(lib, "d3d9")
+#pragma comment(lib, "d3dx9")
+#ifdef DEBUG_ALL
+#pragma comment(lib, "QuartzCore_debug")
+#else
+#pragma comment(lib, "QuartzCore")
+#endif
+
+static IDirect3D9* s_d3d = 0;
+static IDirect3D9* d3d()
+{
+ if (s_d3d)
+ return s_d3d;
+
+ if (!LoadLibrary(TEXT("d3d9.dll")))
+ return 0;
+
+ s_d3d = Direct3DCreate9(D3D_SDK_VERSION);
+
+ return s_d3d;
+}
+
+inline static CGRect winRectToCGRect(RECT rc)
+{
+ return CGRectMake(rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top));
+}
+
+inline static CGRect winRectToCGRect(RECT rc, RECT relativeToRect)
+{
+ return CGRectMake(rc.left, (relativeToRect.bottom-rc.bottom), (rc.right - rc.left), (rc.bottom - rc.top));
+}
+
+namespace WebCore {
+
+static D3DPRESENT_PARAMETERS initialPresentationParameters()
+{
+ D3DPRESENT_PARAMETERS parameters = {0};
+ parameters.Windowed = TRUE;
+ parameters.SwapEffect = D3DSWAPEFFECT_COPY;
+ parameters.BackBufferCount = 1;
+ parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
+ parameters.MultiSampleType = D3DMULTISAMPLE_NONE;
+
+ return parameters;
+}
+
+// FIXME: <rdar://6507851> Share this code with CoreAnimation.
+static bool hardwareCapabilitiesIndicateCoreAnimationSupport(const D3DCAPS9& caps)
+{
+ // CoreAnimation needs two or more texture units.
+ if (caps.MaxTextureBlendStages < 2)
+ return false;
+
+ // CoreAnimation needs non-power-of-two textures.
+ if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && !(caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL))
+ return false;
+
+ // CoreAnimation needs vertex shader 2.0 or greater.
+ if (D3DSHADER_VERSION_MAJOR(caps.VertexShaderVersion) < 2)
+ return false;
+
+ // CoreAnimation needs pixel shader 2.0 or greater.
+ if (D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion) < 2)
+ return false;
+
+ return true;
+}
+
+bool WKCACFLayerRenderer::acceleratedCompositingAvailable()
+{
+ static bool available;
+ static bool tested;
+
+ if (tested)
+ return available;
+
+ tested = true;
+
+ // Initialize available to true since this function will be called from a
+ // propagation within createRenderer(). We want to be able to return true
+ // when that happens so that the test can continue.
+ available = true;
+
+ HMODULE library = LoadLibrary(TEXT("d3d9.dll"));
+ if (!library) {
+ available = false;
+ return available;
+ }
+
+ FreeLibrary(library);
+#ifdef DEBUG_ALL
+ library = LoadLibrary(TEXT("QuartzCore_debug.dll"));
+#else
+ library = LoadLibrary(TEXT("QuartzCore.dll"));
+#endif
+ if (!library) {
+ available = false;
+ return available;
+ }
+
+ FreeLibrary(library);
+
+ // Make a dummy HWND.
+ WNDCLASSEX wcex = { 0 };
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = DefWindowProc;
+ wcex.hInstance = WebCore::instanceHandle();
+ wcex.lpszClassName = L"CoreAnimationTesterWindowClass";
+ ::RegisterClassEx(&wcex);
+ HWND testWindow = ::CreateWindow(L"CoreAnimationTesterWindowClass", L"CoreAnimationTesterWindow", WS_POPUP, -500, -500, 0, 0, 0, 0, 0, 0);
+
+ if (!testWindow) {
+ available = false;
+ return available;
+ }
+
+ OwnPtr<WKCACFLayerRenderer> testLayerRenderer = WKCACFLayerRenderer::create(0);
+ testLayerRenderer->setHostWindow(testWindow);
+ available = testLayerRenderer->createRenderer();
+ ::DestroyWindow(testWindow);
+
+ return available;
+}
+
+PassOwnPtr<WKCACFLayerRenderer> WKCACFLayerRenderer::create(WKCACFLayerRendererClient* client)
+{
+ if (!acceleratedCompositingAvailable())
+ return 0;
+ return new WKCACFLayerRenderer(client);
+}
+
+WKCACFLayerRenderer::WKCACFLayerRenderer(WKCACFLayerRendererClient* client)
+ : m_client(client)
+ , m_mightBeAbleToCreateDeviceLater(true)
+ , m_rootLayer(PlatformCALayer::create(PlatformCALayer::LayerTypeRootLayer, 0))
+ , m_context(wkCACFContextCreate())
+ , m_hostWindow(0)
+ , m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired)
+ , m_backingStoreDirty(false)
+ , m_mustResetLostDeviceBeforeRendering(false)
+ , m_syncLayerChanges(false)
+{
+ // Point the CACFContext to this
+ wkCACFContextSetUserData(m_context, this);
+
+ // Under the root layer, we have a clipping layer to clip the content,
+ // that contains a scroll layer that we use for scrolling the content.
+ // The root layer is the size of the client area of the window.
+ // The clipping layer is the size of the WebView client area (window less the scrollbars).
+ // The scroll layer is the size of the root child layer.
+ // Resizing the window will change the bounds of the rootLayer and the clip layer and will not
+ // cause any repositioning.
+ // Scrolling will affect only the position of the scroll layer without affecting the bounds.
+
+ m_rootLayer->setName("WKCACFLayerRenderer rootLayer");
+ m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0));
+ m_rootLayer->setGeometryFlipped(true);
+
+#ifndef NDEBUG
+ CGColorRef debugColor = CGColorCreateGenericRGB(1, 0, 0, 0.8);
+ m_rootLayer->setBackgroundColor(debugColor);
+ CGColorRelease(debugColor);
+#endif
+
+ if (m_context)
+ wkCACFContextSetLayer(m_context, m_rootLayer->platformLayer());
+
+#ifndef NDEBUG
+ char* printTreeFlag = getenv("CA_PRINT_TREE");
+ m_printTree = printTreeFlag && atoi(printTreeFlag);
+#endif
+}
+
+WKCACFLayerRenderer::~WKCACFLayerRenderer()
+{
+ destroyRenderer();
+ wkCACFContextDestroy(m_context);
+}
+
+PlatformCALayer* WKCACFLayerRenderer::rootLayer() const
+{
+ return m_rootLayer.get();
+}
+
+void WKCACFLayerRenderer::addPendingAnimatedLayer(PassRefPtr<PlatformCALayer> layer)
+{
+ m_pendingAnimatedLayers.add(layer);
+}
+
+void WKCACFLayerRenderer::setRootContents(CGImageRef image)
+{
+ ASSERT(m_rootLayer);
+ m_rootLayer->setContents(image);
+ renderSoon();
+}
+
+void WKCACFLayerRenderer::setRootContentsAndDisplay(CGImageRef image)
+{
+ ASSERT(m_rootLayer);
+ m_rootLayer->setContents(image);
+ paint();
+}
+
+void WKCACFLayerRenderer::setRootChildLayer(PlatformCALayer* layer)
+{
+ m_rootLayer->removeAllSublayers();
+ m_rootChildLayer = layer;
+ if (m_rootChildLayer)
+ m_rootLayer->appendSublayer(m_rootChildLayer.get());
+}
+
+void WKCACFLayerRenderer::layerTreeDidChange()
+{
+ WKCACFContextFlusher::shared().addContext(m_context);
+ renderSoon();
+}
+
+void WKCACFLayerRenderer::setNeedsDisplay(bool sync)
+{
+ if (!m_syncLayerChanges && sync)
+ m_syncLayerChanges = true;
+
+ ASSERT(m_rootLayer);
+ m_rootLayer->setNeedsDisplay(0);
+ renderSoon();
+}
+
+bool WKCACFLayerRenderer::createRenderer()
+{
+ if (m_d3dDevice || !m_mightBeAbleToCreateDeviceLater)
+ return m_d3dDevice;
+
+ m_mightBeAbleToCreateDeviceLater = false;
+ D3DPRESENT_PARAMETERS parameters = initialPresentationParameters();
+
+ if (!d3d() || !::IsWindow(m_hostWindow))
+ return false;
+
+ // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the
+ // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero
+ // size eventually, and then the backbuffer size will get reset.
+ RECT rect;
+ GetClientRect(m_hostWindow, &rect);
+
+ if (rect.left-rect.right == 0 || rect.bottom-rect.top == 0) {
+ parameters.BackBufferWidth = 1;
+ parameters.BackBufferHeight = 1;
+ }
+
+ D3DCAPS9 d3dCaps;
+ if (FAILED(d3d()->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps)))
+ return false;
+
+ DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE;
+ if ((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) && d3dCaps.VertexProcessingCaps)
+ behaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
+ else
+ behaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
+
+ COMPtr<IDirect3DDevice9> device;
+ if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, behaviorFlags, &parameters, &device))) {
+ // In certain situations (e.g., shortly after waking from sleep), Direct3DCreate9() will
+ // return an IDirect3D9 for which IDirect3D9::CreateDevice will always fail. In case we
+ // have one of these bad IDirect3D9s, get rid of it so we'll fetch a new one the next time
+ // we want to call CreateDevice.
+ s_d3d->Release();
+ s_d3d = 0;
+
+ // Even if we don't have a bad IDirect3D9, in certain situations (e.g., shortly after
+ // waking from sleep), CreateDevice will fail, but will later succeed if called again.
+ m_mightBeAbleToCreateDeviceLater = true;
+
+ return false;
+ }
+
+ // Now that we've created the IDirect3DDevice9 based on the capabilities we
+ // got from the IDirect3D9 global object, we requery the device for its
+ // actual capabilities. The capabilities returned by the device can
+ // sometimes be more complete, for example when using software vertex
+ // processing.
+ D3DCAPS9 deviceCaps;
+ if (FAILED(device->GetDeviceCaps(&deviceCaps)))
+ return false;
+
+ if (!hardwareCapabilitiesIndicateCoreAnimationSupport(deviceCaps))
+ return false;
+
+ m_d3dDevice = device;
+
+ initD3DGeometry();
+
+ wkCACFContextInitializeD3DDevice(m_context, m_d3dDevice.get());
+
+ if (IsWindow(m_hostWindow))
+ m_rootLayer->setBounds(bounds());
+
+ return true;
+}
+
+void WKCACFLayerRenderer::destroyRenderer()
+{
+ wkCACFContextSetLayer(m_context, m_rootLayer->platformLayer());
+
+ m_d3dDevice = 0;
+ if (s_d3d)
+ s_d3d->Release();
+
+ s_d3d = 0;
+ m_rootLayer = 0;
+ m_rootChildLayer = 0;
+
+ m_mightBeAbleToCreateDeviceLater = true;
+}
+
+void WKCACFLayerRenderer::resize()
+{
+ if (!m_d3dDevice)
+ return;
+
+ // Resetting the device might fail here. But that's OK, because if it does it we will attempt to
+ // reset the device the next time we try to render.
+ resetDevice(ChangedWindowSize);
+
+ if (m_rootLayer) {
+ m_rootLayer->setBounds(bounds());
+ WKCACFContextFlusher::shared().flushAllContexts();
+ }
+}
+
+static void getDirtyRects(HWND window, Vector<CGRect>& outRects)
+{
+ ASSERT_ARG(outRects, outRects.isEmpty());
+
+ RECT clientRect;
+ if (!GetClientRect(window, &clientRect))
+ return;
+
+ OwnPtr<HRGN> region(CreateRectRgn(0, 0, 0, 0));
+ int regionType = GetUpdateRgn(window, region.get(), false);
+ if (regionType != COMPLEXREGION) {
+ RECT dirtyRect;
+ if (GetUpdateRect(window, &dirtyRect, false))
+ outRects.append(winRectToCGRect(dirtyRect, clientRect));
+ return;
+ }
+
+ DWORD dataSize = GetRegionData(region.get(), 0, 0);
+ OwnArrayPtr<unsigned char> regionDataBuffer(new unsigned char[dataSize]);
+ RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get());
+ if (!GetRegionData(region.get(), dataSize, regionData))
+ return;
+
+ outRects.resize(regionData->rdh.nCount);
+
+ RECT* rect = reinterpret_cast<RECT*>(regionData->Buffer);
+ for (size_t i = 0; i < outRects.size(); ++i, ++rect)
+ outRects[i] = winRectToCGRect(*rect, clientRect);
+}
+
+void WKCACFLayerRenderer::renderTimerFired(Timer<WKCACFLayerRenderer>*)
+{
+ paint();
+}
+
+void WKCACFLayerRenderer::paint()
+{
+ createRenderer();
+ if (!m_d3dDevice) {
+ if (m_mightBeAbleToCreateDeviceLater)
+ renderSoon();
+ return;
+ }
+
+ if (m_backingStoreDirty) {
+ // If the backing store is still dirty when we are about to draw the
+ // composited content, we need to force the window to paint into the
+ // backing store. The paint will only paint the dirty region that
+ // if being tracked in WebView.
+ UpdateWindow(m_hostWindow);
+ return;
+ }
+
+ Vector<CGRect> dirtyRects;
+ getDirtyRects(m_hostWindow, dirtyRects);
+ render(dirtyRects);
+}
+
+void WKCACFLayerRenderer::render(const Vector<CGRect>& windowDirtyRects)
+{
+ ASSERT(m_d3dDevice);
+
+ if (m_mustResetLostDeviceBeforeRendering && !resetDevice(LostDevice)) {
+ // We can't reset the device right now. Try again soon.
+ renderSoon();
+ return;
+ }
+
+ if (m_client && !m_client->shouldRender()) {
+ renderSoon();
+ return;
+ }
+
+ // Sync the layer if needed
+ if (m_syncLayerChanges) {
+ m_client->syncCompositingState();
+ m_syncLayerChanges = false;
+ }
+
+ // Flush the root layer to the render tree.
+ wkCACFContextFlush(m_context);
+
+ // All pending animations will have been started with the flush. Fire the animationStarted calls
+ double currentTime = WTF::currentTime();
+ double currentMediaTime = CACurrentMediaTime();
+ double t = currentTime + wkCACFContextGetLastCommitTime(m_context) - currentMediaTime;
+ ASSERT(t <= currentTime);
+
+ HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end();
+ for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it) {
+ PlatformCALayerClient* owner = (*it)->owner();
+ owner->platformCALayerAnimationStarted(t);
+ }
+
+ m_pendingAnimatedLayers.clear();
+
+ CGRect bounds = this->bounds();
+
+ // Give the renderer some space to use. This needs to be valid until the
+ // wkCACFContextFinishUpdate() call below.
+ char space[4096];
+ if (!wkCACFContextBeginUpdate(m_context, space, sizeof(space), currentMediaTime, bounds, windowDirtyRects.data(), windowDirtyRects.size()))
+ return;
+
+ HRESULT err = S_OK;
+ CFTimeInterval timeToNextRender = numeric_limits<CFTimeInterval>::infinity();
+
+ do {
+ // FIXME: don't need to clear dirty region if layer tree is opaque.
+
+ WKCACFUpdateRectEnumerator* e = wkCACFContextCopyUpdateRectEnumerator(m_context);
+ if (!e)
+ break;
+
+ Vector<D3DRECT, 64> rects;
+ for (const CGRect* r = wkCACFUpdateRectEnumeratorNextRect(e); r; r = wkCACFUpdateRectEnumeratorNextRect(e)) {
+ D3DRECT rect;
+ rect.x1 = r->origin.x;
+ rect.x2 = rect.x1 + r->size.width;
+ rect.y1 = bounds.origin.y + bounds.size.height - (r->origin.y + r->size.height);
+ rect.y2 = rect.y1 + r->size.height;
+
+ rects.append(rect);
+ }
+ wkCACFUpdateRectEnumeratorRelease(e);
+
+ timeToNextRender = wkCACFContextGetNextUpdateTime(m_context);
+
+ if (rects.isEmpty())
+ break;
+
+ m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0);
+
+ m_d3dDevice->BeginScene();
+ wkCACFContextRenderUpdate(m_context);
+ m_d3dDevice->EndScene();
+
+ err = m_d3dDevice->Present(0, 0, 0, 0);
+
+ if (err == D3DERR_DEVICELOST) {
+ wkCACFContextAddUpdateRect(m_context, bounds);
+ if (!resetDevice(LostDevice)) {
+ // We can't reset the device right now. Try again soon.
+ renderSoon();
+ return;
+ }
+ }
+ } while (err == D3DERR_DEVICELOST);
+
+ wkCACFContextFinishUpdate(m_context);
+
+#ifndef NDEBUG
+ if (m_printTree)
+ m_rootLayer->printTree();
+#endif
+
+ // If timeToNextRender is not infinity, it means animations are running, so queue up to render again
+ if (timeToNextRender != numeric_limits<CFTimeInterval>::infinity())
+ renderSoon();
+}
+
+void WKCACFLayerRenderer::renderSoon()
+{
+ if (!m_renderTimer.isActive())
+ m_renderTimer.startOneShot(0);
+}
+
+CGRect WKCACFLayerRenderer::bounds() const
+{
+ RECT clientRect;
+ GetClientRect(m_hostWindow, &clientRect);
+
+ return winRectToCGRect(clientRect);
+}
+
+void WKCACFLayerRenderer::initD3DGeometry()
+{
+ ASSERT(m_d3dDevice);
+
+ CGRect bounds = this->bounds();
+
+ float x0 = bounds.origin.x;
+ float y0 = bounds.origin.y;
+ float x1 = x0 + bounds.size.width;
+ float y1 = y0 + bounds.size.height;
+
+ D3DXMATRIXA16 projection;
+ D3DXMatrixOrthoOffCenterRH(&projection, x0, x1, y0, y1, -1.0f, 1.0f);
+
+ m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection);
+}
+
+bool WKCACFLayerRenderer::resetDevice(ResetReason reason)
+{
+ ASSERT(m_d3dDevice);
+ ASSERT(m_context);
+
+ HRESULT hr = m_d3dDevice->TestCooperativeLevel();
+
+ if (hr == D3DERR_DEVICELOST || hr == D3DERR_DRIVERINTERNALERROR) {
+ // The device cannot be reset at this time. Try again soon.
+ m_mustResetLostDeviceBeforeRendering = true;
+ return false;
+ }
+
+ m_mustResetLostDeviceBeforeRendering = false;
+
+ if (reason == LostDevice && hr == D3D_OK) {
+ // The device wasn't lost after all.
+ return true;
+ }
+
+ // We can reset the device.
+
+ // We have to release the context's D3D resrouces whenever we reset the IDirect3DDevice9 in order to
+ // destroy any D3DPOOL_DEFAULT resources that Core Animation has allocated (e.g., textures used
+ // for mask layers). See <http://msdn.microsoft.com/en-us/library/bb174425(v=VS.85).aspx>.
+ wkCACFContextReleaseD3DResources(m_context);
+
+ D3DPRESENT_PARAMETERS parameters = initialPresentationParameters();
+ hr = m_d3dDevice->Reset(&parameters);
+
+ // TestCooperativeLevel told us the device may be reset now, so we should
+ // not be told here that the device is lost.
+ ASSERT(hr != D3DERR_DEVICELOST);
+
+ initD3DGeometry();
+
+ return true;
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
new file mode 100644
index 0000000..aff1f83
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 WKCACFLayerRenderer_h
+#define WKCACFLayerRenderer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "COMPtr.h"
+#include "Timer.h"
+
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+#include <CoreGraphics/CGGeometry.h>
+
+interface IDirect3DDevice9;
+struct WKCACFContext;
+
+typedef struct CGImage* CGImageRef;
+
+namespace WebCore {
+
+class PlatformCALayer;
+
+class WKCACFLayerRendererClient {
+public:
+ virtual ~WKCACFLayerRendererClient() { }
+ virtual bool shouldRender() const = 0;
+ virtual void animationsStarted(CFTimeInterval) { }
+ virtual void syncCompositingState() { }
+};
+
+// FIXME: Currently there is a WKCACFLayerRenderer for each WebView and each
+// has its own CARenderOGLContext and Direct3DDevice9, which is inefficient.
+// (https://bugs.webkit.org/show_bug.cgi?id=31855)
+class WKCACFLayerRenderer : public Noncopyable {
+ friend PlatformCALayer;
+
+public:
+ static PassOwnPtr<WKCACFLayerRenderer> create(WKCACFLayerRendererClient*);
+ ~WKCACFLayerRenderer();
+
+ static bool acceleratedCompositingAvailable();
+
+ void setRootContents(CGImageRef);
+ void setRootContentsAndDisplay(CGImageRef);
+ void setRootChildLayer(PlatformCALayer*);
+ void layerTreeDidChange();
+ void setNeedsDisplay(bool sync = false);
+ void setHostWindow(HWND window) { m_hostWindow = window; }
+ void setBackingStoreDirty(bool dirty) { m_backingStoreDirty = dirty; }
+ bool createRenderer();
+ void destroyRenderer();
+ void resize();
+ void renderSoon();
+
+protected:
+ PlatformCALayer* rootLayer() const;
+ void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>);
+
+private:
+ WKCACFLayerRenderer(WKCACFLayerRendererClient*);
+
+ void renderTimerFired(Timer<WKCACFLayerRenderer>*);
+
+ CGRect bounds() const;
+
+ void initD3DGeometry();
+
+ // Call this when the device window has changed size or when IDirect3DDevice9::Present returns
+ // D3DERR_DEVICELOST. Returns true if the device was recovered, false if rendering must be
+ // aborted and reattempted soon.
+ enum ResetReason { ChangedWindowSize, LostDevice };
+ bool resetDevice(ResetReason);
+
+ void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>());
+ void paint();
+
+ WKCACFLayerRendererClient* m_client;
+ bool m_mightBeAbleToCreateDeviceLater;
+ COMPtr<IDirect3DDevice9> m_d3dDevice;
+ RefPtr<PlatformCALayer> m_rootLayer;
+ RefPtr<PlatformCALayer> m_rootChildLayer;
+ WKCACFContext* m_context;
+ HWND m_hostWindow;
+ Timer<WKCACFLayerRenderer> m_renderTimer;
+ bool m_backingStoreDirty;
+ bool m_mustResetLostDeviceBeforeRendering;
+ bool m_syncLayerChanges;
+ HashSet<RefPtr<PlatformCALayer> > m_pendingAnimatedLayers;
+
+#ifndef NDEBUG
+ bool m_printTree;
+#endif
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WKCACFLayerRenderer_h
diff --git a/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp b/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp
new file mode 100644
index 0000000..c2a178b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WKCAImageQueue.h"
+
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+class WKCAImageQueuePrivate {
+public:
+ RetainPtr<CAImageQueueRef> m_imageQueue;
+};
+
+static CAImageQueueRef WKCAImageQueueRetain(CAImageQueueRef iq)
+{
+ if (iq)
+ return (CAImageQueueRef)CFRetain(iq);
+ return 0;
+}
+
+static void WKCAImageQueueRelease(CAImageQueueRef iq)
+{
+ if (iq)
+ CFRelease(iq);
+}
+
+WKCAImageQueue::WKCAImageQueue(uint32_t width, uint32_t height, uint32_t capacity)
+ : m_private(new WKCAImageQueuePrivate())
+{
+ m_private->m_imageQueue.adoptCF(wkCAImageQueueCreate(width, height, capacity));
+}
+
+WKCAImageQueue::WKCAImageQueue(const WKCAImageQueue& o)
+ : m_private(new WKCAImageQueuePrivate())
+{
+ m_private->m_imageQueue = o.m_private->m_imageQueue;
+}
+
+WKCAImageQueue::~WKCAImageQueue(void)
+{
+}
+
+WKCAImageQueue& WKCAImageQueue::operator=(const WKCAImageQueue& o)
+{
+ m_private->m_imageQueue = o.m_private->m_imageQueue;
+ return *this;
+}
+
+size_t WKCAImageQueue::collect()
+{
+ return wkCAImageQueueCollect(m_private->m_imageQueue.get());
+}
+
+bool WKCAImageQueue::insertImage(double t, unsigned int type, uint64_t id, uint32_t flags, ReleaseCallback release, void* info)
+{
+ return wkCAImageQueueInsertImage(m_private->m_imageQueue.get(), t, type, id, flags, release, info);
+}
+
+uint64_t WKCAImageQueue::registerPixelBuffer(void *data, size_t data_size, size_t rowbytes, size_t width, size_t height, uint32_t pixel_format, CFDictionaryRef attachments, uint32_t flags)
+{
+ return wkCAImageQueueRegisterPixelBuffer(m_private->m_imageQueue.get(), data, data_size, rowbytes, width, height, pixel_format, attachments, flags);
+}
+
+void WKCAImageQueue::setFlags(uint32_t mask, uint32_t flags)
+{
+ wkCAImageQueueSetFlags(m_private->m_imageQueue.get(), mask, flags);
+}
+
+CFTypeRef WKCAImageQueue::get()
+{
+ return m_private->m_imageQueue.get();
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/WKCAImageQueue.h b/Source/WebCore/platform/graphics/win/WKCAImageQueue.h
new file mode 100644
index 0000000..3d25b48
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCAImageQueue.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 WKCAImageQueue_h
+#define WKCAImageQueue_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+typedef const void * CFTypeRef;
+typedef const struct __CFDictionary * CFDictionaryRef;
+
+#include <stdint.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class WKCAImageQueuePrivate;
+
+class WKCAImageQueue {
+public:
+ enum Flags {
+ Async = 1U << 0,
+ Fill = 1U << 1,
+ Protected = 1U << 2,
+ UseCleanAperture = 1U << 3,
+ UseAspectRatio = 1U << 4,
+ LowQualityColor = 1U << 5,
+ };
+
+ enum ImageType {
+ Nil = 1,
+ Surface,
+ Buffer,
+ IOSurface,
+ };
+
+ enum ImageFlags {
+ Opaque = 1U << 0,
+ Flush = 1U << 1,
+ WillFlush = 1U << 2,
+ Flipped = 1U << 3,
+ WaitGPU = 1U << 4,
+ };
+
+ typedef void (*ReleaseCallback)(unsigned int type, uint64_t id, void* info);
+
+ WKCAImageQueue(uint32_t width, uint32_t height, uint32_t capacity);
+ ~WKCAImageQueue(void);
+
+ size_t collect();
+
+ bool insertImage(double t, unsigned int type, uint64_t id, uint32_t flags, ReleaseCallback release, void* info);
+ uint64_t registerPixelBuffer(void *data, size_t data_size, size_t rowbytes, size_t width, size_t height, uint32_t pixel_format, CFDictionaryRef attachments, uint32_t flags);
+
+ uint32_t flags() const;
+ void setFlags(uint32_t mask, uint32_t flags);
+
+ CFTypeRef get();
+
+private:
+ WKCAImageQueue(const WKCAImageQueue&);
+ WKCAImageQueue& operator=(const WKCAImageQueue&);
+ OwnPtr<WKCAImageQueuePrivate> m_private;
+};
+
+}
+
+#endif
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/WebLayer.cpp b/Source/WebCore/platform/graphics/win/WebLayer.cpp
new file mode 100644
index 0000000..ecda294
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WebLayer.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WebLayer.h"
+
+#include "Font.h"
+#include "GraphicsLayer.h"
+
+namespace WebCore {
+
+using namespace std;
+
+void WebLayer::internalSetNeedsDisplay(const CGRect* dirtyRect)
+{
+ if (m_owner) {
+ if (m_owner->showRepaintCounter()) {
+ CGRect layerBounds = bounds();
+ CGRect repaintCounterRect = layerBounds;
+ // We assume a maximum of 4 digits and a font size of 18.
+ repaintCounterRect.size.width = 80;
+ repaintCounterRect.size.height = 22;
+ if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown)
+ repaintCounterRect.origin.y = layerBounds.size.height - (layerBounds.origin.y + repaintCounterRect.size.height);
+ WKCACFLayer::internalSetNeedsDisplay(&repaintCounterRect);
+ }
+ if (dirtyRect && m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
+ CGRect flippedDirtyRect = *dirtyRect;
+ flippedDirtyRect.origin.y = bounds().size.height - (flippedDirtyRect.origin.y + flippedDirtyRect.size.height);
+ WKCACFLayer::internalSetNeedsDisplay(&flippedDirtyRect);
+ return;
+ }
+ }
+
+ WKCACFLayer::internalSetNeedsDisplay(dirtyRect);
+}
+
+void WebLayer::drawInContext(PlatformGraphicsContext* context)
+{
+ if (!m_owner)
+ return;
+
+ CGContextSaveGState(context);
+
+ CGRect layerBounds = bounds();
+ if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
+ CGContextScaleCTM(context, 1, -1);
+ CGContextTranslateCTM(context, 0, -layerBounds.size.height);
+ }
+
+ if (m_owner->client()) {
+ GraphicsContext graphicsContext(context);
+
+ // It's important to get the clip from the context, because it may be significantly
+ // smaller than the layer bounds (e.g. tiled layers)
+ CGRect clipBounds = CGContextGetClipBoundingBox(context);
+ IntRect clip(enclosingIntRect(clipBounds));
+ m_owner->paintGraphicsLayerContents(graphicsContext, clip);
+ }
+#ifndef NDEBUG
+ else {
+ ASSERT_NOT_REACHED();
+
+ // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
+ // so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
+ CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
+ CGContextFillRect(context, layerBounds);
+ }
+#endif
+
+ if (m_owner->showRepaintCounter()) {
+ String text = String::number(m_owner->incrementRepaintCount());
+
+ CGContextSaveGState(context);
+
+ // Make the background of the counter the same as the border color,
+ // unless there is no border, then make it red
+ float borderWidth = CACFLayerGetBorderWidth(layer());
+ if (borderWidth > 0) {
+ CGColorRef borderColor = CACFLayerGetBorderColor(layer());
+ const CGFloat* colors = CGColorGetComponents(borderColor);
+ CGContextSetRGBFillColor(context, colors[0], colors[1], colors[2], colors[3]);
+ } else
+ CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
+
+ CGRect aBounds = layerBounds;
+
+ aBounds.size.width = 10 + 10 * text.length();
+ aBounds.size.height = 22;
+ CGContextFillRect(context, aBounds);
+
+ FontDescription desc;
+
+ NONCLIENTMETRICS metrics;
+ metrics.cbSize = sizeof(metrics);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
+ FontFamily family;
+ family.setFamily(metrics.lfSmCaptionFont.lfFaceName);
+ desc.setFamily(family);
+
+ desc.setComputedSize(18);
+
+ Font font = Font(desc, 0, 0);
+ font.update(0);
+
+ GraphicsContext cg(context);
+ cg.setFillColor(Color::black, ColorSpaceDeviceRGB);
+ cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 5, aBounds.origin.y + 17));
+
+ CGContextRestoreGState(context);
+ }
+
+ CGContextRestoreGState(context);
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WebLayer.h b/Source/WebCore/platform/graphics/win/WebLayer.h
new file mode 100644
index 0000000..8dab5cc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WebLayer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 WebLayer_h
+#define WebLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WKCACFLayer.h"
+
+namespace WebCore {
+
+class GraphicsLayer;
+
+class WebLayer : public WKCACFLayer {
+public:
+ static PassRefPtr<WKCACFLayer> create(LayerType layerType, GraphicsLayer* owner)
+ {
+ return adoptRef(new WebLayer(layerType, owner));
+ }
+
+ virtual void drawInContext(PlatformGraphicsContext*);
+
+protected:
+ WebLayer(LayerType layerType, GraphicsLayer* owner)
+ : WKCACFLayer(layerType)
+ , m_owner(owner)
+ {
+ }
+
+ virtual void internalSetNeedsDisplay(const CGRect* dirtyRect);
+
+ GraphicsLayer* m_owner;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebLayer_h
diff --git a/Source/WebCore/platform/graphics/win/WebTiledLayer.cpp b/Source/WebCore/platform/graphics/win/WebTiledLayer.cpp
new file mode 100644
index 0000000..4705033
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WebTiledLayer.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WebTiledLayer.h"
+
+#include "GraphicsLayer.h"
+#include "WKCACFLayerRenderer.h"
+
+namespace WebCore {
+
+using namespace std;
+
+#ifndef NDEBUG
+void WebTiledLayer::internalCheckLayerConsistency()
+{
+ WKCACFLayer::internalCheckLayerConsistency();
+
+ // Additionally make sure the tiled parent is valid
+ CFArrayRef sublayers = CACFLayerGetSublayers(layer());
+
+ // Make sure there is a tile parent and it is the same as we remember
+ size_t n = CFArrayGetCount(sublayers);
+ ASSERT(n > 0);
+ const void* element = CFArrayGetValueAtIndex(sublayers, 0);
+ ASSERT(m_tileParent.get() == element);
+
+ // Make sure the tile parent doesn't have user data. If it does, it is probably
+ // a WKCACFLayer in the wrong place.
+ ASSERT(!layer(m_tileParent.get()));
+}
+#endif
+
+void WebTiledLayer::tileDisplayCallback(CACFLayerRef layer, CGContextRef context)
+{
+ static_cast<WebTiledLayer*>(CACFLayerGetUserData(layer))->drawTile(layer, context);
+}
+
+PassRefPtr<WebTiledLayer> WebTiledLayer::create(const CGSize& tileSize, GraphicsLayer* owner)
+{
+ ASSERT(WKCACFLayerRenderer::acceleratedCompositingAvailable());
+ return adoptRef(new WebTiledLayer(tileSize, owner));
+}
+
+WebTiledLayer::WebTiledLayer(const CGSize& tileSize, GraphicsLayer* owner)
+ : WebLayer(WKCACFLayer::Layer, owner)
+ , m_tileSize(tileSize)
+ , m_constrainedSize(constrainedSize(bounds().size))
+{
+ // Tiled layers are placed in a child layer that is always the first child of the TiledLayer
+ m_tileParent.adoptCF(CACFLayerCreate(kCACFLayer));
+ CACFLayerInsertSublayer(layer(), m_tileParent.get(), 0);
+
+ updateTiles();
+}
+
+WebTiledLayer::~WebTiledLayer()
+{
+}
+
+void WebTiledLayer::setBounds(const CGRect& rect)
+{
+ if (CGRectEqualToRect(rect, bounds()))
+ return;
+
+ WebLayer::setBounds(rect);
+ m_constrainedSize = constrainedSize(rect.size);
+ updateTiles();
+}
+
+void WebTiledLayer::setFrame(const CGRect& rect)
+{
+ if (CGRectEqualToRect(rect, frame()))
+ return;
+
+ WebLayer::setFrame(rect);
+ updateTiles();
+}
+
+void WebTiledLayer::internalSetNeedsDisplay(const CGRect* dirtyRect)
+{
+ // FIXME: Only setNeedsDisplay for tiles that are currently visible
+ int numTileLayers = tileCount();
+ for (int i = 0; i < numTileLayers; ++i)
+ CACFLayerSetNeedsDisplay(tileAtIndex(i), dirtyRect);
+
+ if (m_owner->showRepaintCounter()) {
+ CGRect layerBounds = bounds();
+ CGRect indicatorRect = CGRectMake(layerBounds.origin.x, layerBounds.origin.y, 80, 25);
+ CACFLayerSetNeedsDisplay(tileAtIndex(0), &indicatorRect);
+ }
+}
+
+size_t WebTiledLayer::internalSublayerCount() const
+{
+ ASSERT(WebLayer::internalSublayerCount() > 0);
+
+ // Subtract 1 to account for the tile parent layer
+ return WebLayer::internalSublayerCount() - 1;
+}
+
+void WebTiledLayer::internalRemoveAllSublayers()
+{
+ // Restore the tile parent after removal
+ WebLayer::internalRemoveAllSublayers();
+ CACFLayerInsertSublayer(layer(), m_tileParent.get(), 0);
+}
+
+void WebTiledLayer::internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers)
+{
+ // Preserve the tile parent after set
+ WebLayer::internalSetSublayers(sublayers);
+ CACFLayerInsertSublayer(layer(), m_tileParent.get(), 0);
+}
+
+void WebTiledLayer::internalInsertSublayer(PassRefPtr<WKCACFLayer> layer, size_t index)
+{
+ // Add 1 to account for the tile parent layer
+ WebLayer::internalInsertSublayer(layer, index + 1);
+}
+
+WKCACFLayer* WebTiledLayer::internalSublayerAtIndex(int i) const
+{
+ // Add 1 to account for the tile parent layer
+ return WebLayer::internalSublayerAtIndex(i + 1);
+}
+
+int WebTiledLayer::internalIndexOfSublayer(const WKCACFLayer* layer)
+{
+ int i = WebLayer::internalIndexOfSublayer(layer);
+
+ // Add 1 to account for the tile parent layer (but be safe about it)
+ return (i > 0) ? i - 1 : -1;
+}
+
+CGSize WebTiledLayer::constrainedSize(const CGSize& size) const
+{
+ const int cMaxTileCount = 512;
+ const float cSqrtMaxTileCount = sqrtf(cMaxTileCount);
+
+ CGSize constrainedSize = size;
+
+ int tileColumns = ceilf(constrainedSize.width / m_tileSize.width);
+ int tileRows = ceilf(constrainedSize.height / m_tileSize.height);
+ int numTiles = tileColumns * tileRows;
+
+ // If number of tiles vertically or horizontally is < sqrt(cMaxTileCount)
+ // just shorten the longer dimension. Otherwise shorten both dimensions
+ // according to the ratio of width to height
+
+ if (numTiles > cMaxTileCount) {
+ if (tileRows < cSqrtMaxTileCount)
+ tileColumns = floorf(cMaxTileCount / tileRows);
+ else if (tileColumns < cSqrtMaxTileCount)
+ tileRows = floorf(cMaxTileCount / tileColumns);
+ else {
+ tileRows = ceilf(sqrtf(cMaxTileCount * constrainedSize.height / constrainedSize.width));
+ tileColumns = floorf(cMaxTileCount / tileRows);
+ }
+
+ constrainedSize.width = tileColumns * m_tileSize.width;
+ constrainedSize.height = tileRows * m_tileSize.height;
+ }
+
+ return constrainedSize;
+}
+
+void WebTiledLayer::addTile()
+{
+ RetainPtr<CACFLayerRef> newLayer(AdoptCF, CACFLayerCreate(kCACFLayer));
+ CACFLayerSetAnchorPoint(newLayer.get(), CGPointMake(0, 1));
+ CACFLayerSetUserData(newLayer.get(), this);
+ CACFLayerSetDisplayCallback(newLayer.get(), tileDisplayCallback);
+
+ CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
+ CACFLayerInsertSublayer(m_tileParent.get(), newLayer.get(), sublayers ? CFArrayGetCount(sublayers) : 0);
+
+ if (m_owner->showDebugBorders()) {
+ CGColorRef borderColor = CGColorCreateGenericRGB(0.5, 0, 0.5, 0.7);
+ CACFLayerSetBorderColor(newLayer.get(), borderColor);
+ CGColorRelease(borderColor);
+ CACFLayerSetBorderWidth(newLayer.get(), 2);
+ }
+}
+
+void WebTiledLayer::removeTile()
+{
+ CACFLayerRemoveFromSuperlayer(tileAtIndex(tileCount() - 1));
+}
+
+CACFLayerRef WebTiledLayer::tileAtIndex(int index)
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
+ if (!sublayers || index < 0 || index >= tileCount() )
+ return 0;
+
+ return static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index)));
+}
+
+int WebTiledLayer::tileCount() const
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
+ return sublayers ? CFArrayGetCount(sublayers) : 0;
+}
+
+void WebTiledLayer::updateTiles()
+{
+ // FIXME: In addition to redoing the number of tiles, we need to only render and have backing
+ // store for visible layers
+ int numTilesHorizontal = ceil(m_constrainedSize.width / m_tileSize.width);
+ int numTilesVertical = ceil(m_constrainedSize.height / m_tileSize.height);
+ int numTilesTotal = numTilesHorizontal * numTilesVertical;
+
+ int numTilesToChange = numTilesTotal - tileCount();
+ if (numTilesToChange >= 0) {
+ // Add new tiles
+ for (int i = 0; i < numTilesToChange; ++i)
+ addTile();
+ } else {
+ // Remove old tiles
+ numTilesToChange = -numTilesToChange;
+ for (int i = 0; i < numTilesToChange; ++i)
+ removeTile();
+ }
+
+ // Set coordinates for all tiles
+ CFArrayRef tileArray = CACFLayerGetSublayers(m_tileParent.get());
+
+ for (int i = 0; i < numTilesHorizontal; ++i) {
+ for (int j = 0; j < numTilesVertical; ++j) {
+ CACFLayerRef tile = static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(tileArray, i * numTilesVertical + j)));
+ CACFLayerSetPosition(tile, CGPointMake(i * m_tileSize.width, j * m_tileSize.height));
+ int width = min(m_tileSize.width, m_constrainedSize.width - i * m_tileSize.width);
+ int height = min(m_tileSize.height, m_constrainedSize.height - j * m_tileSize.height);
+ CACFLayerSetBounds(tile, CGRectMake(i * m_tileSize.width, j * m_tileSize.height, width, height));
+
+ // Flip Y to compensate for the flipping that happens during render to match the CG context coordinate space
+ CATransform3D transform = CATransform3DMakeScale(1, -1, 1);
+ CATransform3DTranslate(transform, 0, height, 0);
+ CACFLayerSetTransform(tile, transform);
+
+#ifndef NDEBUG
+ String name = "Tile (" + String::number(i) + "," + String::number(j) + ")";
+ CACFLayerSetName(tile, RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get());
+#endif
+ }
+ }
+}
+
+void WebTiledLayer::drawTile(CACFLayerRef tile, CGContextRef context)
+{
+ CGPoint tilePosition = CACFLayerGetPosition(tile);
+ CGRect tileBounds = CACFLayerGetBounds(tile);
+
+ CGContextSaveGState(context);
+
+ // Transform context to be at the origin of the parent layer
+ CGContextTranslateCTM(context, -tilePosition.x, -tilePosition.y);
+
+ // Set the context clipping rectangle to the current tile
+ CGContextClipToRect(context, CGRectMake(tilePosition.x, tilePosition.y, tileBounds.size.width, tileBounds.size.height));
+
+ if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
+ // If the layer is rendering top-down, it will flip the coordinates in y. Tiled layers are
+ // already flipping, so we need to undo that here.
+ CGContextTranslateCTM(context, 0, bounds().size.height);
+ CGContextScaleCTM(context, 1, -1);
+ }
+
+ // Draw the tile
+ drawInContext(context);
+
+ CGContextRestoreGState(context);
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WebTiledLayer.h b/Source/WebCore/platform/graphics/win/WebTiledLayer.h
new file mode 100644
index 0000000..b8ae320
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WebTiledLayer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 WebTiledLayer_h
+#define WebTiledLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WebLayer.h"
+
+namespace WebCore {
+
+class WebTiledLayer : public WebLayer {
+public:
+ static PassRefPtr<WebTiledLayer> create(const CGSize& tileSize, GraphicsLayer* owner);
+
+ virtual ~WebTiledLayer();
+
+ virtual void setBounds(const CGRect&);
+ virtual void setFrame(const CGRect&);
+
+protected:
+ WebTiledLayer(const CGSize& tileSize, GraphicsLayer* owner);
+
+ // Overridden from WKCACFLayer
+ virtual WKCACFLayer* internalSublayerAtIndex(int) const;
+ virtual int internalIndexOfSublayer(const WKCACFLayer*);
+
+ virtual size_t internalSublayerCount() const;
+ virtual void internalInsertSublayer(PassRefPtr<WKCACFLayer>, size_t index);
+
+ virtual void internalRemoveAllSublayers();
+ virtual void internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >&);
+
+ virtual void internalSetNeedsDisplay(const CGRect* dirtyRect);
+
+#ifndef NDEBUG
+ virtual void internalCheckLayerConsistency();
+#endif
+
+private:
+ static void tileDisplayCallback(CACFLayerRef, CGContextRef);
+ void drawTile(CACFLayerRef, CGContextRef);
+
+ CGSize constrainedSize(const CGSize& size) const;
+
+ void addTile();
+ void removeTile();
+ CACFLayerRef tileAtIndex(int);
+ int tileCount() const;
+
+ void updateTiles();
+
+ CGSize m_tileSize;
+ CGSize m_constrainedSize;
+ RetainPtr<CACFLayerRef> m_tileParent;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebTiledLayer_h
diff --git a/Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h b/Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h
new file mode 100644
index 0000000..d8f538a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2010 Brent Fulgham <bfulgham@webkit.org>
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformDataCairoWin_h
+#define FontPlatformDataCairoWin_h
+
+#include "FontOrientation.h"
+#include "GlyphBuffer.h"
+#include "RefCountedGDIHandle.h"
+#include "StringImpl.h"
+#include <cairo-win32.h>
+#include <cairo.h>
+#include <wtf/Forward.h>
+
+typedef struct HFONT__* HFONT;
+
+namespace WebCore {
+
+class FontDescription;
+
+class FontPlatformData {
+public:
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_fontFace(0)
+ , m_useGDI(false)
+ , m_font(WTF::HashTableDeletedValue)
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+ { }
+
+ FontPlatformData()
+ : m_fontFace(0)
+ , m_useGDI(false)
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+ { }
+
+ FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI);
+ FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic);
+ FontPlatformData(float size, bool bold, bool italic);
+ FontPlatformData(const FontPlatformData&);
+ ~FontPlatformData();
+
+ HFONT hfont() const { return m_font->handle(); }
+ bool useGDI() const { return m_useGDI; }
+ cairo_font_face_t* fontFace() const { return m_fontFace; }
+
+ bool isFixedPitch();
+ float size() const { return m_size; }
+ void setSize(float size) { m_size = size; }
+ bool syntheticBold() const { return m_syntheticBold; }
+ bool syntheticOblique() const { return m_syntheticOblique; }
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+ cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
+
+ unsigned hash() const
+ {
+ return m_font->hash();
+ }
+
+ bool operator==(const FontPlatformData&) const;
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool isHashTableDeletedValue() const
+ {
+ return m_font.isHashTableDeletedValue();
+ }
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+private:
+ void platformDataInit(HFONT, float size, HDC, WCHAR* faceName);
+
+ RefPtr<RefCountedGDIHandle<HFONT> > m_font;
+ cairo_font_face_t* m_fontFace;
+ bool m_useGDI;
+ float m_size;
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+ cairo_scaled_font_t* m_scaledFont;
+};
+
+}
+
+#endif // FontPlatformDataCairoWin_h
diff --git a/Source/WebCore/platform/graphics/wince/ColorWinCE.cpp b/Source/WebCore/platform/graphics/wince/ColorWinCE.cpp
new file mode 100644
index 0000000..820b9d2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/ColorWinCE.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+Color focusRingColor()
+{
+ return Color(0, 0, 0);
+}
+
+void setFocusRingColorChangeFunction(void (*)())
+{
+ notImplemented();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/FontCacheWinCE.cpp b/Source/WebCore/platform/graphics/wince/FontCacheWinCE.cpp
new file mode 100644
index 0000000..ccfc063
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/FontCacheWinCE.cpp
@@ -0,0 +1,351 @@
+/*
+* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+* Copyright (C) 2007-2009 Torch Mobile, Inc.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. 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.
+* 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+*/
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "Font.h"
+#include "FontData.h"
+#include "SimpleFontData.h"
+#include "UnicodeRange.h"
+#include "wtf/OwnPtr.h"
+
+#include <windows.h>
+#include <mlang.h>
+
+namespace WebCore {
+
+extern HDC g_screenDC;
+
+static IMultiLanguage *multiLanguage = 0;
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+static IMLangFontLink2* langFontLink = 0;
+#else
+static IMLangFontLink* langFontLink = 0;
+#endif
+
+IMultiLanguage* FontCache::getMultiLanguageInterface()
+{
+ if (!multiLanguage)
+ CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&multiLanguage);
+
+ return multiLanguage;
+}
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+IMLangFontLink2* FontCache::getFontLinkInterface()
+#else
+IMLangFontLink* FontCache::getFontLinkInterface()
+#endif
+{
+ if (!langFontLink) {
+ if (IMultiLanguage* mli = getMultiLanguageInterface())
+ mli->QueryInterface(&langFontLink);
+ }
+
+ return langFontLink;
+}
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+static bool currentFontContainsCharacter(IMLangFontLink2* langFontLink, HDC hdc, UChar character)
+{
+ UINT unicodeRanges;
+ if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, 0))
+ return false;
+
+ static Vector<UNICODERANGE, 64> glyphsetBuffer;
+ glyphsetBuffer.resize(unicodeRanges);
+
+ if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, glyphsetBuffer.data()))
+ return false;
+
+ // FIXME: Change this to a binary search. (Yong Li: That's easy. But, is it guaranteed that the ranges are sorted?)
+ for (Vector<UNICODERANGE, 64>::const_iterator i = glyphsetBuffer.begin(); i != glyphsetBuffer.end(); ++i) {
+ if (i->wcTo >= character)
+ return i->wcFrom <= character;
+ }
+
+ return false;
+}
+#else
+static bool currentFontContainsCharacter(IMLangFontLink* langFontLink, HDC hdc, HFONT hfont, UChar character, const wchar_t* faceName)
+{
+ DWORD fontCodePages = 0, charCodePages = 0;
+ HRESULT result = langFontLink->GetFontCodePages(hdc, hfont, &fontCodePages);
+ if (result != S_OK)
+ return false;
+ result = langFontLink->GetCharCodePages(character, &charCodePages);
+ if (result != S_OK)
+ return false;
+
+ fontCodePages |= FontPlatformData::getKnownFontCodePages(faceName);
+ if (fontCodePages & charCodePages)
+ return true;
+
+ return false;
+}
+#endif
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0)
+{
+ HFONT mlangFont;
+ if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &mlangFont)))
+ return mlangFont;
+
+ return 0;
+}
+#else
+static HFONT createMLangFont(IMLangFontLink* langFontLink, HDC hdc, const FontPlatformData& refFont, DWORD codePageMask)
+{
+ HFONT mlangFont;
+ LRESULT result = langFontLink->MapFont(hdc, codePageMask, refFont.hfont(), &mlangFont);
+
+ return result == S_OK ? mlangFont : 0;
+}
+#endif
+
+static const Vector<DWORD, 4>& getCJKCodePageMasks()
+{
+ // The default order in which we look for a font for a CJK character. If the user's default code page is
+ // one of these, we will use it first.
+ static const UINT CJKCodePages[] = {
+ 932, /* Japanese */
+ 936, /* Simplified Chinese */
+ 950, /* Traditional Chinese */
+ 949 /* Korean */
+ };
+
+ static Vector<DWORD, 4> codePageMasks;
+ static bool initialized;
+ if (!initialized) {
+ initialized = true;
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
+#else
+ IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface();
+#endif
+ if (!langFontLink)
+ return codePageMasks;
+
+ UINT defaultCodePage;
+ DWORD defaultCodePageMask = 0;
+ if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage)))
+ langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask);
+
+ if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3])
+ codePageMasks.append(defaultCodePageMask);
+ for (unsigned i = 0; i < 4; ++i) {
+ if (defaultCodePage != CJKCodePages[i]) {
+ DWORD codePageMask;
+ langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask);
+ codePageMasks.append(codePageMask);
+ }
+ }
+ }
+ return codePageMasks;
+}
+
+
+struct TraitsInFamilyProcData {
+ TraitsInFamilyProcData(const AtomicString& familyName)
+ : m_familyName(familyName)
+ {
+ }
+
+ const AtomicString& m_familyName;
+ HashSet<unsigned> m_traitsMasks;
+};
+
+static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam);
+
+ unsigned traitsMask = 0;
+ traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask;
+ traitsMask |= FontVariantNormalMask;
+ LONG weight = FontPlatformData::adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName);
+ traitsMask |= weight == FW_THIN ? FontWeight100Mask :
+ weight == FW_EXTRALIGHT ? FontWeight200Mask :
+ weight == FW_LIGHT ? FontWeight300Mask :
+ weight == FW_NORMAL ? FontWeight400Mask :
+ weight == FW_MEDIUM ? FontWeight500Mask :
+ weight == FW_SEMIBOLD ? FontWeight600Mask :
+ weight == FW_BOLD ? FontWeight700Mask :
+ weight == FW_EXTRABOLD ? FontWeight800Mask :
+ FontWeight900Mask;
+ procData->m_traitsMasks.add(traitsMask);
+ return 1;
+}
+
+void FontCache::platformInit()
+{
+}
+
+void FontCache::comInitialize()
+{
+}
+
+void FontCache::comUninitialize()
+{
+ if (langFontLink) {
+ langFontLink->Release();
+ langFontLink = 0;
+ }
+ if (multiLanguage) {
+ multiLanguage->Release();
+ multiLanguage = 0;
+ }
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ String familyName;
+ WCHAR name[LF_FACESIZE];
+
+ UChar character = characters[0];
+ const FontPlatformData& origFont = font.primaryFont()->fontDataForCharacter(character)->platformData();
+ unsigned unicodeRange = findCharUnicodeRange(character);
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
+#else
+ if (IMLangFontLink* langFontLink = getFontLinkInterface()) {
+#endif
+ HGDIOBJ oldFont = GetCurrentObject(g_screenDC, OBJ_FONT);
+ HFONT hfont = 0;
+ DWORD codePages = 0;
+ UINT codePage = 0;
+ // Try MLang font linking first.
+ langFontLink->GetCharCodePages(character, &codePages);
+ if (codePages && unicodeRange == cRangeSetCJK) {
+ // The CJK character may belong to multiple code pages. We want to
+ // do font linking against a single one of them, preferring the default
+ // code page for the user's locale.
+ const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
+ unsigned numCodePages = CJKCodePageMasks.size();
+ for (unsigned i = 0; i < numCodePages; ++i) {
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ hfont = createMLangFont(langFontLink, g_screenDC, CJKCodePageMasks[i]);
+#else
+ hfont = createMLangFont(langFontLink, g_screenDC, origFont, CJKCodePageMasks[i]);
+#endif
+ if (!hfont)
+ continue;
+
+ SelectObject(g_screenDC, hfont);
+ GetTextFace(g_screenDC, LF_FACESIZE, name);
+
+ if (hfont && !(codePages & CJKCodePageMasks[i])) {
+ // We asked about a code page that is not one of the code pages
+ // returned by MLang, so the font might not contain the character.
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (!currentFontContainsCharacter(langFontLink, g_screenDC, character)) {
+#else
+ if (!currentFontContainsCharacter(langFontLink, g_screenDC, hfont, character, name)) {
+#endif
+ SelectObject(g_screenDC, oldFont);
+ langFontLink->ReleaseFont(hfont);
+ hfont = 0;
+ continue;
+ }
+ }
+ break;
+ }
+ } else {
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ hfont = createMLangFont(langFontLink, g_screenDC, codePages, character);
+#else
+ hfont = createMLangFont(langFontLink, g_screenDC, origFont, codePages);
+#endif
+ SelectObject(g_screenDC, hfont);
+ GetTextFace(g_screenDC, LF_FACESIZE, name);
+ }
+ SelectObject(g_screenDC, oldFont);
+
+ if (hfont) {
+ familyName = name;
+ langFontLink->ReleaseFont(hfont);
+ } else
+ FontPlatformData::mapKnownFont(codePages, familyName);
+ }
+
+ if (familyName.isEmpty())
+ familyName = FontPlatformData::defaultFontFamily();
+
+ if (!familyName.isEmpty()) {
+ // FIXME: temporary workaround for Thai font problem
+ FontDescription fontDescription(font.fontDescription());
+ if (unicodeRange == cRangeThai && fontDescription.weight() > FontWeightNormal)
+ fontDescription.setWeight(FontWeightNormal);
+
+ FontPlatformData* result = getCachedFontPlatformData(fontDescription, familyName);
+ if (result && result->hash() != origFont.hash()) {
+ if (SimpleFontData* fontData = getCachedFontData(result))
+ return fontData;
+ }
+ }
+
+ return 0;
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDesc)
+{
+ // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick
+ // the default that the user would get without changing any prefs.
+ return getCachedFontData(fontDesc, FontPlatformData::defaultFontFamily());
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ FontPlatformData* result = new FontPlatformData(fontDescription, family);
+ return result;
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = std::min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ TraitsInFamilyProcData procData(familyName);
+ EnumFontFamiliesEx(g_screenDC, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
+ copyToVector(procData.m_traitsMasks, traitsMasks);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..f61ae8e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "Base64.h"
+#include "CachedFont.h"
+#include "FontPlatformData.h"
+#include "SharedBuffer.h"
+#include <wtf/RandomNumber.h>
+
+namespace WebCore {
+
+static CustomFontCache* g_customFontCache = 0;
+
+bool renameFont(SharedBuffer* fontData, const String& fontName);
+
+void setCustomFontCache(CustomFontCache* cache)
+{
+ g_customFontCache = cache;
+}
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ if (g_customFontCache && !m_name.isEmpty())
+ g_customFontCache->unregisterFont(m_name);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode renderingMode)
+{
+ FontDescription fontDesc;
+ fontDesc.setComputedSize(size);
+ fontDesc.setSpecifiedSize(size);
+ fontDesc.setItalic(italic);
+ fontDesc.setWeight(bold ? FontWeightBold : FontWeightNormal);
+ return FontPlatformData(fontDesc, m_name, false);
+}
+
+// Creates a unique and unpredictable font name, in order to avoid collisions and to
+// not allow access from CSS.
+static String createUniqueFontName()
+{
+ Vector<char> fontUuid(sizeof(GUID));
+
+ unsigned int* ptr = reinterpret_cast<unsigned int*>(fontUuid.data());
+ for (int i = 0; i < sizeof(GUID) / sizeof(int) ; ++i)
+ *(ptr + i) = static_cast<unsigned int>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0));
+
+ Vector<char> fontNameVector;
+ base64Encode(fontUuid, fontNameVector);
+ ASSERT(fontNameVector.size() < LF_FACESIZE);
+ String fontName(fontNameVector.data(), fontNameVector.size());
+ return fontName.replace('/', '_');
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(const SharedBuffer* buffer)
+{
+ if (g_customFontCache) {
+ String fontName = createUniqueFontName();
+ RefPtr<SharedBuffer> localBuffer = SharedBuffer::create(buffer->data(), buffer->size());
+ if (renameFont(localBuffer.get(), fontName) && g_customFontCache->registerFont(fontName, localBuffer.get()))
+ return new FontCustomPlatformData(fontName);
+ }
+ return 0;
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype");
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h
new file mode 100644
index 0000000..abdc0f2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontDescription.h"
+#include "FontRenderingMode.h"
+#include "PlatformString.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+ class FontPlatformData;
+ class CachedFont;
+
+ class CustomFontCache {
+ public:
+ virtual bool registerFont(const String& fontName, const SharedBuffer*) = 0;
+ virtual void unregisterFont(const String& fontName) = 0;
+ };
+
+ struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(const String& name)
+ : m_name(name)
+ {
+ }
+
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation fontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+
+ static bool supportsFormat(const String&);
+
+ String m_name;
+ };
+
+ FontCustomPlatformData* createFontCustomPlatformData(const SharedBuffer*);
+ void setCustomFontCache(CustomFontCache*);
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp b/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp
new file mode 100644
index 0000000..d9d8a72
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "Font.h"
+#include "FontCache.h"
+#include "FontData.h"
+#include "PlatformString.h"
+#include "SimpleFontData.h"
+#include "UnicodeRange.h"
+#include "wtf/OwnPtr.h"
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.h>
+
+#include <windows.h>
+#include <mlang.h>
+
+namespace WebCore {
+
+extern HDC g_screenDC;
+
+static wchar_t songTiStr[] = { 0x5b8b, 0x4f53, 0 };
+static wchar_t heiTiStr[] = { 0x9ed1, 0x4f53, 0 };
+
+class FontFamilyCodePageInfo {
+public:
+ FontFamilyCodePageInfo()
+ : m_codePage(0), m_codePages(0)
+ {
+ }
+ FontFamilyCodePageInfo(const wchar_t* family, UINT codePage)
+ : m_family(family), m_codePage(codePage), m_codePages(0)
+ {
+ }
+ DWORD codePages() const
+ {
+ if (!m_codePages) {
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface())
+ langFontLink->CodePageToCodePages(m_codePage, &m_codePages);
+#else
+ if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface())
+ langFontLink->CodePageToCodePages(m_codePage, &m_codePages);
+#endif
+ }
+ return m_codePages;
+ }
+
+ String m_family;
+ UINT m_codePage;
+private:
+ mutable DWORD m_codePages;
+};
+
+class FontFamilyChecker {
+public:
+ FontFamilyChecker(const wchar_t* family)
+ : m_exists(false)
+ {
+ EnumFontFamilies(g_screenDC, family, enumFontFamProc, (LPARAM)this);
+ }
+ bool isSupported() const { return m_exists; }
+private:
+ bool m_exists;
+ static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam);
+};
+
+class ValidFontFamilyFinder {
+public:
+ ValidFontFamilyFinder()
+ {
+ EnumFontFamilies(g_screenDC, 0, enumFontFamProc, (LPARAM)this);
+ }
+ const String& family() const { return m_family; }
+private:
+ String m_family;
+ static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam);
+};
+
+class FixedSizeFontData: public RefCounted<FixedSizeFontData> {
+public:
+ LOGFONT m_font;
+ OwnPtr<HFONT> m_hfont;
+ TEXTMETRIC m_metrics;
+ DWORD m_codePages;
+ unsigned m_weight;
+ bool m_italic;
+
+ static PassRefPtr<FixedSizeFontData> create(const AtomicString& family, unsigned weight, bool italic);
+private:
+ FixedSizeFontData()
+ : m_codePages(0)
+ , m_weight(0)
+ , m_italic(false)
+ {
+ memset(&m_font, 0, sizeof(m_font));
+ memset(&m_metrics, 0, sizeof(m_metrics));
+ }
+};
+
+struct FixedSizeFontDataKey {
+ FixedSizeFontDataKey(const AtomicString& family = AtomicString(), unsigned weight = 0, bool italic = false)
+ : m_family(family)
+ , m_weight(weight)
+ , m_italic(italic)
+ {
+ }
+
+ FixedSizeFontDataKey(WTF::HashTableDeletedValueType) : m_weight(-2) { }
+ bool isHashTableDeletedValue() const { return m_weight == -2; }
+
+ bool operator==(const FixedSizeFontDataKey& other) const
+ {
+ return equalIgnoringCase(m_family, other.m_family)
+ && m_weight == other.m_weight
+ && m_italic == other.m_italic;
+ }
+
+ AtomicString m_family;
+ unsigned m_weight;
+ bool m_italic;
+};
+
+struct FixedSizeFontDataKeyHash {
+ static unsigned hash(const FixedSizeFontDataKey& font)
+ {
+ unsigned hashCodes[] = {
+ CaseFoldingHash::hash(font.m_family),
+ font.m_weight,
+ // static_cast<unsigned>(font.m_italic);
+ };
+ return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+ }
+
+ static bool equal(const FixedSizeFontDataKey& a, const FixedSizeFontDataKey& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FixedSizeFontDataKeyTraits : WTF::GenericHashTraits<FixedSizeFontDataKey> {
+ static const bool emptyValueIsZero = true;
+ static const FixedSizeFontDataKey& emptyValue()
+ {
+ DEFINE_STATIC_LOCAL(FixedSizeFontDataKey, key, (nullAtom));
+ return key;
+ }
+ static void constructDeletedValue(FixedSizeFontDataKey& slot)
+ {
+ new (&slot) FixedSizeFontDataKey(WTF::HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FixedSizeFontDataKey& value)
+ {
+ return value.isHashTableDeletedValue();
+ }
+};
+
+int CALLBACK FontFamilyChecker::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam)
+{
+ ((FontFamilyChecker*)lParam)->m_exists = true;
+ return 0;
+}
+
+int CALLBACK ValidFontFamilyFinder::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam)
+{
+ if (lpelf->lfCharSet != SYMBOL_CHARSET) {
+ ((ValidFontFamilyFinder*)lParam)->m_family = String(lpelf->lfFaceName);
+ return 0;
+ }
+ return 1;
+}
+
+typedef Vector<FontFamilyCodePageInfo> KnownFonts;
+static KnownFonts& knownFonts()
+{
+ static KnownFonts fonts;
+ static bool firstTime = true;
+ if (firstTime) {
+ firstTime = false;
+ if (FontPlatformData::isSongTiSupported())
+ fonts.append(FontFamilyCodePageInfo(songTiStr, 936));
+ }
+ return fonts;
+}
+
+static String getDefaultFontFamily()
+{
+ if (FontFamilyChecker(L"Tahoma").isSupported())
+ return String(L"Tahoma");
+
+ bool good = false;
+ String family;
+ HKEY key;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\GDI\\SysFnt", 0, 0, &key) == ERROR_SUCCESS) {
+ DWORD maxlen, type;
+ if (RegQueryValueEx(key, L"Nm", 0, &type, 0, &maxlen) == ERROR_SUCCESS && type == REG_SZ) {
+ ++maxlen;
+ if (wchar_t* buffer = new wchar_t[maxlen]) {
+ if (RegQueryValueEx(key, L"Nm", 0, &type, (LPBYTE)buffer, &maxlen) == ERROR_SUCCESS) {
+ family = String(buffer, maxlen);
+ good = true;
+ }
+ delete[] buffer;
+ }
+ }
+ RegCloseKey(key);
+ }
+ if (good)
+ return family;
+
+ return ValidFontFamilyFinder().family();
+}
+
+typedef HashMap<FixedSizeFontDataKey, RefPtr<FixedSizeFontData>, FixedSizeFontDataKeyHash, FixedSizeFontDataKeyTraits> FixedSizeFontCache;
+FixedSizeFontCache g_fixedSizeFontCache;
+
+PassRefPtr<FixedSizeFontData> FixedSizeFontData::create(const AtomicString& family, unsigned weight, bool italic)
+{
+ FixedSizeFontData* fontData = new FixedSizeFontData();
+
+ fontData->m_weight = weight;
+ fontData->m_italic = italic;
+
+ LOGFONT& winFont = fontData->m_font;
+ // The size here looks unusual. The negative number is intentional.
+ winFont.lfHeight = -72;
+ winFont.lfWidth = 0;
+ winFont.lfEscapement = 0;
+ winFont.lfOrientation = 0;
+ winFont.lfUnderline = false;
+ winFont.lfStrikeOut = false;
+ winFont.lfCharSet = DEFAULT_CHARSET;
+ winFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ winFont.lfQuality = CLEARTYPE_QUALITY; //DEFAULT_QUALITY;
+ winFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ winFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ winFont.lfItalic = italic;
+ winFont.lfWeight = FontPlatformData::adjustedGDIFontWeight(weight, family);
+
+ int len = std::min(family.length(), (unsigned int)LF_FACESIZE - 1);
+ wmemcpy(winFont.lfFaceName, family.characters(), len);
+ winFont.lfFaceName[len] = L'\0';
+
+ fontData->m_hfont.set(CreateFontIndirect(&winFont));
+
+ HGDIOBJ oldFont = SelectObject(g_screenDC, fontData->m_hfont.get());
+
+ GetTextMetrics(g_screenDC, &fontData->m_metrics);
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface()) {
+#else
+ if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface()) {
+#endif
+ langFontLink->GetFontCodePages(g_screenDC, fontData->m_hfont.get(), &fontData->m_codePages);
+ fontData->m_codePages |= FontPlatformData::getKnownFontCodePages(winFont.lfFaceName);
+ }
+
+ SelectObject(g_screenDC, oldFont);
+
+ return adoptRef(fontData);
+}
+
+static PassRefPtr<FixedSizeFontData> createFixedSizeFontData(const AtomicString& family, unsigned weight, bool italic)
+{
+ FixedSizeFontDataKey key(family, weight, italic);
+ pair<FixedSizeFontCache::iterator, bool> result = g_fixedSizeFontCache.add(key, RefPtr<FixedSizeFontData>());
+ if (result.second)
+ result.first->second = FixedSizeFontData::create(family, weight, italic);
+
+ return result.first->second;
+}
+
+static LONG toGDIFontWeight(FontWeight fontWeight)
+{
+ static LONG gdiFontWeights[] = {
+ FW_THIN, // FontWeight100
+ FW_EXTRALIGHT, // FontWeight200
+ FW_LIGHT, // FontWeight300
+ FW_NORMAL, // FontWeight400
+ FW_MEDIUM, // FontWeight500
+ FW_SEMIBOLD, // FontWeight600
+ FW_BOLD, // FontWeight700
+ FW_EXTRABOLD, // FontWeight800
+ FW_HEAVY // FontWeight900
+ };
+ return gdiFontWeights[fontWeight];
+}
+
+class FontPlatformPrivateData {
+public:
+ int m_reference;
+ RefPtr<FixedSizeFontData> m_rootFontData;
+ AtomicString m_family;
+ FontDescription m_fontDescription;
+ OwnPtr<HFONT> m_hfontScaled;
+ int m_size;
+ long m_fontScaledWidth;
+ long m_fontScaledHeight;
+ bool m_disabled;
+ FontPlatformPrivateData(int size, unsigned weight)
+ : m_reference(1)
+ , m_family(FontPlatformData::defaultFontFamily())
+ , m_size(size)
+ , m_fontScaledWidth(0)
+ , m_fontScaledHeight(0)
+ , m_disabled(false)
+ {
+ m_rootFontData = createFixedSizeFontData(m_family, weight, false);
+ }
+ FontPlatformPrivateData(const FontDescription& fontDescription, const AtomicString& family)
+ : m_reference(1)
+ , m_size(fontDescription.computedPixelSize())
+ , m_fontDescription(fontDescription)
+ , m_family(family)
+ , m_fontScaledWidth(0)
+ , m_fontScaledHeight(0)
+ , m_disabled(!fontDescription.specifiedSize())
+ {
+ m_rootFontData = FixedSizeFontData::create(family, toGDIFontWeight(fontDescription.weight()), fontDescription.italic());
+ }
+};
+
+FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& desiredFamily, bool useDefaultFontIfNotPresent)
+{
+ String family(desiredFamily);
+ if (!equalIgnoringCase(family, defaultFontFamily()) && !FontFamilyChecker(family.charactersWithNullTermination()).isSupported()) {
+ if (equalIgnoringCase(family, String(heiTiStr)) && isSongTiSupported())
+ family = String(songTiStr);
+ else if (useDefaultFontIfNotPresent)
+ family = defaultFontFamily();
+ }
+
+ m_private = new FontPlatformPrivateData(fontDescription, family);
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+{
+ if (!size)
+ m_private = 0;
+ else
+ m_private = new FontPlatformPrivateData((int)(size + 0.5), bold ? FW_BOLD : FW_NORMAL);
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ if (isValid() && !--m_private->m_reference) {
+ if (m_private->m_rootFontData->refCount() == 2) {
+ FixedSizeFontDataKey key(m_private->m_family, m_private->m_rootFontData->m_weight, m_private->m_rootFontData->m_italic);
+ g_fixedSizeFontCache.remove(key);
+ }
+ delete m_private;
+ }
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& o)
+{
+ if (isValid() && !--m_private->m_reference)
+ delete m_private;
+
+ if (m_private = o.m_private)
+ ++m_private->m_reference;
+
+ return *this;
+}
+
+HFONT FontPlatformData::hfont() const
+{
+ if (!isValid())
+ return 0;
+
+ if (m_private->m_disabled)
+ return 0;
+
+ if (!m_private->m_rootFontData->m_hfont)
+ m_private->m_rootFontData->m_hfont.set(CreateFontIndirect(&m_private->m_rootFontData->m_font));
+
+ return m_private->m_rootFontData->m_hfont.get();
+}
+
+HFONT FontPlatformData::getScaledFontHandle(int height, int width) const
+{
+ if (!isValid() || m_private->m_disabled)
+ return 0;
+
+ if (!m_private->m_hfontScaled || m_private->m_fontScaledHeight != height || m_private->m_fontScaledWidth != width) {
+ m_private->m_fontScaledHeight = height;
+ m_private->m_fontScaledWidth = width;
+ LOGFONT font = m_private->m_rootFontData->m_font;
+ font.lfHeight = -height;
+ font.lfWidth = width;
+ m_private->m_hfontScaled.set(CreateFontIndirect(&font));
+ }
+
+ return m_private->m_hfontScaled.get();
+}
+
+bool FontPlatformData::discardFontHandle()
+{
+ if (!isValid())
+ return false;
+
+ if (m_private->m_rootFontData->m_hfont) {
+ m_private->m_rootFontData->m_hfont.set(0);
+ return true;
+ }
+
+ if (m_private->m_hfontScaled) {
+ m_private->m_hfontScaled.set(0);
+ return true;
+ }
+ return false;
+}
+
+const TEXTMETRIC& FontPlatformData::metrics() const
+{
+ return m_private->m_rootFontData->m_metrics;
+}
+
+bool FontPlatformData::isSystemFont() const
+{
+ return false;
+}
+
+int FontPlatformData::size() const
+{
+ return m_private->m_size;
+}
+
+const FontDescription& FontPlatformData::fontDescription() const
+{
+ return m_private->m_fontDescription;
+}
+
+const AtomicString& FontPlatformData::family() const
+{
+ return m_private->m_family;
+}
+
+const LOGFONT& FontPlatformData::logFont() const
+{
+ return m_private->m_rootFontData->m_font;
+}
+
+int FontPlatformData::averageCharWidth() const
+{
+ return (m_private->m_rootFontData->m_metrics.tmAveCharWidth * size() + 36) / 72;
+}
+
+bool FontPlatformData::isDisabled() const
+{
+ return !isValid() || m_private->m_disabled;
+}
+
+DWORD FontPlatformData::codePages() const
+{
+ return m_private->m_rootFontData->m_codePages;
+}
+
+bool FontPlatformData::isSongTiSupported()
+{
+ static bool exists = FontFamilyChecker(songTiStr).isSupported();
+ return exists;
+}
+
+bool FontPlatformData::mapKnownFont(DWORD codePages, String& family)
+{
+ KnownFonts& fonts = knownFonts();
+ for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) {
+ if (i->codePages() & codePages) {
+ family = i->m_family;
+ return true;
+ }
+ }
+ return false;
+}
+
+DWORD FontPlatformData::getKnownFontCodePages(const wchar_t* family)
+{
+ KnownFonts& fonts = knownFonts();
+ for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) {
+ if (equalIgnoringCase(i->m_family, String(family)))
+ return i->codePages();
+ }
+ return 0;
+}
+
+const String& FontPlatformData::defaultFontFamily()
+{
+ static String family(getDefaultFontFamily());
+ return family;
+}
+
+LONG FontPlatformData::adjustedGDIFontWeight(LONG gdiFontWeight, const String& family)
+{
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr)) {
+ if (gdiFontWeight == FW_NORMAL)
+ return FW_MEDIUM;
+ if (gdiFontWeight == FW_BOLD)
+ return FW_SEMIBOLD;
+ }
+ return gdiFontWeight;
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/wince/FontPlatformData.h b/Source/WebCore/platform/graphics/wince/FontPlatformData.h
new file mode 100644
index 0000000..e73a7b2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/FontPlatformData.h
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006, 2007 Apple Inc.
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+#include "FontDescription.h"
+#include "FontOrientation.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/StringImpl.h>
+
+typedef struct tagTEXTMETRICW TEXTMETRIC;
+typedef struct tagLOGFONTW LOGFONT;
+
+namespace WebCore {
+
+ class FontPlatformPrivateData;
+
+ class FontPlatformData {
+
+ public:
+
+ FontPlatformData(): m_private(0) {}
+ FontPlatformData(float size, bool bold, bool oblique);
+
+ // Used for deleted values in the font cache's hash tables.
+ FontPlatformData(WTF::HashTableDeletedValueType) : m_private((FontPlatformPrivateData*)1) {}
+ bool isHashTableDeletedValue() const { return (unsigned)m_private == 1; }
+
+ FontPlatformData(const FontDescription& fontDescription, const AtomicString& family, bool useDefaultFontIfNotPresent = true);
+
+ ~FontPlatformData();
+
+ FontPlatformData(const FontPlatformData& o) : m_private(0) { operator=(o); }
+ FontPlatformData& operator=(const FontPlatformData& o);
+
+ int isValid() const { return reinterpret_cast<unsigned>(m_private) & ~1; }
+ HFONT hfont() const;
+ const TEXTMETRIC& metrics() const;
+ bool isSystemFont() const;
+ int size() const;
+ unsigned hash() const { return (unsigned)m_private; }
+ const FontDescription& fontDescription() const;
+ const AtomicString& family() const;
+ bool operator==(const FontPlatformData& other) const { return m_private == other.m_private; }
+ HFONT getScaledFontHandle(int height, int width) const;
+ const LOGFONT& logFont() const;
+ int averageCharWidth() const;
+ bool isDisabled() const;
+ bool discardFontHandle();
+ DWORD codePages() const;
+
+ static bool isSongTiSupported();
+ static bool mapKnownFont(DWORD codePages, String& family);
+ static DWORD getKnownFontCodePages(const wchar_t* family);
+ static const String& defaultFontFamily();
+ static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family);
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+ private:
+ FontPlatformPrivateData* m_private;
+ };
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/wince/FontWinCE.cpp b/Source/WebCore/platform/graphics/wince/FontWinCE.cpp
new file mode 100644
index 0000000..d636517
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/FontWinCE.cpp
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "FontCache.h"
+#include "FontData.h"
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "WidthIterator.h"
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/unicode/Unicode.h>
+
+#include <windows.h>
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+HDC g_screenDC = GetDC(0);
+
+class ScreenDcReleaser {
+public:
+ ~ScreenDcReleaser()
+ {
+ ReleaseDC(0, g_screenDC);
+ }
+};
+
+ScreenDcReleaser releaseScreenDc;
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ graphicsContext->drawText(fontData, glyphBuffer, from, numGlyphs, point);
+}
+
+class TextRunComponent {
+public:
+ TextRunComponent() : m_textRun(0, 0) {}
+ TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int offset);
+ TextRunComponent(int spaces, const Font &font, int offset);
+ ~TextRunComponent() { m_textRun; }
+
+ bool isSpace() const { return m_spaces; }
+ int textLength() const { return m_spaces ? m_spaces : m_textRun.length(); }
+
+ TextRun m_textRun;
+ float m_width;
+ int m_offset;
+ int m_spaces;
+};
+
+TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o)
+ : m_textRun(start, length, parentTextRun.allowTabs(), 0, 0
+ , parentTextRun.rtl()
+ , parentTextRun.directionalOverride()
+ , parentTextRun.applyRunRounding()
+ , parentTextRun.applyWordRounding())
+ , m_offset(o)
+ , m_spaces(0)
+{
+ WidthIterator it(&font, m_textRun);
+ it.advance(m_textRun.length(), 0);
+ m_width = it.m_runWidthSoFar;
+}
+
+TextRunComponent::TextRunComponent(int s, const Font &font, int o)
+ : m_textRun(0, 0)
+ , m_offset(o)
+ , m_spaces(s)
+{
+ m_width = s * font.primaryFont()->widthForGlyph(' ');
+}
+
+typedef Vector<TextRunComponent, 128> TextRunComponents;
+
+static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run)
+{
+ int letterSpacing = font.letterSpacing();
+ int wordSpacing = font.wordSpacing();
+ int padding = run.padding();
+ int numSpaces = 0;
+ if (padding) {
+ for (int i = 0; i < run.length(); i++)
+ if (Font::treatAsSpace(run[i]))
+ ++numSpaces;
+ }
+
+ int offset = 0;
+ if (letterSpacing) {
+ // need to draw every letter on it's own
+ int start = 0;
+ if (Font::treatAsSpace(run[0])) {
+ int add = 0;
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, font, offset));
+ offset += add + letterSpacing + components->last().m_width;
+ start = 1;
+ }
+ for (int i = 1; i < run.length(); ++i) {
+ uint ch = run[i];
+ if (isHighSurrogate(ch) && isLowSurrogate(run[i-1]))
+ ch = surrogateToUcs4(ch, run[i-1]);
+ if (isLowSurrogate(ch) || category(ch) == Mark_NonSpacing)
+ continue;
+ if (Font::treatAsSpace(run[i])) {
+ int add = 0;
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run, font, offset));
+ offset += components->last().m_width + letterSpacing;
+ }
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, font, offset));
+ offset += wordSpacing + add + components->last().m_width + letterSpacing;
+ start = i + 1;
+ continue;
+ }
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run,
+ font, offset));
+ offset += components->last().m_width + letterSpacing;
+ }
+ start = i;
+ }
+ if (run.length() - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, run.length() - start,
+ run,
+ font, offset));
+ offset += components->last().m_width;
+ }
+ offset += letterSpacing;
+ } else {
+ int start = 0;
+ for (int i = 0; i < run.length(); ++i) {
+ if (Font::treatAsSpace(run[i])) {
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run,
+ font, offset));
+ offset += components->last().m_width;
+ }
+ int add = 0;
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, font, offset));
+ offset += add + components->last().m_width;
+ if (i)
+ offset += wordSpacing;
+ start = i + 1;
+ }
+ }
+ if (run.length() - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, run.length() - start,
+ run,
+ font, offset));
+ offset += components->last().m_width;
+ }
+ }
+ return offset;
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point,
+ int from, int to) const
+{
+ if (to < 0)
+ to = run.length();
+ if (from < 0)
+ from = 0;
+
+ TextRunComponents components;
+ int w = generateComponents(&components, *this, run);
+
+ int curPos = 0;
+ for (int i = 0; i < (int)components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ int len = comp.textLength();
+ int curEnd = curPos + len;
+ if (curPos < to && from < curEnd && !comp.isSpace()) {
+ FloatPoint pt = point;
+ if (run.rtl())
+ pt.setX(point.x() + w - comp.m_offset - comp.m_width);
+ else
+ pt.setX(point.x() + comp.m_offset);
+ drawSimpleText(context, comp.m_textRun, pt, from - curPos, std::min(to, curEnd) - curPos);
+ }
+ curPos += len;
+ if (from < curPos)
+ from = curPos;
+ }
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+ TextRunComponents components;
+ int w = generateComponents(&components, *this, run);
+ return w;
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const
+{
+ // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
+ // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
+ int position = static_cast<int>(xFloat);
+
+ TextRunComponents components;
+ int w = generateComponents(&components, *this, run);
+
+ if (position >= w)
+ return run.length();
+
+ int offset = 0;
+ if (run.rtl()) {
+ for (size_t i = 0; i < components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ int xe = w - comp.m_offset;
+ int xs = xe - comp.m_width;
+ if (position >= xs)
+ return offset + (comp.isSpace()
+ ? static_cast<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
+ : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
+
+ offset += comp.textLength();
+ }
+ } else {
+ for (size_t i = 0; i < components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ int xs = comp.m_offset;
+ int xe = xs + comp.m_width;
+ if (position <= xe) {
+ if (position - xs >= xe)
+ return offset + comp.textLength();
+ return offset + (comp.isSpace()
+ ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
+ : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
+ }
+ offset += comp.textLength();
+ }
+ }
+ return run.length();
+}
+
+
+static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor)
+{
+ int start = 0;
+ for (size_t i = 0; i < components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ if (start + comp.textLength() <= cursor) {
+ start += comp.textLength();
+ continue;
+ }
+ int xs = comp.m_offset;
+ if (rtl)
+ xs = width - xs - comp.m_width;
+
+ int pos = cursor - start;
+ if (comp.isSpace()) {
+ if (rtl)
+ pos = comp.textLength() - pos;
+ return xs + pos * comp.m_width / comp.m_spaces;
+ }
+ WidthIterator it(font, comp.m_textRun);
+ it.advance(pos);
+ return xs + it.m_runWidthSoFar;
+ }
+ return width;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt,
+ int h, int from, int to) const
+{
+ TextRunComponents components;
+ int w = generateComponents(&components, *this, run);
+
+ if (!from && to == run.length())
+ return FloatRect(pt.x(), pt.y(), w, h);
+
+ float x1 = cursorToX(this, components, w, run.rtl(), from);
+ float x2 = cursorToX(this, components, w, run.rtl(), to);
+ if (x2 < x1)
+ std::swap(x1, x2);
+
+ return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
+}
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/GlyphPageTreeNodeWinCE.cpp b/Source/WebCore/platform/graphics/wince/GlyphPageTreeNodeWinCE.cpp
new file mode 100644
index 0000000..1c22f23
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/GlyphPageTreeNodeWinCE.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "Font.h"
+#include "FontCache.h"
+#include "FontData.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+DWORD getKnownFontCodePages(const wchar_t* family);
+
+typedef unsigned (*funcGetCharCodePages)(unsigned short c, unsigned& lastPos);
+funcGetCharCodePages getCharCodePages = 0;
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ if (length != bufferLength)
+ return false;
+
+ if (fontData->platformData().hfont()) {
+ DWORD fontCodePages = fontData->platformData().codePages();
+ if (fontCodePages) {
+ if (getCharCodePages) {
+ unsigned lastPos = 0;
+ for (unsigned i = 0; i < bufferLength; ++i) {
+ DWORD actualCodePages = getCharCodePages(buffer[i], lastPos);
+ if (!actualCodePages || (actualCodePages & fontCodePages))
+ setGlyphDataForIndex(offset + i, buffer[i], fontData);
+ else
+ setGlyphDataForIndex(offset + i, buffer[i], 0);
+ }
+ return true;
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ } else if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface()) {
+#else
+ } else if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface()) {
+#endif
+ for (unsigned i = 0; i < bufferLength; ++i) {
+ DWORD actualCodePages;
+ langFontLink->GetCharCodePages(buffer[i], &actualCodePages);
+ if (!actualCodePages || (actualCodePages & fontCodePages))
+ setGlyphDataForIndex(offset + i, buffer[i], fontData);
+ else
+ setGlyphDataForIndex(offset + i, buffer[i], 0);
+ }
+ return true;
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < length; ++i)
+ setGlyphDataForIndex(offset + i, buffer[i], fontData);
+
+ return true;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/GradientWinCE.cpp b/Source/WebCore/platform/graphics/wince/GradientWinCE.cpp
new file mode 100644
index 0000000..d735881
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/GradientWinCE.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+}
+
+static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
+{
+ return a.stop < b.stop;
+}
+
+const Vector<Gradient::ColorStop, 2>& Gradient::getStops() const
+{
+ if (!m_stopsSorted) {
+ if (m_stops.size())
+ std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
+ m_stopsSorted = true;
+ }
+ return m_stops;
+}
+
+void Gradient::fill(GraphicsContext* c, const FloatRect& r)
+{
+ c->fillRect(r, this);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp
new file mode 100644
index 0000000..2def6ab
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp
@@ -0,0 +1,1890 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile Inc.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "CharacterNames.h"
+#include "Font.h"
+#include "GDIExtras.h"
+#include "GlyphBuffer.h"
+#include "Gradient.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "PlatformPathWinCE.h"
+#include "SharedBitmap.h"
+#include "SimpleFontData.h"
+#include <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+namespace WebCore {
+
+typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector<Gradient::ColorStop>& stops);
+typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector<Gradient::ColorStop>& stops);
+FuncGradientFillRectLinear g_linearGradientFiller = 0;
+FuncGradientFillRectRadial g_radialGradientFiller = 0;
+
+static inline bool isZero(double d)
+{
+ return d > 0 ? d <= 1.E-10 : d >= -1.E-10;
+}
+
+// stableRound rounds -0.5 to 0, where lround rounds -0.5 to -1.
+static inline int stableRound(double d)
+{
+ if (d > 0)
+ return static_cast<int>(d + 0.5);
+
+ int i = static_cast<int>(d);
+ return i - d > 0.5 ? i - 1 : i;
+}
+
+// Unlike enclosingIntRect(), this function does strict rounding.
+static inline IntRect roundRect(const FloatRect& r)
+{
+ return IntRect(stableRound(r.x()), stableRound(r.y()), stableRound(r.right()) - stableRound(r.x()), stableRound(r.bottom()) - stableRound(r.y()));
+}
+
+// Rotation transformation
+class RotationTransform {
+public:
+ RotationTransform()
+ : m_cosA(1.)
+ , m_sinA(0.)
+ , m_preShiftX(0)
+ , m_preShiftY(0)
+ , m_postShiftX(0)
+ , m_postShiftY(0)
+ {
+ }
+ RotationTransform operator-() const
+ {
+ RotationTransform rtn;
+ rtn.m_cosA = m_cosA;
+ rtn.m_sinA = -m_sinA;
+ rtn.m_preShiftX = m_postShiftX;
+ rtn.m_preShiftY = m_postShiftY;
+ rtn.m_postShiftX = m_preShiftX;
+ rtn.m_postShiftY = m_preShiftY;
+ return rtn;
+ }
+ void map(double x1, double y1, double* x2, double* y2) const
+ {
+ x1 += m_preShiftX;
+ y1 += m_preShiftY;
+ *x2 = x1 * m_cosA + y1 * m_sinA + m_postShiftX;
+ *y2 = y1 * m_cosA - x1 * m_sinA + m_postShiftY;
+ }
+ void map(int x1, int y1, int* x2, int* y2) const
+ {
+ x1 += m_preShiftX;
+ y1 += m_preShiftY;
+ *x2 = stableRound(x1 * m_cosA + y1 * m_sinA) + m_postShiftX;
+ *y2 = stableRound(y1 * m_cosA - x1 * m_sinA) + m_postShiftY;
+ }
+
+ double m_cosA;
+ double m_sinA;
+ int m_preShiftX;
+ int m_preShiftY;
+ int m_postShiftX;
+ int m_postShiftY;
+};
+
+template<class T> static inline IntPoint mapPoint(const IntPoint& p, const T& t)
+{
+ int x, y;
+ t.map(p.x(), p.y(), &x, &y);
+ return IntPoint(x, y);
+}
+
+template<class T> static inline FloatPoint mapPoint(const FloatPoint& p, const T& t)
+{
+ double x, y;
+ t.map(p.x(), p.y(), &x, &y);
+ return FloatPoint(static_cast<float>(x), static_cast<float>(y));
+}
+
+template<class Transform, class Rect, class Value> static inline Rect mapRect(const Rect& rect, const Transform& transform)
+{
+ Value x[4], y[4];
+ Value l, t, r, b;
+ r = rect.right() - 1;
+ b = rect.bottom() - 1;
+ transform.map(rect.x(), rect.y(), x, y);
+ transform.map(rect.x(), b, x + 1, y + 1);
+ transform.map(r, b, x + 2, y + 2);
+ transform.map(r, rect.y(), x + 3, y + 3);
+ l = r = x[3];
+ t = b = y[3];
+ for (int i = 0; i < 3; ++i) {
+ if (x[i] < l)
+ l = x[i];
+ else if (x[i] > r)
+ r = x[i];
+
+ if (y[i] < t)
+ t = y[i];
+ else if (y[i] > b)
+ b = y[i];
+ }
+
+ return IntRect(l, t, r - l + 1, b - t + 1);
+}
+
+template<class T> static inline IntRect mapRect(const IntRect& rect, const T& transform)
+{
+ return mapRect<T, IntRect, int>(rect, transform);
+}
+
+template<class T> static inline FloatRect mapRect(const FloatRect& rect, const T& transform)
+{
+ return mapRect<T, FloatRect, double>(rect, transform);
+}
+
+class GraphicsContextPlatformPrivateData {
+public:
+ GraphicsContextPlatformPrivateData()
+ : m_transform()
+ , m_opacity(1.0)
+ {
+ }
+
+ AffineTransform m_transform;
+ float m_opacity;
+};
+
+enum AlphaPaintType {
+ AlphaPaintNone,
+ AlphaPaintImage,
+ AlphaPaintOther,
+};
+
+class GraphicsContextPlatformPrivate : public GraphicsContextPlatformPrivateData {
+public:
+ GraphicsContextPlatformPrivate(HDC dc)
+ : m_dc(dc)
+ {
+ }
+ ~GraphicsContextPlatformPrivate()
+ {
+ while (!m_backupData.isEmpty())
+ restore();
+ }
+
+ void translate(float x, float y)
+ {
+ m_transform.translate(x, y);
+ }
+
+ void scale(const FloatSize& size)
+ {
+ m_transform.scaleNonUniform(size.width(), size.height());
+ }
+
+ void rotate(float radians)
+ {
+ m_transform.rotate(rad2deg(radians));
+ }
+
+ void concatCTM(const AffineTransform& transform)
+ {
+ m_transform = transform * m_transform;
+ }
+
+ IntRect mapRect(const IntRect& rect) const
+ {
+ return m_transform.mapRect(rect);
+ }
+
+ FloatRect mapRect(const FloatRect& rect) const
+ {
+ return m_transform.mapRect(rect);
+ }
+
+ IntPoint mapPoint(const IntPoint& point) const
+ {
+ return m_transform.mapPoint(point);
+ }
+
+ FloatPoint mapPoint(const FloatPoint& point) const
+ {
+ return m_transform.mapPoint(point);
+ }
+
+ FloatSize mapSize(const FloatSize& size) const
+ {
+ double w, h;
+ m_transform.map(size.width(), size.height(), w, h);
+ return FloatSize(static_cast<float>(w), static_cast<float>(h));
+ }
+
+ void save()
+ {
+ if (m_dc)
+ SaveDC(m_dc);
+
+ m_backupData.append(*static_cast<GraphicsContextPlatformPrivateData*>(this));
+ }
+
+ void restore()
+ {
+ if (m_backupData.isEmpty())
+ return;
+
+ if (m_dc)
+ RestoreDC(m_dc, -1);
+
+ GraphicsContextPlatformPrivateData::operator=(m_backupData.last());
+ m_backupData.removeLast();
+ }
+
+ bool hasAlpha() const { return m_bitmap && m_bitmap->hasAlpha(); }
+
+ PassRefPtr<SharedBitmap> getTransparentLayerBitmap(IntRect& origRect, AlphaPaintType alphaPaint, RECT& bmpRect, bool checkClipBox, bool force) const
+ {
+ if (m_opacity <= 0)
+ return 0;
+
+ if (force || m_opacity < 1.) {
+ if (checkClipBox) {
+ RECT clipBox;
+ int clipType = GetClipBox(m_dc, &clipBox);
+ if (clipType == SIMPLEREGION || clipType == COMPLEXREGION)
+ origRect.intersect(clipBox);
+ if (origRect.isEmpty())
+ return 0;
+ }
+
+ RefPtr<SharedBitmap> bmp = SharedBitmap::create(origRect.size(), alphaPaint == AlphaPaintNone ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32, false);
+ SetRect(&bmpRect, 0, 0, origRect.width(), origRect.height());
+ if (bmp) {
+ switch (alphaPaint) {
+ case AlphaPaintNone:
+ case AlphaPaintImage:
+ {
+ SharedBitmap::DCHolder dc(bmp.get());
+ if (dc.get()) {
+ BitBlt(dc.get(), 0, 0, origRect.width(), origRect.height(), m_dc, origRect.x(), origRect.y(), SRCCOPY);
+ if (bmp->is32bit() && (!m_bitmap || m_bitmap->is16bit())) {
+ // Set alpha channel
+ unsigned* pixels = (unsigned*)bmp->bytes();
+ const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels();
+ while (pixels < pixelsEnd) {
+ *pixels |= 0xFF000000;
+ ++pixels;
+ }
+ }
+ return bmp;
+ }
+ }
+ break;
+ //case AlphaPaintOther:
+ default:
+ memset(bmp->bytes(), 0xFF, bmp->bitmapInfo().numPixels() * 4);
+ return bmp;
+ break;
+ }
+ }
+ }
+
+ bmpRect = origRect;
+ return 0;
+ }
+
+ void paintBackTransparentLayerBitmap(HDC hdc, SharedBitmap* bmp, const IntRect& origRect, AlphaPaintType alphaPaint, const RECT& bmpRect)
+ {
+ if (hdc == m_dc)
+ return;
+
+ if (alphaPaint == AlphaPaintOther && hasAlphaBlendSupport()) {
+ ASSERT(bmp && bmp->bytes() && bmp->is32bit());
+ unsigned* pixels = (unsigned*)bmp->bytes();
+ const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels();
+ while (pixels < pixelsEnd) {
+ *pixels ^= 0xFF000000;
+ ++pixels;
+ }
+ }
+ if ((m_opacity < 1. || alphaPaint == AlphaPaintOther) && hasAlphaBlendSupport()) {
+ const BLENDFUNCTION blend = { AC_SRC_OVER, 0
+ , m_opacity >= 1. ? 255 : (BYTE)(m_opacity * 255)
+ , alphaPaint == AlphaPaintNone ? 0 : AC_SRC_ALPHA };
+ bool success = alphaBlendIfSupported(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend);
+ ASSERT_UNUSED(success, success);
+ } else
+ StretchBlt(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, SRCCOPY);
+ }
+
+ HDC m_dc;
+ RefPtr<SharedBitmap> m_bitmap;
+ Vector<GraphicsContextPlatformPrivateData> m_backupData;
+};
+
+static PassOwnPtr<HPEN> createPen(const Color& col, double fWidth, StrokeStyle style)
+{
+ int width = stableRound(fWidth);
+ if (width < 1)
+ width = 1;
+
+ int penStyle = PS_NULL;
+ switch (style) {
+ case SolidStroke:
+ penStyle = PS_SOLID;
+ break;
+ case DottedStroke: // not supported on Windows CE
+ case DashedStroke:
+ penStyle = PS_DASH;
+ width = 1;
+ break;
+ default:
+ break;
+ }
+
+ return adoptPtr(CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue())));
+}
+
+static inline PassOwnPtr<HBRUSH> createBrush(const Color& col)
+{
+ return adoptPtr(CreateSolidBrush(RGB(col.red(), col.green(), col.blue())));
+}
+
+template <typename PixelType, bool Is16bit> static void _rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
+{
+ int destW = destBmp->width();
+ int destH = destBmp->height();
+ int sourceW = sourceBmp->width();
+ int sourceH = sourceBmp->height();
+ PixelType* dest = (PixelType*)destBmp->bytes();
+ const PixelType* source = (const PixelType*)sourceBmp->bytes();
+ int padding;
+ int paddedSourceW;
+ if (Is16bit) {
+ padding = destW & 1;
+ paddedSourceW = sourceW + (sourceW & 1);
+ } else {
+ padding = 0;
+ paddedSourceW = sourceW;
+ }
+ if (isZero(transform.m_sinA)) {
+ int cosA = transform.m_cosA > 0 ? 1 : -1;
+ for (int y = 0; y < destH; ++y) {
+ for (int x = 0; x < destW; ++x) {
+ int x1 = x + transform.m_preShiftX;
+ int y1 = y + transform.m_preShiftY;
+ int srcX = x1 * cosA + transform.m_postShiftX;
+ int srcY = y1 * cosA - transform.m_postShiftY;
+ if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
+ *dest++ = source[srcY * paddedSourceW + srcX] | 0xFF000000;
+ else
+ *dest++ |= 0xFF;
+ }
+ dest += padding;
+ }
+ } else if (isZero(transform.m_cosA)) {
+ int sinA = transform.m_sinA > 0 ? 1 : -1;
+ for (int y = 0; y < destH; ++y) {
+ for (int x = 0; x < destW; ++x) {
+ int x1 = x + transform.m_preShiftX;
+ int y1 = y + transform.m_preShiftY;
+ int srcX = y1 * sinA + transform.m_postShiftX;
+ int srcY = -x1 * sinA + transform.m_postShiftY;
+ if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
+ *dest++ = source[srcY * paddedSourceW + srcX];
+ }
+ dest += padding;
+ }
+ } else {
+ for (int y = 0; y < destH; ++y) {
+ for (int x = 0; x < destW; ++x) {
+ // FIXME: for best quality, we should get weighted sum of four neighbours,
+ // but that will be too expensive
+ int srcX, srcY;
+ transform.map(x, y, &srcX, &srcY);
+ if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
+ *dest++ = source[srcY * paddedSourceW + srcX];
+ }
+ dest += padding;
+ }
+ }
+}
+
+static void rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
+{
+ ASSERT(destBmp->is16bit() == sourceBmp->is16bit());
+ if (destBmp->is16bit())
+ _rotateBitmap<unsigned short, true>(destBmp, sourceBmp, transform);
+ else
+ _rotateBitmap<unsigned, false>(destBmp, sourceBmp, transform);
+}
+
+class TransparentLayerDC : Noncopyable {
+public:
+ TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform = 0, int alpha = 255, bool paintImage = false);
+ ~TransparentLayerDC();
+
+ HDC hdc() const { return m_memDc; }
+ const RECT& rect() const { return m_bmpRect; }
+ IntSize toShift() const { return IntSize(m_bmpRect.left - m_origRect.x(), m_bmpRect.top - m_origRect.y()); }
+ void fillAlphaChannel();
+
+private:
+ GraphicsContextPlatformPrivate* m_data;
+ IntRect m_origRect;
+ IntRect m_rotatedOrigRect;
+ HDC m_memDc;
+ RefPtr<SharedBitmap> m_bitmap;
+ RefPtr<SharedBitmap> m_rotatedBitmap;
+ RECT m_bmpRect;
+ unsigned m_key;
+ RotationTransform m_rotation;
+ float m_oldOpacity;
+ AlphaPaintType m_alphaPaintType;
+};
+
+TransparentLayerDC::TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform, int alpha, bool paintImage)
+: m_data(data)
+, m_origRect(origRect)
+, m_oldOpacity(data->m_opacity)
+// m_key1 and m_key2 are not initalized here. They are used only in the case that
+// SharedBitmap::getDC() is called, I.E., when m_bitmap is not null.
+{
+ m_data->m_opacity *= alpha / 255.;
+ bool mustCreateLayer;
+ if (!m_data->hasAlpha()) {
+ mustCreateLayer = false;
+ m_alphaPaintType = AlphaPaintNone;
+ } else {
+ mustCreateLayer = true;
+ m_alphaPaintType = paintImage ? AlphaPaintImage : AlphaPaintOther;
+ }
+ if (rectBeforeTransform && !isZero(m_data->m_transform.b())) {
+ m_rotatedOrigRect = origRect;
+ m_rotatedBitmap = m_data->getTransparentLayerBitmap(m_rotatedOrigRect, m_alphaPaintType, m_bmpRect, false, true);
+ if (m_rotatedBitmap) {
+ double a = m_data->m_transform.a();
+ double b = m_data->m_transform.b();
+ double c = _hypot(a, b);
+ m_rotation.m_cosA = a / c;
+ m_rotation.m_sinA = b / c;
+
+ int centerX = origRect.x() + origRect.width() / 2;
+ int centerY = origRect.y() + origRect.height() / 2;
+ m_rotation.m_preShiftX = -centerX;
+ m_rotation.m_preShiftY = -centerY;
+ m_rotation.m_postShiftX = centerX;
+ m_rotation.m_postShiftY = centerY;
+
+ m_origRect = mapRect(m_rotatedOrigRect, m_rotation);
+
+ m_rotation.m_preShiftX += m_rotatedOrigRect.x();
+ m_rotation.m_preShiftY += m_rotatedOrigRect.y();
+ m_rotation.m_postShiftX -= m_origRect.x();
+ m_rotation.m_postShiftY -= m_origRect.y();
+
+ FloatPoint topLeft = m_data->m_transform.mapPoint(FloatPoint(rectBeforeTransform->topLeft()));
+ FloatPoint topRight(rectBeforeTransform->right() - 1, rectBeforeTransform->y());
+ topRight = m_data->m_transform.mapPoint(topRight);
+ FloatPoint bottomLeft(rectBeforeTransform->x(), rectBeforeTransform->bottom() - 1);
+ bottomLeft = m_data->m_transform.mapPoint(bottomLeft);
+ FloatSize sideTop = topRight - topLeft;
+ FloatSize sideLeft = bottomLeft - topLeft;
+ float width = _hypot(sideTop.width() + 1, sideTop.height() + 1);
+ float height = _hypot(sideLeft.width() + 1, sideLeft.height() + 1);
+
+ origRect.inflateX(stableRound((width - origRect.width()) * 0.5));
+ origRect.inflateY(stableRound((height - origRect.height()) * 0.5));
+
+ m_bitmap = SharedBitmap::create(m_origRect.size(), m_rotatedBitmap->is16bit() ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32, true);
+ if (m_bitmap)
+ rotateBitmap(m_bitmap.get(), m_rotatedBitmap.get(), -m_rotation);
+ else
+ m_rotatedBitmap = 0;
+ }
+ } else
+ m_bitmap = m_data->getTransparentLayerBitmap(m_origRect, m_alphaPaintType, m_bmpRect, true, mustCreateLayer);
+ if (m_bitmap)
+ m_memDc = m_bitmap->getDC(&m_key);
+ else
+ m_memDc = m_data->m_dc;
+}
+
+TransparentLayerDC::~TransparentLayerDC()
+{
+ if (m_rotatedBitmap) {
+ m_bitmap->releaseDC(m_memDc, m_key);
+ m_key = 0;
+ rotateBitmap(m_rotatedBitmap.get(), m_bitmap.get(), m_rotation);
+ m_memDc = m_rotatedBitmap->getDC(&m_key);
+ m_data->paintBackTransparentLayerBitmap(m_memDc, m_rotatedBitmap.get(), m_rotatedOrigRect, m_alphaPaintType, m_bmpRect);
+ m_rotatedBitmap->releaseDC(m_memDc, m_key);
+ } else if (m_bitmap) {
+ m_data->paintBackTransparentLayerBitmap(m_memDc, m_bitmap.get(), m_origRect, m_alphaPaintType, m_bmpRect);
+ m_bitmap->releaseDC(m_memDc, m_key);
+ }
+ m_data->m_opacity = m_oldOpacity;
+}
+
+void TransparentLayerDC::fillAlphaChannel()
+{
+ if (!m_bitmap || !m_bitmap->is32bit())
+ return;
+
+ unsigned* pixels = (unsigned*)m_bitmap->bytes();
+ const unsigned* const pixelsEnd = pixels + m_bitmap->bitmapInfo().numPixels();
+ while (pixels < pixelsEnd) {
+ *pixels |= 0xFF000000;
+ ++pixels;
+ }
+}
+
+class ScopeDCProvider : Noncopyable {
+public:
+ explicit ScopeDCProvider(GraphicsContextPlatformPrivate* data)
+ : m_data(data)
+ {
+ if (m_data->m_bitmap)
+ m_data->m_dc = m_data->m_bitmap->getDC(&m_key);
+ }
+ ~ScopeDCProvider()
+ {
+ if (m_data->m_bitmap) {
+ m_data->m_bitmap->releaseDC(m_data->m_dc, m_key);
+ m_data->m_dc = 0;
+ }
+ }
+private:
+ GraphicsContextPlatformPrivate* m_data;
+ unsigned m_key;
+};
+
+
+void GraphicsContext::platformInit(PlatformGraphicsContext* dc)
+{
+ m_data = new GraphicsContextPlatformPrivate(dc);
+}
+
+void GraphicsContext::platformDestroy()
+{
+ delete m_data;
+}
+
+void GraphicsContext::setBitmap(PassRefPtr<SharedBitmap> bmp)
+{
+ ASSERT(!m_data->m_dc);
+ m_data->m_bitmap = bmp;
+}
+
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // FIXME: Add support for AlphaBlend.
+ ASSERT(!supportAlphaBlend);
+ return m_data->m_dc;
+}
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+}
+
+void GraphicsContext::savePlatformState()
+{
+ m_data->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ m_data->restore();
+}
+
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (!m_data->m_opacity || paintingDisabled() || rect.isEmpty())
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ OwnPtr<HBRUSH> brush;
+ HGDIOBJ oldBrush;
+ if (fillColor().alpha()) {
+ brush = createBrush(fillColor());
+ oldBrush = SelectObject(dc, brush.get());
+ } else
+ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+
+ OwnPtr<HPEN> pen;
+ HGDIOBJ oldPen;
+ if (strokeStyle() != NoStroke) {
+ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ oldPen = SelectObject(dc, pen.get());
+ } else
+ oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
+
+ if (brush || pen) {
+ if (trRect.width() <= 0)
+ trRect.setWidth(1);
+ if (trRect.height() <= 0)
+ trRect.setHeight(1);
+
+ Rectangle(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+ }
+
+ SelectObject(dc, oldPen);
+ SelectObject(dc, oldBrush);
+}
+
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || !strokeColor().alpha())
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntPoint trPoint1 = m_data->mapPoint(point1);
+ IntPoint trPoint2 = m_data->mapPoint(point2);
+
+ IntRect lineRect(trPoint1, trPoint2 - trPoint1);
+ lineRect.setHeight(lineRect.height() + strokeThickness());
+ TransparentLayerDC transparentDC(m_data, lineRect, 0, strokeColor().alpha());
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trPoint1 += transparentDC.toShift();
+ trPoint2 += transparentDC.toShift();
+
+ OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ HGDIOBJ oldPen = SelectObject(dc, pen.get());
+
+ MoveToEx(dc, trPoint1.x(), trPoint1.y(), 0);
+ LineTo(dc, trPoint2.x(), trPoint2.y());
+
+ SelectObject(dc, oldPen);
+}
+
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (!m_data->m_opacity || paintingDisabled() || (!fillColor().alpha() && strokeStyle() == NoStroke))
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ OwnPtr<HBRUSH> brush;
+ HGDIOBJ oldBrush;
+ if (fillColor().alpha()) {
+ brush = createBrush(fillColor());
+ oldBrush = SelectObject(dc, brush.get());
+ } else
+ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+
+ OwnPtr<HPEN> pen;
+ HGDIOBJ oldPen = 0;
+ if (strokeStyle() != NoStroke) {
+ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ oldPen = SelectObject(dc, pen.get());
+ } else
+ oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
+
+ if (brush || pen)
+ Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+
+ SelectObject(dc, oldPen);
+ SelectObject(dc, oldBrush);
+}
+
+static inline bool equalAngle(double a, double b)
+{
+ return fabs(a - b) < 1E-5;
+}
+
+void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y)
+{
+ while (angle < 0)
+ angle += 2 * piDouble;
+ while (angle >= 2 * piDouble)
+ angle -= 2 * piDouble;
+
+ if (equalAngle(angle, 0) || equalAngle(angle, 2 * piDouble)) {
+ x = a;
+ y = 0;
+ } else if (equalAngle(angle, piDouble)) {
+ x = -a;
+ y = 0;
+ } else if (equalAngle(angle, .5 * piDouble)) {
+ x = 0;
+ y = b;
+ } else if (equalAngle(angle, 1.5 * piDouble)) {
+ x = 0;
+ y = -b;
+ } else {
+ double k = tan(angle);
+ double sqA = a * a;
+ double sqB = b * b;
+ double tmp = 1. / (1. / sqA + (k * k) / sqB);
+ tmp = tmp <= 0 ? 0 : sqrt(tmp);
+ if (angle > .5 * piDouble && angle < 1.5 * piDouble)
+ tmp = -tmp;
+ x = tmp;
+
+ k = tan(.5 * piDouble - angle);
+ tmp = 1. / ((k * k) / sqA + 1 / sqB);
+ tmp = tmp <= 0 ? 0 : sqrt(tmp);
+ if (angle > piDouble)
+ tmp = -tmp;
+ y = tmp;
+ }
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || rect.isEmpty())
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ HGDIOBJ oldPen = SelectObject(dc, pen.get());
+
+ double a = trRect.width() * 0.5;
+ double b = trRect.height() * 0.5;
+ int centerX = stableRound(trRect.x() + a);
+ int centerY = stableRound(trRect.y() + b);
+ float fstartX, fstartY, fendX, fendY;
+ int startX, startY, endX, endY;
+ getEllipsePointByAngle(deg2rad((double)startAngle), a, b, fstartX, fstartY);
+ getEllipsePointByAngle(deg2rad((double)startAngle + angleSpan), a, b, fendX, fendY);
+ startX = stableRound(fstartX);
+ startY = stableRound(fstartY);
+ endX = stableRound(fendX);
+ endY = stableRound(fendY);
+
+ startX += centerX;
+ startY = centerY - startY;
+ endX += centerX;
+ endY = centerY - endY;
+ RECT clipRect;
+ if (startX < endX) {
+ clipRect.left = startX;
+ clipRect.right = endX;
+ } else {
+ clipRect.left = endX;
+ clipRect.right = startX;
+ }
+ if (startY < endY) {
+ clipRect.top = startY;
+ clipRect.bottom = endY;
+ } else {
+ clipRect.top = endY;
+ clipRect.bottom = startY;
+ }
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ bool newClip;
+ if (GetClipRgn(dc, clipRgn.get()) <= 0) {
+ newClip = true;
+ clipRgn.set(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
+ SelectClipRgn(dc, clipRgn.get());
+ } else {
+ newClip = false;
+ IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+ }
+
+ HGDIOBJ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+ Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+ SelectObject(dc, oldBrush);
+
+ if (newClip)
+ SelectClipRgn(dc, 0);
+ else
+ SelectClipRgn(dc, clipRgn.get());
+
+ SelectObject(dc, oldPen);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (!m_data->m_opacity || paintingDisabled() || npoints <= 1 || !points)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ Vector<POINT, 20> winPoints(npoints);
+ FloatPoint trPoint = m_data->mapPoint(points[0]);
+ winPoints[0].x = stableRound(trPoint.x());
+ winPoints[0].y = stableRound(trPoint.y());
+ RECT rect = { winPoints[0].x, winPoints[0].y, winPoints[0].x, winPoints[0].y };
+ for (size_t i = 1; i < npoints; ++i) {
+ trPoint = m_data->mapPoint(points[i]);
+ winPoints[i].x = stableRound(trPoint.x());
+ winPoints[i].y = stableRound(trPoint.y());
+ if (rect.left > winPoints[i].x)
+ rect.left = winPoints[i].x;
+ else if (rect.right < winPoints[i].x)
+ rect.right = winPoints[i].x;
+ if (rect.top > winPoints[i].y)
+ rect.top = winPoints[i].y;
+ else if (rect.bottom < winPoints[i].y)
+ rect.bottom = winPoints[i].y;
+ }
+ rect.bottom += 1;
+ rect.right += 1;
+
+ IntRect intRect(rect);
+ TransparentLayerDC transparentDC(m_data, intRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+
+ for (size_t i = 0; i < npoints; ++i) {
+ winPoints[i].x += transparentDC.toShift().width();
+ winPoints[i].y += transparentDC.toShift().height();
+ }
+
+ OwnPtr<HBRUSH> brush;
+ HGDIOBJ oldBrush;
+ if (fillColor().alpha()) {
+ brush = createBrush(fillColor());
+ oldBrush = SelectObject(dc, brush.get());
+ } else
+ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+
+ OwnPtr<HPEN> pen;
+ HGDIOBJ oldPen;
+ if (strokeStyle() != NoStroke) {
+ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ oldPen = SelectObject(dc, pen.get());
+ } else
+ oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
+
+ if (brush || pen)
+ Polygon(dc, winPoints.data(), npoints);
+
+ SelectObject(dc, oldPen);
+ SelectObject(dc, oldBrush);
+}
+
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ // FIXME: IMPLEMENT!!
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !m_data->m_opacity)
+ return;
+
+ int alpha = color.alpha();
+ if (!alpha)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect intRect = enclosingIntRect(rect);
+ TransparentLayerDC transparentDC(m_data, m_data->mapRect(intRect), &intRect, alpha);
+
+ if (!transparentDC.hdc())
+ return;
+
+ OwnPtr<HBRUSH> hbrush(CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
+ FillRect(transparentDC.hdc(), &transparentDC.rect(), hbrush.get());
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ if (GetClipRgn(m_data->m_dc, clipRgn.get()) > 0)
+ IntersectClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+ else {
+ clipRgn.set(CreateRectRgn(trRect.x(), trRect.y(), trRect.right(), trRect.bottom()));
+ SelectClipRgn(m_data->m_dc, clipRgn.get());
+ }
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+
+ ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
+{
+ if (!m_data->m_opacity || paintingDisabled())
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ int radius = (width - 1) / 2;
+ offset += radius;
+
+ unsigned rectCount = rects.size();
+ IntRect finalFocusRect;
+ for (unsigned i = 0; i < rectCount; i++) {
+ IntRect focusRect = rects[i];
+ focusRect.inflate(offset);
+ finalFocusRect.unite(focusRect);
+ }
+
+ IntRect intRect = finalFocusRect;
+ IntRect trRect = m_data->mapRect(finalFocusRect);
+ TransparentLayerDC transparentDC(m_data, trRect, &intRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ RECT rect = trRect;
+ DrawFocusRect(dc, &rect);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle oldStyle = strokeStyle();
+ setStrokeStyle(SolidStroke);
+ drawLine(origin, origin + IntSize(width, 0));
+ setStrokeStyle(oldStyle);
+}
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint&, int width, TextCheckingLineStyle style)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ notImplemented();
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ // We can only clip rectangles on WINCE
+ clip(rect);
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->hasAlpha()) {
+ IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
+ m_data->m_bitmap->clearPixels(trRect);
+ return;
+ }
+
+ fillRect(rect, Color(Color::white), ColorSpaceDeviceRGB);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float width)
+{
+ if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect intRect = enclosingIntRect(rect);
+ IntRect trRect = m_data->mapRect(intRect);
+ TransparentLayerDC transparentDC(m_data, trRect, &intRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ HGDIOBJ oldPen = SelectObject(dc, pen.get());
+
+ int right = trRect.right() - 1;
+ int bottom = trRect.bottom() - 1;
+ const POINT intPoints[5] =
+ {
+ { trRect.x(), trRect.y() },
+ { right, trRect.y() },
+ { right, bottom },
+ { trRect.x(), bottom },
+ { trRect.x(), trRect.y() }
+ };
+
+ Polyline(dc, intPoints, 5);
+
+ SelectObject(dc, oldPen);
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ m_data->save();
+ m_data->m_opacity *= opacity;
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ m_data->restore();
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ m_data->concatCTM(transform);
+}
+
+AffineTransform& GraphicsContext::affineTransform()
+{
+ return m_data->m_transform;
+}
+
+const AffineTransform& GraphicsContext::affineTransform() const
+{
+ return m_data->m_transform;
+}
+
+void GraphicsContext::resetAffineTransform()
+{
+ m_data->m_transform.makeIdentity();
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ m_data->translate(x, y);
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ m_data->rotate(radians);
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ m_data->scale(size);
+}
+
+void GraphicsContext::setLineCap(LineCap lineCap)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setLineJoin(LineJoin lineJoin)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setMiterLimit(float miter)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ m_data->m_opacity = alpha;
+}
+
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ notImplemented();
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void GraphicsContext::clipOut(const Path&)
+{
+ notImplemented();
+}
+
+static inline IntPoint rectCenterPoint(const RECT& rect)
+{
+ return IntPoint(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2);
+}
+void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c, ColorSpace colorSpace)
+{
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ FloatSize shadowOffset;
+ float shadowBlur = 0;
+ Color shadowColor;
+ ColorSpace shadowColorSpace;
+
+ getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
+
+ IntRect dstRect = fillRect;
+
+ dstRect.move(stableRound(shadowOffset.width()), stableRound(shadowOffset.height()));
+ dstRect.inflate(stableRound(shadowBlur));
+ dstRect = m_data->mapRect(dstRect);
+
+ FloatSize newTopLeft(m_data->mapSize(topLeft));
+ FloatSize newTopRight(m_data->mapSize(topRight));
+ FloatSize newBottomLeft(m_data->mapSize(bottomLeft));
+ FloatSize newBottomRight(m_data->mapSize(bottomRight));
+
+ TransparentLayerDC transparentDc(m_data, dstRect, &fillRect);
+ HDC dc = transparentDc.hdc();
+ if (!dc)
+ return;
+
+ dstRect.move(transparentDc.toShift());
+
+ RECT rectWin = dstRect;
+
+ OwnPtr<HBRUSH> brush = createBrush(shadowColor);
+ HGDIOBJ oldBrush = SelectObject(dc, brush.get());
+
+ SelectObject(dc, GetStockObject(NULL_PEN));
+
+ IntPoint centerPoint = rectCenterPoint(rectWin);
+ // Draw top left half
+ RECT clipRect(rectWin);
+ clipRect.right = centerPoint.x();
+ clipRect.bottom = centerPoint.y();
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ bool needsNewClip = (GetClipRgn(dc, clipRgn.get()) <= 0);
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopLeft.width() * 2), stableRound(newTopLeft.height() * 2));
+
+ // Draw top right
+ clipRect = rectWin;
+ clipRect.left = centerPoint.x();
+ clipRect.bottom = centerPoint.y();
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopRight.width() * 2), stableRound(newTopRight.height() * 2));
+
+ // Draw bottom left
+ clipRect = rectWin;
+ clipRect.right = centerPoint.x();
+ clipRect.top = centerPoint.y();
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomLeft.width() * 2), stableRound(newBottomLeft.height() * 2));
+
+ // Draw bottom right
+ clipRect = rectWin;
+ clipRect.left = centerPoint.x();
+ clipRect.top = centerPoint.y();
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomRight.width() * 2), stableRound(newBottomRight.height() * 2));
+
+ SelectObject(dc, oldBrush);
+}
+
+
+void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height)
+{
+ if (!dc)
+ return;
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ if (needsNewClip) {
+ clipRgn.set(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
+ SelectClipRgn(dc, clipRgn.get());
+ } else
+ IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+
+ ::RoundRect(dc, rectWin.left , rectWin.top , rectWin.right , rectWin.bottom , width, height);
+
+ SelectClipRgn(dc, needsNewClip ? 0 : clipRgn.get());
+}
+
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ notImplemented();
+ return frect;
+}
+
+Color gradientAverageColor(const Gradient* gradient)
+{
+ const Vector<Gradient::ColorStop>& stops = gradient->getStops();
+ if (stops.isEmpty())
+ return Color();
+
+ const Gradient::ColorStop& stop = stops.first();
+ if (stops.size() == 1)
+ return Color(stop.red, stop.green, stop.blue, stop.alpha);
+
+ const Gradient::ColorStop& lastStop = stops.last();
+ return Color((stop.red + lastStop.red) * 0.5f
+ , (stop.green + lastStop.green) * 0.5f
+ , (stop.blue + lastStop.blue) * 0.5f
+ , (stop.alpha + lastStop.alpha) * 0.5f);
+}
+
+void GraphicsContext::fillPath(const Path& path)
+{
+ Color c = m_state.fillGradient
+ ? gradientAverageColor(m_state.fillGradient.get())
+ : fillColor();
+
+ if (!c.alpha() || !m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ OwnPtr<HBRUSH> brush = createBrush(c);
+
+ if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
+ IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect()));
+ trRect.inflate(1);
+ TransparentLayerDC transparentDC(m_data, trRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+
+ AffineTransform tr = m_data->m_transform;
+ tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
+
+ SelectObject(dc, GetStockObject(NULL_PEN));
+ HGDIOBJ oldBrush = SelectObject(dc, brush.get());
+ path.platformPath()->fillPath(dc, &tr);
+ SelectObject(dc, oldBrush);
+ } else {
+ SelectObject(m_data->m_dc, GetStockObject(NULL_PEN));
+ HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush.get());
+ path.platformPath()->fillPath(m_data->m_dc, &m_data->m_transform);
+ SelectObject(m_data->m_dc, oldBrush);
+ }
+}
+
+
+void GraphicsContext::strokePath(const Path& path)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+
+ if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
+ IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect()));
+ trRect.inflate(1);
+ TransparentLayerDC transparentDC(m_data, trRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+
+ AffineTransform tr = m_data->m_transform;
+ tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
+
+ SelectObject(dc, GetStockObject(NULL_BRUSH));
+ HGDIOBJ oldPen = SelectObject(dc, pen.get());
+ path.platformPath()->strokePath(dc, &tr);
+ SelectObject(dc, oldPen);
+ } else {
+ SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH));
+ HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen.get());
+ path.platformPath()->strokePath(m_data->m_dc, &m_data->m_transform);
+ SelectObject(m_data->m_dc, oldPen);
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ const Vector<Gradient::ColorStop>& stops = gradient->getStops();
+ if (stops.isEmpty())
+ return;
+
+ size_t numStops = stops.size();
+ if (numStops == 1) {
+ const Gradient::ColorStop& stop = stops.first();
+ Color color(stop.red, stop.green, stop.blue, stop.alpha);
+ fillRect(r, color, ColorSpaceDeviceRGB);
+ return;
+ }
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect intRect = enclosingIntRect(r);
+ IntRect rect = m_data->mapRect(intRect);
+ TransparentLayerDC transparentDC(m_data, rect, &intRect, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+
+ rect.move(transparentDC.toShift());
+ FloatPoint fp0 = m_data->mapPoint(gradient->p0());
+ FloatPoint fp1 = m_data->mapPoint(gradient->p1());
+ IntPoint p0(stableRound(fp0.x()), stableRound(fp0.y()));
+ IntPoint p1(stableRound(fp1.x()), stableRound(fp1.y()));
+ p0 += transparentDC.toShift();
+ p1 += transparentDC.toShift();
+
+ if (gradient->isRadial()) {
+ if (g_radialGradientFiller) {
+ // FIXME: don't support 2D scaling at this time
+ double scale = (m_data->m_transform.a() + m_data->m_transform.d()) * 0.5;
+ float r0 = gradient->startRadius() * scale;
+ float r1 = gradient->endRadius() * scale;
+ g_radialGradientFiller(dc, rect, p0, p1, r0, r1, gradient->getStops());
+ return;
+ }
+ } else if (g_linearGradientFiller) {
+ g_linearGradientFiller(dc, rect, p0, p1, gradient->getStops());
+ return;
+ }
+
+ // Simple 1D linear solution that assumes p0 is on the top or left side, and p1 is on the right or bottom side
+ size_t numRects = (numStops - 1);
+ Vector<TRIVERTEX, 20> tv;
+ tv.resize(numRects * 2);
+ Vector<GRADIENT_RECT, 10> mesh;
+ mesh.resize(numRects);
+ int x = rect.x();
+ int y = rect.y();
+ int width = rect.width();
+ int height = rect.height();
+ FloatSize d = gradient->p1() - gradient->p0();
+ bool vertical = fabs(d.height()) > fabs(d.width());
+ for (size_t i = 0; i < numStops; ++i) {
+ const Gradient::ColorStop& stop = stops[i];
+ int iTv = i ? 2 * i - 1 : 0;
+ tv[iTv].Red = stop.red * 0xFFFF;
+ tv[iTv].Green = stop.green * 0xFFFF;
+ tv[iTv].Blue = stop.blue * 0xFFFF;
+ tv[iTv].Alpha = stop.alpha * 0xFFFF;
+ if (i) {
+ tv[iTv].x = vertical ? x + width: x + width * stop.stop;
+ tv[iTv].y = vertical ? y + height * stop.stop : y + height;
+ mesh[i - 1].UpperLeft = iTv - 1;
+ mesh[i - 1].LowerRight = iTv;
+ } else {
+ tv[iTv].x = x;
+ tv[iTv].y = y;
+ }
+
+ if (i && i < numRects) {
+ tv[iTv + 1] = tv[iTv];
+ if (vertical)
+ tv[iTv + 1].x = x;
+ else
+ tv[iTv + 1].y = y;
+ }
+ }
+
+ GradientFill(dc, tv.data(), tv.size(), mesh.data(), mesh.size(), vertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H);
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ return m_data->m_transform;
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ savePlatformState();
+
+ if (m_state.fillGradient)
+ fillRect(rect, m_state.fillGradient.get());
+ else
+ fillRect(rect, fillColor(), ColorSpaceDeviceRGB);
+
+ restorePlatformState();
+}
+
+void GraphicsContext::setPlatformShadow(const FloatSize&, float, const Color&, ColorSpace)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ notImplemented();
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ notImplemented();
+ return InterpolationDefault;
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+ notImplemented();
+}
+
+static inline bool isCharVisible(UChar c)
+{
+ return c && c != zeroWidthSpace;
+}
+
+void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPoint& point, int from, int to)
+{
+ if (paintingDisabled() || !fillColor().alpha() || !m_data->m_opacity)
+ return;
+
+ bool mustSupportAlpha = m_data->hasAlpha();
+
+ if (!mustSupportAlpha && fillColor().alpha() == 0xFF && m_data->m_opacity >= 1.0) {
+ font.drawText(this, run, point, from, to);
+ return;
+ }
+
+ float oldOpacity = m_data->m_opacity;
+ m_data->m_opacity *= fillColor().alpha() / 255.0;
+
+ FloatRect textRect = font.selectionRectForText(run, point, font.height(), from, to);
+ textRect.setY(textRect.y() - font.ascent());
+ IntRect trRect = enclosingIntRect(m_data->mapRect(textRect));
+ RECT bmpRect;
+ AlphaPaintType alphaPaintType = mustSupportAlpha ? AlphaPaintOther : AlphaPaintNone;
+ if (RefPtr<SharedBitmap> bmp = m_data->getTransparentLayerBitmap(trRect, alphaPaintType, bmpRect, true, mustSupportAlpha)) {
+ {
+ GraphicsContext gc(0);
+ gc.setBitmap(bmp);
+ gc.scale(FloatSize(m_data->m_transform.a(), m_data->m_transform.d()));
+ font.drawText(&gc, run, IntPoint(0, font.ascent()), from, to);
+ }
+ unsigned key1;
+ HDC memDC = bmp->getDC(&key1);
+ if (memDC) {
+ m_data->paintBackTransparentLayerBitmap(memDC, bmp.get(), trRect, alphaPaintType, bmpRect);
+ bmp->releaseDC(memDC, key1);
+ }
+ }
+
+ m_data->m_opacity = oldOpacity;
+}
+
+void GraphicsContext::drawText(const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ for (;;) {
+ if (!numGlyphs)
+ return;
+ if (isCharVisible(*glyphBuffer.glyphs(from)))
+ break;
+ ++from;
+ --numGlyphs;
+ }
+
+ double scaleX = m_data->m_transform.a();
+ double scaleY = m_data->m_transform.d();
+
+ int height = fontData->platformData().size() * scaleY;
+ int width = fontData->platformData().averageCharWidth() * scaleX;
+
+ if (!height || !width)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ HFONT hFont = height > 1
+ ? fontData->platformData().getScaledFontHandle(height, scaleX == scaleY ? 0 : width)
+ : 0;
+
+ FloatPoint startPoint(point.x(), point.y() - fontData->ascent());
+ FloatPoint trPoint = m_data->mapPoint(startPoint);
+ int y = stableRound(trPoint.y());
+
+ Color color = fillColor();
+ if (!color.alpha())
+ return;
+
+ COLORREF fontColor = RGB(color.red(), color.green(), color.blue());
+
+ if (!hFont) {
+ double offset = trPoint.x();
+ const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
+ if (scaleX == 1.)
+ for (int i = 1; i < numGlyphs; ++i)
+ offset += *advance++;
+ else
+ for (int i = 1; i < numGlyphs; ++i)
+ offset += *advance++ * scaleX;
+
+ offset += width;
+
+ OwnPtr<HPEN> hPen(CreatePen(PS_DASH, 1, fontColor));
+ HGDIOBJ oldPen = SelectObject(m_data->m_dc, hPen.get());
+
+ MoveToEx(m_data->m_dc, stableRound(trPoint.x()), y, 0);
+ LineTo(m_data->m_dc, stableRound(offset), y);
+
+ SelectObject(m_data->m_dc, oldPen);
+ return;
+ }
+
+ FloatSize shadowOffset;
+ float shadowBlur = 0;
+ Color shadowColor;
+ ColorSpace shadowColorSpace;
+ bool hasShadow = textDrawingMode() == TextModeFill
+ && getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace)
+ && shadowColor.alpha();
+ COLORREF shadowRGBColor;
+ FloatPoint trShadowPoint;
+ if (hasShadow) {
+ shadowRGBColor = RGB(shadowColor.red(), shadowColor.green(), shadowColor.blue());
+ trShadowPoint = m_data->mapPoint(startPoint + shadowOffset);
+ }
+
+ HGDIOBJ hOldFont = SelectObject(m_data->m_dc, hFont);
+ COLORREF oldTextColor = GetTextColor(m_data->m_dc);
+ int oldTextAlign = GetTextAlign(m_data->m_dc);
+ SetTextAlign(m_data->m_dc, 0);
+
+ int oldBkMode = GetBkMode(m_data->m_dc);
+ SetBkMode(m_data->m_dc, TRANSPARENT);
+
+ if (numGlyphs > 1) {
+ double offset = trPoint.x();
+ Vector<int, 256> glyphSpace(numGlyphs);
+ Vector<UChar, 256> text(numGlyphs);
+ int* curSpace = glyphSpace.data();
+ UChar* curChar = text.data();
+ const UChar* srcChar = glyphBuffer.glyphs(from);
+ const UChar* const srcCharEnd = srcChar + numGlyphs;
+ *curChar++ = *srcChar++;
+ int firstOffset = stableRound(offset);
+ int lastOffset = firstOffset;
+ const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
+ // FIXME: ExtTextOut() can flip over each word for RTL languages, even when TA_RTLREADING is off.
+ // (this can be GDI bug or font driver bug?)
+ // We are not clear how it processes characters and handles specified spaces. On the other side,
+ // our glyph buffer is already in the correct order for rendering. So, the solution is that we
+ // call ExtTextOut() for each single character when the text contains any RTL character.
+ // This solution is not perfect as it is slower than calling ExtTextOut() one time for all characters.
+ // Drawing characters one by one may be too slow.
+ bool drawOneByOne = false;
+ if (scaleX == 1.) {
+ for (; srcChar < srcCharEnd; ++srcChar) {
+ offset += *advance++;
+ int offsetInt = stableRound(offset);
+ if (isCharVisible(*srcChar)) {
+ if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
+ drawOneByOne = true;
+ *curChar++ = *srcChar;
+ *curSpace++ = offsetInt - lastOffset;
+ lastOffset = offsetInt;
+ }
+ }
+ } else {
+ for (; srcChar < srcCharEnd; ++srcChar) {
+ offset += *advance++ * scaleX;
+ int offsetInt = stableRound(offset);
+ if (isCharVisible(*srcChar)) {
+ if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
+ drawOneByOne = true;
+ *curChar++ = *srcChar;
+ *curSpace++ = offsetInt - lastOffset;
+ lastOffset = offsetInt;
+ }
+ }
+ }
+ numGlyphs = curChar - text.data();
+ if (hasShadow) {
+ SetTextColor(m_data->m_dc, shadowRGBColor);
+ if (drawOneByOne) {
+ int xShadow = firstOffset + stableRound(trShadowPoint.x() - trPoint.x());
+ int yShadow = stableRound(trShadowPoint.y());
+ for (int i = 0; i < numGlyphs; ++i) {
+ ExtTextOut(m_data->m_dc, xShadow, yShadow, 0, NULL, text.data() + i, 1, 0);
+ xShadow += glyphSpace[i];
+ }
+ } else
+ ExtTextOut(m_data->m_dc, firstOffset + stableRound(trShadowPoint.x() - trPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, text.data(), numGlyphs, glyphSpace.data());
+ }
+ SetTextColor(m_data->m_dc, fontColor);
+ if (drawOneByOne) {
+ int x = firstOffset;
+ for (int i = 0; i < numGlyphs; ++i) {
+ ExtTextOut(m_data->m_dc, x, y, 0, NULL, text.data() + i, 1, 0);
+ x += glyphSpace[i];
+ }
+ } else
+ ExtTextOut(m_data->m_dc, firstOffset, y, 0, NULL, text.data(), numGlyphs, glyphSpace.data());
+ } else {
+ UChar c = *glyphBuffer.glyphs(from);
+ if (hasShadow) {
+ SetTextColor(m_data->m_dc, shadowRGBColor);
+ ExtTextOut(m_data->m_dc, stableRound(trShadowPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, &c, 1, 0);
+ }
+ SetTextColor(m_data->m_dc, fontColor);
+ ExtTextOut(m_data->m_dc, stableRound(trPoint.x()), y, 0, NULL, &c, 1, 0);
+ }
+
+ SetTextAlign(m_data->m_dc, oldTextAlign);
+ SetTextColor(m_data->m_dc, oldTextColor);
+ SetBkMode(m_data->m_dc, oldBkMode);
+ SelectObject(m_data->m_dc, hOldFont);
+}
+
+void GraphicsContext::drawFrameControl(const IntRect& rect, unsigned type, unsigned state)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ const int boxWidthBest = 8;
+ const int boxHeightBest = 8;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ RECT rectWin = trRect;
+
+ if ((rectWin.right - rectWin.left) < boxWidthBest) {
+ RefPtr<SharedBitmap> bmp = SharedBitmap::create(IntSize(boxWidthBest, boxHeightBest), BitmapInfo::BitCount16, true);
+ SharedBitmap::DCHolder memDC(bmp.get());
+ if (memDC.get()) {
+ RECT tempRect = {0, 0, boxWidthBest, boxHeightBest};
+ DrawFrameControl(memDC.get(), &tempRect, type, state);
+
+ ::StretchBlt(dc, rectWin.left, rectWin.top, rectWin.right - rectWin.left, rectWin.bottom - rectWin.top, memDC.get(), 0, 0, boxWidthBest, boxHeightBest, SRCCOPY);
+ return;
+ }
+ }
+
+ DrawFrameControl(dc, &rectWin, type, state);
+}
+
+void GraphicsContext::drawFocusRect(const IntRect& rect)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ RECT rectWin = trRect;
+ DrawFocusRect(dc, &rectWin);
+}
+
+void GraphicsContext::paintTextField(const IntRect& rect, unsigned state)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ RECT rectWin = trRect;
+ DrawEdge(dc, &rectWin, EDGE_ETCHED, BF_RECT | BF_ADJUST);
+ FillRect(dc, &rectWin, reinterpret_cast<HBRUSH>(((state & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW) + 1));
+}
+
+void GraphicsContext::drawBitmap(SharedBitmap* bmp, const IntRect& dstRectIn, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect dstRect = m_data->mapRect(dstRectIn);
+ TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ dstRect.move(transparentDC.toShift());
+
+ bmp->draw(dc, dstRect, srcRect, compositeOp);
+
+ if (bmp->is16bit())
+ transparentDC.fillAlphaChannel();
+}
+
+void GraphicsContext::drawBitmapPattern(SharedBitmap* bmp, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRectIn, const IntSize& origSourceSize)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect intDstRect = enclosingIntRect(destRectIn);
+ IntRect trRect = m_data->mapRect(intDstRect);
+ TransparentLayerDC transparentDC(m_data, trRect, &intDstRect, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+ FloatRect movedDstRect = m_data->m_transform.inverse().mapRect(FloatRect(trRect));
+ FloatSize moved(movedDstRect.location() - destRectIn.location());
+ AffineTransform transform = m_data->m_transform;
+ transform.translate(moved.width(), moved.height());
+
+ bmp->drawPattern(dc, transform, tileRectIn, patternTransform, phase, styleColorSpace, op, destRectIn, origSourceSize);
+
+ if (!bmp->hasAlpha())
+ transparentDC.fillAlphaChannel();
+}
+
+void GraphicsContext::drawIcon(HICON icon, const IntRect& dstRectIn, UINT flags)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect dstRect = m_data->mapRect(dstRectIn);
+ TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ dstRect.move(transparentDC.toShift());
+
+ DrawIconEx(dc, dstRect.x(), dstRect.y(), icon, dstRect.width(), dstRect.height(), 0, NULL, flags);
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setLineDash(const DashArray&, float)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clipPath(const Path&, WindRule)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/ImageBufferData.h b/Source/WebCore/platform/graphics/wince/ImageBufferData.h
new file mode 100644
index 0000000..01b7d06
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/ImageBufferData.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+namespace WebCore {
+
+ class IntSize;
+ class ImageBufferData {
+ public:
+ ImageBufferData(const IntSize& size);
+ RefPtr<SharedBitmap> m_bitmap;
+ };
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp b/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp
new file mode 100644
index 0000000..537d27d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "Base64.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "ImageData.h"
+#include "NotImplemented.h"
+#include "SharedBitmap.h"
+#include "UnusedParam.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+class BufferedImage: public Image {
+
+public:
+ BufferedImage(const ImageBufferData* data)
+ : m_data(data)
+ {
+ }
+
+ virtual IntSize size() const { return IntSize(m_data->m_bitmap->width(), m_data->m_bitmap->height()); }
+ virtual void destroyDecodedData(bool destroyAll = true) {}
+ virtual unsigned decodedSize() const { return 0; }
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
+ virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect);
+
+ const ImageBufferData* m_data;
+};
+
+void BufferedImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ IntRect intDstRect = enclosingIntRect(dstRect);
+ IntRect intSrcRect(srcRect);
+ m_data->m_bitmap->draw(ctxt, intDstRect, intSrcRect, styleColorSpace, compositeOp);
+}
+
+void BufferedImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ m_data->m_bitmap->drawPattern(ctxt, tileRectIn, patternTransform, phase, styleColorSpace, op, destRect, size());
+}
+
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_bitmap(SharedBitmap::create(size, BitmapInfo::BitCount32, false))
+{
+ // http://www.w3.org/TR/2009/WD-html5-20090212/the-canvas-element.html#canvaspixelarray
+ // "When the canvas is initialized it must be set to fully transparent black."
+ m_bitmap->resetPixels(true);
+ m_bitmap->setHasAlpha(true);
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace colorSpace, RenderingMode, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ // FIXME: colorSpace is not used
+ UNUSED_PARAM(colorSpace);
+
+ m_context.set(new GraphicsContext(0));
+ m_context->setBitmap(m_data.m_bitmap);
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+bool ImageBuffer::drawsUsingCopy() const
+{
+ return true;
+}
+
+PassRefPtr<Image> ImageBuffer::copyImage() const
+{
+ return adoptRef(new BufferedImage(&m_data));
+}
+
+void ImageBuffer::clip(GraphicsContext*, const FloatRect&) const
+{
+ notImplemented();
+}
+
+void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
+ CompositeOperator op , bool useLowQualityScale)
+{
+ RefPtr<Image> imageCopy = copyImage();
+ context->drawImage(imageCopy.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
+}
+
+void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ RefPtr<Image> imageCopy = copyImage();
+ imageCopy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+}
+
+template <bool premultiplied>
+static PassRefPtr<ByteArray> getImageData(const IntRect& rect, const SharedBitmap* bitmap)
+{
+ RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
+
+ const unsigned char* src = static_cast<const unsigned char*>(bitmap->bytes());
+ if (!src)
+ return imageData.release();
+
+ IntRect sourceRect(0, 0, bitmap->width(), bitmap->height());
+ sourceRect.intersect(rect);
+ if (sourceRect.isEmpty())
+ return imageData.release();
+
+ unsigned char* dst = imageData->data();
+ memset(dst, 0, imageData->length());
+ src += (sourceRect.y() * bitmap->width() + sourceRect.x()) * 4;
+ dst += ((sourceRect.y() - rect.y()) * rect.width() + sourceRect.x() - rect.x()) * 4;
+ int bytesToCopy = sourceRect.width() * 4;
+ int srcSkip = (bitmap->width() - sourceRect.width()) * 4;
+ int dstSkip = (rect.width() - sourceRect.width()) * 4;
+ const unsigned char* dstEnd = dst + sourceRect.height() * rect.width() * 4;
+ while (dst < dstEnd) {
+ const unsigned char* dstRowEnd = dst + bytesToCopy;
+ while (dst < dstRowEnd) {
+ // Convert ARGB little endian to RGBA big endian
+ int blue = *src++;
+ int green = *src++;
+ int red = *src++;
+ int alpha = *src++;
+ if (premultiplied) {
+ *dst++ = static_cast<unsigned char>((red * alpha + 254) / 255);
+ *dst++ = static_cast<unsigned char>((green * alpha + 254) / 255);
+ *dst++ = static_cast<unsigned char>((blue * alpha + 254) / 255);
+ *dst++ = static_cast<unsigned char>(alpha);
+ } else {
+ *dst++ = static_cast<unsigned char>(red);
+ *dst++ = static_cast<unsigned char>(green);
+ *dst++ = static_cast<unsigned char>(blue);
+ *dst++ = static_cast<unsigned char>(alpha);
+ ++src;
+ }
+ }
+ src += srcSkip;
+ dst += dstSkip;
+ }
+
+ return imageData.release();
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<false>(rect, m_data.m_bitmap.get());
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<true>(rect, m_data.m_bitmap.get());
+}
+
+template <bool premultiplied>
+static void putImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, SharedBitmap* bitmap)
+{
+ unsigned char* dst = (unsigned char*)bitmap->bytes();
+ if (!dst)
+ return;
+
+ IntRect destRect(destPoint, sourceRect.size());
+ destRect.intersect(IntRect(0, 0, bitmap->width(), bitmap->height()));
+
+ if (destRect.isEmpty())
+ return;
+
+ const unsigned char* src = source->data();
+ dst += (destRect.y() * bitmap->width() + destRect.x()) * 4;
+ src += (sourceRect.y() * sourceSize.width() + sourceRect.x()) * 4;
+ int bytesToCopy = destRect.width() * 4;
+ int dstSkip = (bitmap->width() - destRect.width()) * 4;
+ int srcSkip = (sourceSize.width() - destRect.width()) * 4;
+ const unsigned char* dstEnd = dst + destRect.height() * bitmap->width() * 4;
+ while (dst < dstEnd) {
+ const unsigned char* dstRowEnd = dst + bytesToCopy;
+ while (dst < dstRowEnd) {
+ // Convert RGBA big endian to ARGB little endian
+ int red = *src++;
+ int green = *src++;
+ int blue = *src++;
+ int alpha = *src++;
+ if (premultiplied) {
+ *dst++ = static_cast<unsigned char>(blue * 255 / alpha);
+ *dst++ = static_cast<unsigned char>(green * 255 / alpha);
+ *dst++ = static_cast<unsigned char>(red * 255 / alpha);
+ *dst++ = static_cast<unsigned char>(alpha);
+ } else {
+ *dst++ = static_cast<unsigned char>(blue);
+ *dst++ = static_cast<unsigned char>(green);
+ *dst++ = static_cast<unsigned char>(red);
+ *dst++ = static_cast<unsigned char>(alpha);
+ }
+ }
+ src += srcSkip;
+ dst += dstSkip;
+ }
+}
+
+void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<false>(source, sourceSize, sourceRect, destPoint, m_data.m_bitmap.get());
+}
+
+void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<true>(source, sourceSize, sourceRect, destPoint, m_data.m_bitmap.get());
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ UNUSED_PARAM(lookUpTable);
+ notImplemented();
+}
+
+String ImageBuffer::toDataURL(const String& mimeType, const double*) const
+{
+ if (!m_data.m_bitmap->bytes())
+ return "data:,";
+
+ notImplemented();
+ return String();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp b/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp
new file mode 100644
index 0000000..c0b2b53
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile Inc.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include "ImageDecoder.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+#include "SharedBuffer.h"
+#include "TransformationMatrix.h"
+#include "WinceGraphicsExtras.h"
+#include <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+namespace WebCore {
+
+NativeImagePtr RGBA32Buffer::asNewNativeImage() const
+{
+ return SharedBitmap::create(m_backingStore, m_size, hasAlpha());
+}
+
+bool FrameData::clear(bool clearMetaData)
+{
+ if (clearMetaData)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ m_frame = 0;
+ return true;
+ }
+
+ return false;
+}
+
+bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
+{
+ if (!bmp)
+ return false;
+
+ BITMAP bmpInfo;
+ GetObject(bmp, sizeof(BITMAP), &bmpInfo);
+
+ ASSERT(bmpInfo.bmBitsPixel == 32);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+
+ OwnPtr<HDC> hdc(CreateCompatibleDC(0));
+ HGDIOBJ hOldBmp = SelectObject(hdc.get(), bmp);
+
+ {
+ GraphicsContext gc(hdc.get());
+
+ IntSize imageSize = BitmapImage::size();
+ if (size)
+ drawFrameMatchingSourceSize(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), ColorSpaceDeviceRGB, CompositeCopy);
+ else
+ draw(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0, 0, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy);
+ }
+
+ SelectObject(hdc.get(), hOldBmp);
+
+ return true;
+}
+
+void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ int frames = frameCount();
+ for (int i = 0; i < frames; ++i) {
+ RefPtr<SharedBitmap> bmp = frameAtIndex(i);
+ if (!bmp || bmp->height() != static_cast<unsigned>(srcSize.height()) || bmp->width() != static_cast<unsigned>(srcSize.width()))
+ continue;
+
+ size_t currentFrame = m_currentFrame;
+ m_currentFrame = i;
+ draw(ctxt, dstRect, FloatRect(0, 0, srcSize.width(), srcSize.height()), styleColorSpace, compositeOp);
+ m_currentFrame = currentFrame;
+ return;
+ }
+
+ // No image of the correct size was found, fallback to drawing the current frame
+ IntSize imageSize = BitmapImage::size();
+ draw(ctxt, dstRect, FloatRect(0, 0, imageSize.width(), imageSize.height()), styleColorSpace, compositeOp);
+}
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRectIn, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ if (!m_source.initialized())
+ return;
+
+ if (mayFillWithSolidColor())
+ fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, compositeOp);
+ else {
+ IntRect intSrcRect(srcRectIn);
+ RefPtr<SharedBitmap> bmp = frameAtIndex(m_currentFrame);
+
+ if (bmp->width() != m_source.size().width()) {
+ double scaleFactor = static_cast<double>(bmp->width()) / m_source.size().width();
+
+ intSrcRect.setX(stableRound(srcRectIn.x() * scaleFactor));
+ intSrcRect.setWidth(stableRound(srcRectIn.width() * scaleFactor));
+ intSrcRect.setY(stableRound(srcRectIn.y() * scaleFactor));
+ intSrcRect.setHeight(stableRound(srcRectIn.height() * scaleFactor));
+ }
+ bmp->draw(ctxt, enclosingIntRect(dstRect), intSrcRect, styleColorSpace, compositeOp);
+ }
+
+ startAnimation();
+}
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ notImplemented();
+}
+
+void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ RefPtr<SharedBitmap> bmp = nativeImageForCurrentFrame();
+ if (!bmp)
+ return;
+
+ bmp->drawPattern(ctxt, tileRectIn, patternTransform, phase, styleColorSpace, op, destRect, m_source.size());
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ if (m_checkedForSolidColor)
+ return;
+
+ if (frameCount() != 1) {
+ m_isSolidColor = false;
+ m_checkedForSolidColor = true;
+ return;
+ }
+
+ RefPtr<SharedBitmap> bmp = frameAtIndex(0);
+ if (!bmp || !bmp->validHeight()) {
+ m_isSolidColor = false;
+ return;
+ }
+
+ if (bmp->width() != 1 || bmp->validHeight() != 1) {
+ m_isSolidColor = false;
+ m_checkedForSolidColor = true;
+ return;
+ }
+
+ m_isSolidColor = true;
+
+ if (bmp->is16bit()) {
+ unsigned short c = ((unsigned short *)bmp->bytes())[0];
+ int r = (c >> 7) & 0xF8;
+ int g = (c >> 2) & 0xF8;
+ int b = (c << 3) & 0xF8;
+ if (bmp->usesTransparentColor() && bmp->transparentColor() == RGB(r, g, b))
+ m_solidColor = Color(r, g, b, 0);
+ else
+ m_solidColor = Color(r, g, b);
+ } else {
+ unsigned c = ((unsigned *)bmp->bytes())[0];
+ m_solidColor = Color(c);
+ }
+
+ if (bmp->validHeight() == bmp->height())
+ m_checkedForSolidColor = true;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/MediaPlayerPrivateWinCE.h b/Source/WebCore/platform/graphics/wince/MediaPlayerPrivateWinCE.h
new file mode 100644
index 0000000..f49d8e2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/MediaPlayerPrivateWinCE.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 MediaPlayerPrivateWinCE_h
+#define MediaPlayerPrivateWinCE_h
+
+#if ENABLE(VIDEO)
+
+#include <wtf/Forward.h>
+#include "MediaPlayerPrivate.h"
+#include "Timer.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+ class GraphicsContext;
+ class IntSize;
+ class IntRect;
+
+ class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
+ public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+
+ ~MediaPlayerPrivate();
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+
+ void load(const String& url);
+ void cancelLoad();
+
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float time);
+
+ void setRate(float);
+ void setVolume(float);
+
+ MediaPlayer::NetworkState networkState() const { return m_networkState; }
+ MediaPlayer::ReadyState readyState() const { return m_readyState; }
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setSize(const IntSize&);
+
+ void loadStateChanged();
+ void didEnd();
+
+ void paint(GraphicsContext*, const IntRect&);
+
+ private:
+ MediaPlayerPrivate(MediaPlayer*);
+
+ void updateStates();
+ void doSeek();
+ void cancelSeek();
+ void seekTimerFired(Timer<MediaPlayerPrivate>*);
+ float maxTimeLoaded() const;
+ void sawUnsupportedTracks();
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ void setMediaPlayerProxy(WebMediaPlayerProxy*);
+ void setPoster(const String& url);
+ void deliverNotification(MediaPlayerProxyNotificationType);
+#endif
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer*);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
+ MediaPlayer* m_player;
+ float m_seekTo;
+ float m_endTime;
+ Timer<MediaPlayerPrivate> m_seekTimer;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ unsigned m_enabledTrackCount;
+ unsigned m_totalTrackCount;
+ bool m_hasUnsupportedTracks;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ WebMediaPlayerProxy* m_proxy;
+#endif
+ };
+
+}
+
+#endif // ENABLE(VIDEO)
+
+#endif // MediaPlayerPrivateWinCE_h
diff --git a/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp b/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp
new file mode 100644
index 0000000..6fb262d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#if ENABLE(VIDEO)
+
+#include "config.h"
+#include "MediaPlayerProxy.h"
+
+#include "Bridge.h"
+#include "DocumentLoader.h"
+#include "HTMLPlugInElement.h"
+#include "HTMLVideoElement.h"
+#include "JSDOMBinding.h"
+#include "JSPluginElementFunctions.h"
+#include "MediaPlayer.h"
+#include "Node.h"
+#include "PlatformString.h"
+#include "PluginView.h"
+#include "RenderPartObject.h"
+#include "RenderWidget.h"
+#include "Widget.h"
+#include "c_class.h"
+#include "c_instance.h"
+#include "c_runtime.h"
+#include "npruntime_impl.h"
+#include <runtime/Identifier.h>
+
+using namespace JSC;
+
+namespace WebCore {
+
+using namespace Bindings;
+using namespace HTMLNames;
+
+WebMediaPlayerProxy::WebMediaPlayerProxy(MediaPlayer* player)
+ : m_mediaPlayer(player)
+ , m_init(false)
+ , m_hasSentResponseToPlugin(false)
+{
+ if (!m_init)
+ initEngine();
+}
+
+WebMediaPlayerProxy::~WebMediaPlayerProxy()
+{
+ m_instance.release();
+}
+
+ScriptInstance WebMediaPlayerProxy::pluginInstance()
+{
+ if (!m_instance) {
+ RenderObject* r = element()->renderer();
+ if (!r || !r->isWidget())
+ return 0;
+
+ Frame* frame = element()->document()->frame();
+
+ RenderWidget* renderWidget = static_cast<RenderWidget*>(element()->renderer());
+ if (renderWidget && renderWidget->widget())
+ m_instance = frame->script()->createScriptInstanceForWidget(renderWidget->widget());
+ }
+
+ return m_instance;
+}
+
+void WebMediaPlayerProxy::load(const String& url)
+{
+ if (!m_init)
+ initEngine();
+ if (m_init)
+ invokeMethod("play");
+}
+
+void WebMediaPlayerProxy::initEngine()
+{
+ HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_mediaPlayer->mediaPlayerClient());
+ String url = element->initialURL();
+
+ if (url.isEmpty())
+ return;
+
+ Frame* frame = element->document()->frame();
+ Vector<String> paramNames;
+ Vector<String> paramValues;
+ String serviceType;
+
+ // add all attributes set on the embed object
+ if (NamedNodeMap* attributes = element->attributes()) {
+ for (unsigned i = 0; i < attributes->length(); ++i) {
+ Attribute* it = attributes->attributeItem(i);
+ paramNames.append(it->name().localName().string());
+ paramValues.append(it->value().string());
+ }
+ }
+ serviceType = "application/x-mplayer2";
+ frame->loader()->subframeLoader()->requestObject(static_cast<RenderPartObject*>(element->renderer()), url, nullAtom, serviceType, paramNames, paramValues);
+ m_init = true;
+
+}
+
+HTMLMediaElement* WebMediaPlayerProxy::element()
+{
+ return static_cast<HTMLMediaElement*>(m_mediaPlayer->mediaPlayerClient());
+
+}
+
+void WebMediaPlayerProxy::invokeMethod(const String& methodName)
+{
+ Frame* frame = element()->document()->frame();
+ RootObject *root = frame->script()->bindingRootObject();
+ if (!root)
+ return;
+ ExecState *exec = root->globalObject()->globalExec();
+ Instance* instance = pluginInstance().get();
+ if (!instance)
+ return;
+
+ instance->begin();
+ Class *aClass = instance->getClass();
+ Identifier iden(exec, methodName);
+ MethodList methodList = aClass->methodsNamed(iden, instance);
+ ArgList args;
+ instance->invokeMethod(exec, methodList , args);
+ instance->end();
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.h b/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.h
new file mode 100644
index 0000000..b02e0f4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef MediaPlayerProxy_h
+#define MediaPlayerProxy_h
+
+#if ENABLE(VIDEO)
+
+#include <wtf/Forward.h>
+#include "ScriptInstance.h"
+
+namespace WebCore {
+
+ class IntRect;
+ class IntSize;
+ class MediaPlayer;
+ class PluginView;
+ class HTMLMediaElement;
+
+ enum MediaPlayerProxyNotificationType {
+ MediaPlayerNotificationPlayPauseButtonPressed,
+ Idle,
+ Loading,
+ Loaded,
+ FormatError,
+ NetworkError,
+ DecodeError
+ };
+
+ class WebMediaPlayerProxy {
+ public:
+ WebMediaPlayerProxy(MediaPlayer* player);
+ ~WebMediaPlayerProxy();
+
+ MediaPlayer* mediaPlayer() {return m_mediaPlayer;}
+ void initEngine();
+ void load(const String& url);
+ HTMLMediaElement* element();
+ void invokeMethod(const String& methodName);
+ ScriptInstance pluginInstance();
+
+ private:
+ MediaPlayer* m_mediaPlayer;
+ bool m_init;
+ WebCore::PluginView* m_pluginView;
+ bool m_hasSentResponseToPlugin;
+ ScriptInstance m_instance;
+ };
+
+}
+#endif // ENABLE(VIDEO)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/wince/PathWinCE.cpp b/Source/WebCore/platform/graphics/wince/PathWinCE.cpp
new file mode 100644
index 0000000..fa4c8fb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/PathWinCE.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "NotImplemented.h"
+#include "PlatformPathWinCE.h"
+#include "PlatformString.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+Path::Path()
+ : m_path(new PlatformPath())
+{
+}
+
+Path::Path(const Path& other)
+ : m_path(new PlatformPath(*other.m_path))
+{
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path& Path::operator=(const Path& other)
+{
+ if (&other != this) {
+ delete m_path;
+ m_path = new PlatformPath(*other.m_path);
+ }
+ return *this;
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ return m_path->contains(point, rule);
+}
+
+void Path::translate(const FloatSize& size)
+{
+ m_path->translate(size);
+}
+
+FloatRect Path::boundingRect() const
+{
+ return m_path->boundingRect();
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ m_path->moveTo(point);
+}
+
+void Path::addLineTo(const FloatPoint& point)
+{
+ m_path->addLineTo(point);
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
+{
+ m_path->addQuadCurveTo(cp, p);
+}
+
+void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
+{
+ m_path->addBezierCurveTo(cp1, cp2, p);
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ m_path->addArcTo(p1, p2, radius);
+}
+
+void Path::closeSubpath()
+{
+ m_path->closeSubpath();
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise)
+{
+ m_path->addEllipse(p, r, r, sar, ear, anticlockwise);
+}
+
+void Path::addRect(const FloatRect& r)
+{
+ m_path->addRect(r);
+}
+
+void Path::addEllipse(const FloatRect& r)
+{
+ m_path->addEllipse(r);
+}
+
+void Path::clear()
+{
+ m_path->clear();
+}
+
+bool Path::isEmpty() const
+{
+ return m_path->isEmpty();
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ m_path->apply(info, function);
+}
+
+void Path::transform(const AffineTransform& t)
+{
+ m_path->transform(t);
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier *)
+{
+ notImplemented();
+ return FloatRect();
+}
+
+bool Path::strokeContains(StrokeStyleApplier*, const FloatPoint&) const
+{
+ notImplemented();
+ return false;
+}
+
+bool Path::hasCurrentPoint() const
+{
+ // Not sure if this is correct. At the meantime, we do what other ports
+ // do.
+ // See https://bugs.webkit.org/show_bug.cgi?id=27266,
+ // https://bugs.webkit.org/show_bug.cgi?id=27187, and
+ // http://trac.webkit.org/changeset/45873
+ return !isEmpty();
+}
+
+FloatPoint Path::currentPoint() const
+{
+ return m_path->lastPoint();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp
new file mode 100644
index 0000000..8534f89
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp
@@ -0,0 +1,772 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "PlatformPathWinCE.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "Path.h"
+#include "PlatformString.h"
+#include "WinCEGraphicsExtras.h"
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+namespace WebCore {
+
+// Implemented in GraphicsContextWinCE.cpp
+void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y);
+
+static void quadCurve(int segments, Vector<PathPoint>& pts, const PathPoint* control)
+{
+ const float step = 1.0 / segments;
+ register float tA = 0.0;
+ register float tB = 1.0;
+
+ float c1x = control[0].x();
+ float c1y = control[0].y();
+ float c2x = control[1].x();
+ float c2y = control[1].y();
+ float c3x = control[2].x();
+ float c3y = control[2].y();
+
+ const int offset = pts.size();
+ pts.resize(offset + segments);
+ PathPoint pp;
+ pp.m_x = c1x;
+ pp.m_y = c1y;
+
+ for (int i = 1; i < segments; ++i) {
+ tA += step;
+ tB -= step;
+
+ const float a = tB * tB;
+ const float b = 2.0 * tA * tB;
+ const float c = tA * tA;
+
+ pp.m_x = c1x * a + c2x * b + c3x * c;
+ pp.m_y = c1y * a + c2y * b + c3y * c;
+
+ pts[offset + i - 1] = pp;
+ }
+
+ pp.m_x = c3x;
+ pp.m_y = c3y;
+ pts[offset + segments - 1] = pp;
+}
+
+static inline void bezier(int segments, Vector<PathPoint>& pts, const PathPoint* control)
+{
+ const float step = 1.0 / segments;
+ register float tA = 0.0;
+ register float tB = 1.0;
+
+ float c1x = control[0].x();
+ float c1y = control[0].y();
+ float c2x = control[1].x();
+ float c2y = control[1].y();
+ float c3x = control[2].x();
+ float c3y = control[2].y();
+ float c4x = control[3].x();
+ float c4y = control[3].y();
+
+ const int offset = pts.size();
+ pts.resize(offset + segments);
+ PathPoint pp;
+ pp.m_x = c1x;
+ pp.m_y = c1y;
+
+ for (int i = 1; i < segments; ++i) {
+ tA += step;
+ tB -= step;
+ const float tAsq = tA * tA;
+ const float tBsq = tB * tB;
+
+ const float a = tBsq * tB;
+ const float b = 3.0 * tA * tBsq;
+ const float c = 3.0 * tB * tAsq;
+ const float d = tAsq * tA;
+
+ pp.m_x = c1x * a + c2x * b + c3x * c + c4x * d;
+ pp.m_y = c1y * a + c2y * b + c3y * c + c4y * d;
+
+ pts[offset + i - 1] = pp;
+ }
+
+ pp.m_x = c4x;
+ pp.m_y = c4y;
+ pts[offset + segments - 1] = pp;
+}
+
+static bool containsPoint(const FloatRect& r, const FloatPoint& p)
+{
+ return p.x() >= r.x() && p.y() >= r.y() && p.x() < r.right() && p.y() < r.bottom();
+}
+
+static void normalizeAngle(float& angle)
+{
+ angle = fmod(angle, 2 * piFloat);
+ if (angle < 0)
+ angle += 2 * piFloat;
+ if (angle < 0.00001f)
+ angle = 0;
+}
+
+static void transformArcPoint(float& x, float& y, const FloatPoint& c)
+{
+ x += c.x();
+ y += c.y();
+}
+
+static void inflateRectToContainPoint(FloatRect& r, float x, float y)
+{
+ if (r.isEmpty()) {
+ r.setX(x);
+ r.setY(y);
+ r.setSize(FloatSize(1, 1));
+ return;
+ }
+ if (x < r.x()) {
+ r.setWidth(r.right() - x);
+ r.setX(x);
+ } else {
+ float w = x - r.x() + 1;
+ if (w > r.width())
+ r.setWidth(w);
+ }
+ if (y < r.y()) {
+ r.setHeight(r.bottom() - y);
+ r.setY(y);
+ } else {
+ float h = y - r.y() + 1;
+ if (h > r.height())
+ r.setHeight(h);
+ }
+}
+
+// return 0-based value: 0 - first Quadrant ( 0 - 90 degree)
+static inline int quadrant(const PathPoint& point, const PathPoint& origin)
+{
+ return point.m_x < origin.m_x ?
+ (point.m_y < origin.m_y ? 2 : 1)
+ : (point.m_y < origin.m_y ? 3 : 0);
+}
+
+static inline bool isQuadrantOnLeft(int q) { return q == 1 || q == 2; }
+static inline bool isQuadrantOnRight(int q) { return q == 0 || q == 3; }
+static inline bool isQuadrantOnTop(int q) { return q == 2 || q == 3; }
+static inline bool isQuadrantOnBottom(int q) { return q == 0 || q == 1; }
+
+static inline int nextQuadrant(int q) { return q == 3 ? 0 : q + 1; }
+static inline int quadrantDiff(int q1, int q2)
+{
+ int d = q1 - q2;
+ while (d < 0)
+ d += 4;
+ return d;
+}
+
+struct PathVector {
+ float m_x;
+ float m_y;
+
+ PathVector() : m_x(0), m_y(0) {}
+ PathVector(float x, float y) : m_x(x), m_y(y) {}
+ double angle() const { return atan2(m_y, m_x); }
+ operator double () const { return angle(); }
+ double length() const { return _hypot(m_x, m_y); }
+};
+
+PathVector operator-(const PathPoint& p1, const PathPoint& p2)
+{
+ return PathVector(p1.m_x - p2.m_x, p1.m_y - p2.m_y);
+}
+
+static void addArcPoint(PathPolygon& poly, const PathPoint& center, const PathPoint& radius, double angle)
+{
+ PathPoint p;
+ getEllipsePointByAngle(angle, radius.m_x, radius.m_y, p.m_x, p.m_y);
+ transformArcPoint(p.m_x, p.m_y, center);
+ if (poly.isEmpty() || poly.last() != p)
+ poly.append(p);
+}
+
+static void addArcPoints(PathPolygon& poly, const PlatformPathElement::ArcTo& data)
+{
+ const PathPoint& startPoint = poly.last();
+ double curAngle = startPoint - data.m_center;
+ double endAngle = data.m_end - data.m_center;
+ double angleStep = 2. / std::max(data.m_radius.m_x, data.m_radius.m_y);
+ if (data.m_clockwise) {
+ if (endAngle <= curAngle || startPoint == data.m_end)
+ endAngle += 2 * piDouble;
+ } else {
+ angleStep = -angleStep;
+ if (endAngle >= curAngle || startPoint == data.m_end)
+ endAngle -= 2 * piDouble;
+ }
+
+ for (curAngle += angleStep; data.m_clockwise ? curAngle < endAngle : curAngle > endAngle; curAngle += angleStep)
+ addArcPoint(poly, data.m_center, data.m_radius, curAngle);
+
+ if (poly.isEmpty() || poly.last() != data.m_end)
+ poly.append(data.m_end);
+}
+
+static void drawPolygons(HDC dc, const Vector<PathPolygon>& polygons, bool fill, const AffineTransform* transformation)
+{
+ for (Vector<PathPolygon>::const_iterator i = polygons.begin(); i != polygons.end(); ++i) {
+ int npoints = i->size();
+ if (!npoints)
+ continue;
+
+ POINT* winPoints = 0;
+ if (fill) {
+ if (npoints > 2)
+ winPoints = new POINT[npoints + 1];
+ } else
+ winPoints = new POINT[npoints];
+
+ if (winPoints) {
+ if (transformation) {
+ for (int i2 = 0; i2 < npoints; ++i2) {
+ FloatPoint trPoint = transformation->mapPoint(i->at(i2));
+ winPoints[i2].x = stableRound(trPoint.x());
+ winPoints[i2].y = stableRound(trPoint.y());
+ }
+ } else {
+ for (int i2 = 0; i2 < npoints; ++i2) {
+ winPoints[i2].x = stableRound(i->at(i2).x());
+ winPoints[i2].y = stableRound(i->at(i2).y());
+ }
+ }
+
+ if (fill && winPoints[npoints - 1] != winPoints[0]) {
+ winPoints[npoints].x = winPoints[0].x;
+ winPoints[npoints].y = winPoints[0].y;
+ ++npoints;
+ }
+
+ if (fill)
+ ::Polygon(dc, winPoints, npoints);
+ else
+ ::Polyline(dc, winPoints, npoints);
+ delete[] winPoints;
+ }
+ }
+}
+
+
+int PlatformPathElement::numControlPoints() const
+{
+ switch (m_type) {
+ case PathMoveTo:
+ case PathLineTo:
+ return 1;
+ case PathQuadCurveTo:
+ case PathArcTo:
+ return 2;
+ case PathBezierCurveTo:
+ return 3;
+ default:
+ ASSERT(m_type == PathCloseSubpath);
+ return 0;
+ }
+}
+
+int PlatformPathElement::numPoints() const
+{
+ switch (m_type) {
+ case PathMoveTo:
+ case PathLineTo:
+ case PathArcTo:
+ return 1;
+ case PathQuadCurveTo:
+ return 2;
+ case PathBezierCurveTo:
+ return 3;
+ default:
+ ASSERT(m_type == PathCloseSubpath);
+ return 0;
+ }
+}
+
+void PathPolygon::move(const FloatSize& offset)
+{
+ for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i)
+ i->move(offset);
+}
+
+void PathPolygon::transform(const AffineTransform& t)
+{
+ for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i)
+ *i = t.mapPoint(*i);
+}
+
+bool PathPolygon::contains(const FloatPoint& point) const
+{
+ if (size() < 3)
+ return false;
+
+ // Test intersections between the polygon and the vertical line: x = point.x()
+
+ int intersected = 0;
+ const PathPoint* point1 = &last();
+ Vector<PathPoint>::const_iterator last = end();
+ // wasNegative: -1 means unknown, 0 means false, 1 means true.
+ int wasNegative = -1;
+ for (Vector<PathPoint>::const_iterator i = begin(); i != last; ++i) {
+ const PathPoint& point2 = *i;
+ if (point1->x() != point.x()) {
+ if (point2.x() == point.x()) {
+ // We are getting on the vertical line
+ wasNegative = point1->x() < point.x() ? 1 : 0;
+ } else if (point2.x() < point.x() != point1->x() < point.x()) {
+ float y = (point2.y() - point1->y()) / (point2.x() - point1->x()) * (point.x() - point1->x()) + point1->y();
+ if (y >= point.y())
+ ++intersected;
+ }
+ } else {
+ // We were on the vertical line
+
+ // handle special case
+ if (point1->y() == point.y())
+ return true;
+
+ if (point1->y() > point.y()) {
+ if (point2.x() == point.x()) {
+ // see if the point is on this segment
+ if (point2.y() <= point.y())
+ return true;
+
+ // We are still on the line
+ } else {
+ // We are leaving the line now.
+ // We have to get back to see which side we come from. If we come from
+ // the same side we are leaving, no intersection should be counted
+ if (wasNegative < 0) {
+ Vector<PathPoint>::const_iterator jLast = i;
+ Vector<PathPoint>::const_iterator j = i;
+ do {
+ if (j == begin())
+ j = last;
+ else
+ --j;
+ if (j->x() != point.x()) {
+ if (j->x() > point.x())
+ wasNegative = 0;
+ else
+ wasNegative = 1;
+ break;
+ }
+ } while (j != jLast);
+
+ if (wasNegative < 0)
+ return false;
+ }
+ if (wasNegative ? point2.x() > point.x() : point2.x() < point.x())
+ ++intersected;
+ }
+ } else if (point2.x() == point.x() && point2.y() >= point.y())
+ return true;
+ }
+ point1 = &point2;
+ }
+
+ return intersected & 1;
+}
+
+void PlatformPathElement::move(const FloatSize& offset)
+{
+ int n = numControlPoints();
+ for (int i = 0; i < n; ++i)
+ m_data.m_points[i].move(offset);
+}
+
+void PlatformPathElement::transform(const AffineTransform& t)
+{
+ int n = numControlPoints();
+ for (int i = 0; i < n; ++i) {
+ FloatPoint p = t.mapPoint(m_data.m_points[i]);
+ m_data.m_points[i].set(p.x(), p.y());
+ }
+}
+
+void PlatformPathElement::inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const
+{
+ if (m_type == PathArcTo) {
+ const ArcTo& data = m_data.m_arcToData;
+ PathPoint startPoint;
+ startPoint = lastPoint;
+ PathPoint endPoint = data.m_end;
+ if (!data.m_clockwise)
+ std::swap(startPoint, endPoint);
+
+ int q0 = quadrant(startPoint, data.m_center);
+ int q1 = quadrant(endPoint, data.m_center);
+ bool containsExtremes[4] = { false }; // bottom, left, top, right
+ static const PathPoint extremeVectors[4] = { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } };
+ if (q0 == q1) {
+ if (startPoint.m_x == endPoint.m_x || isQuadrantOnBottom(q0) != startPoint.m_x > endPoint.m_x) {
+ for (int i = 0; i < 4; ++i)
+ containsExtremes[i] = true;
+ }
+ } else {
+ int extreme = q0;
+ int diff = quadrantDiff(q1, q0);
+ for (int i = 0; i < diff; ++i) {
+ containsExtremes[extreme] = true;
+ extreme = nextQuadrant(extreme);
+ }
+ }
+
+ inflateRectToContainPoint(r, startPoint.m_x, startPoint.m_y);
+ inflateRectToContainPoint(r, endPoint.m_x, endPoint.m_y);
+ for (int i = 0; i < 4; ++i) {
+ if (containsExtremes[i])
+ inflateRectToContainPoint(r, data.m_center.m_x + data.m_radius.m_x * extremeVectors[i].m_x, data.m_center.m_y + data.m_radius.m_y * extremeVectors[i].m_y);
+ }
+ } else {
+ int n = numPoints();
+ for (int i = 0; i < n; ++i)
+ inflateRectToContainPoint(r, m_data.m_points[i].m_x, m_data.m_points[i].m_y);
+ }
+}
+
+PathElementType PlatformPathElement::type() const
+{
+ switch (m_type) {
+ case PathMoveTo:
+ return PathElementMoveToPoint;
+ case PathLineTo:
+ return PathElementAddLineToPoint;
+ case PathArcTo:
+ // FIXME: there's no arcTo type for PathElement
+ return PathElementAddLineToPoint;
+ // return PathElementAddQuadCurveToPoint;
+ case PathQuadCurveTo:
+ return PathElementAddQuadCurveToPoint;
+ case PathBezierCurveTo:
+ return PathElementAddCurveToPoint;
+ default:
+ ASSERT(m_type == PathCloseSubpath);
+ return PathElementCloseSubpath;
+ }
+}
+
+PlatformPath::PlatformPath()
+ : m_penLifted(true)
+{
+ m_currentPoint.clear();
+}
+
+void PlatformPath::ensureSubpath()
+{
+ if (m_penLifted) {
+ m_penLifted = false;
+ m_subpaths.append(PathPolygon());
+ m_subpaths.last().append(m_currentPoint);
+ } else
+ ASSERT(!m_subpaths.isEmpty());
+}
+
+void PlatformPath::addToSubpath(const PlatformPathElement& e)
+{
+ if (e.platformType() == PlatformPathElement::PathMoveTo) {
+ m_penLifted = true;
+ m_currentPoint = e.pointAt(0);
+ } else if (e.platformType() == PlatformPathElement::PathCloseSubpath) {
+ m_penLifted = true;
+ if (!m_subpaths.isEmpty()) {
+ if (m_currentPoint != m_subpaths.last()[0]) {
+ // According to W3C, we have to draw a line from current point to the initial point
+ m_subpaths.last().append(m_subpaths.last()[0]);
+ m_currentPoint = m_subpaths.last()[0];
+ }
+ } else
+ m_currentPoint.clear();
+ } else {
+ ensureSubpath();
+ switch (e.platformType()) {
+ case PlatformPathElement::PathLineTo:
+ m_subpaths.last().append(e.pointAt(0));
+ break;
+ case PlatformPathElement::PathArcTo:
+ addArcPoints(m_subpaths.last(), e.arcTo());
+ break;
+ case PlatformPathElement::PathQuadCurveTo:
+ {
+ PathPoint control[] = {
+ m_currentPoint,
+ e.pointAt(0),
+ e.pointAt(1),
+ };
+ // FIXME: magic number?
+ quadCurve(50, m_subpaths.last(), control);
+ }
+ break;
+ case PlatformPathElement::PathBezierCurveTo:
+ {
+ PathPoint control[] = {
+ m_currentPoint,
+ e.pointAt(0),
+ e.pointAt(1),
+ e.pointAt(2),
+ };
+ // FIXME: magic number?
+ bezier(100, m_subpaths.last(), control);
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ m_currentPoint = m_subpaths.last().last();
+ }
+}
+
+void PlatformPath::append(const PlatformPathElement& e)
+{
+ e.inflateRectToContainMe(m_boundingRect, lastPoint());
+ addToSubpath(e);
+ m_elements.append(e);
+}
+
+void PlatformPath::append(const PlatformPath& p)
+{
+ const PlatformPathElements& e = p.elements();
+ for (PlatformPathElements::const_iterator it(e.begin()); it != e.end(); ++it) {
+ addToSubpath(*it);
+ it->inflateRectToContainMe(m_boundingRect, lastPoint());
+ m_elements.append(*it);
+ }
+}
+
+void PlatformPath::clear()
+{
+ m_elements.clear();
+ m_boundingRect = FloatRect();
+ m_subpaths.clear();
+ m_currentPoint.clear();
+ m_penLifted = true;
+}
+
+void PlatformPath::strokePath(HDC dc, const AffineTransform* transformation) const
+{
+ drawPolygons(dc, m_subpaths, false, transformation);
+}
+
+void PlatformPath::fillPath(HDC dc, const AffineTransform* transformation) const
+{
+ HGDIOBJ oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
+ drawPolygons(dc, m_subpaths, true, transformation);
+ SelectObject(dc, oldPen);
+}
+
+void PlatformPath::translate(const FloatSize& size)
+{
+ for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it)
+ it->move(size);
+
+ m_boundingRect.move(size);
+ for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it)
+ it->move(size);
+}
+
+void PlatformPath::transform(const AffineTransform& t)
+{
+ for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it)
+ it->transform(t);
+
+ m_boundingRect = t.mapRect(m_boundingRect);
+ for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it)
+ it->transform(t);
+}
+
+bool PlatformPath::contains(const FloatPoint& point, WindRule rule) const
+{
+ // optimization: check the bounding rect first
+ if (!containsPoint(m_boundingRect, point))
+ return false;
+
+ for (Vector<PathPolygon>::const_iterator i = m_subpaths.begin(); i != m_subpaths.end(); ++i) {
+ if (i->contains(point))
+ return true;
+ }
+
+ return false;
+}
+
+void PlatformPath::moveTo(const FloatPoint& point)
+{
+ PlatformPathElement::MoveTo data = { { point.x(), point.y() } };
+ PlatformPathElement pe(data);
+ append(pe);
+}
+
+void PlatformPath::addLineTo(const FloatPoint& point)
+{
+ PlatformPathElement::LineTo data = { { point.x(), point.y() } };
+ PlatformPathElement pe(data);
+ append(pe);
+}
+
+void PlatformPath::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
+{
+ PlatformPathElement::QuadCurveTo data = { { cp.x(), cp.y() }, { p.x(), p.y() } };
+ PlatformPathElement pe(data);
+ append(pe);
+}
+
+void PlatformPath::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
+{
+ PlatformPathElement::BezierCurveTo data = { { cp1.x(), cp1.y() }, { cp2.x(), cp2.y() }, { p.x(), p.y() } };
+ PlatformPathElement pe(data);
+ append(pe);
+}
+
+void PlatformPath::addArcTo(const FloatPoint& fp1, const FloatPoint& fp2, float radius)
+{
+ const PathPoint& p0 = m_currentPoint;
+ PathPoint p1;
+ p1 = fp1;
+ PathPoint p2;
+ p2 = fp2;
+ if (!radius || p0 == p1 || p1 == p2) {
+ addLineTo(p1);
+ return;
+ }
+
+ PathVector v01 = p0 - p1;
+ PathVector v21 = p2 - p1;
+
+ // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A)
+ double cross = v01.m_x * v21.m_y - v01.m_y * v21.m_x;
+
+ if (fabs(cross) < 1E-10) {
+ // on one line
+ addLineTo(p1);
+ return;
+ }
+
+ double d01 = v01.length();
+ double d21 = v21.length();
+ double angle = (piDouble - fabs(asin(cross / (d01 * d21)))) * 0.5;
+ double span = radius * tan(angle);
+ double rate = span / d01;
+ PathPoint startPoint;
+ startPoint.m_x = p1.m_x + v01.m_x * rate;
+ startPoint.m_y = p1.m_y + v01.m_y * rate;
+
+ addLineTo(startPoint);
+
+ PathPoint endPoint;
+ rate = span / d21;
+ endPoint.m_x = p1.m_x + v21.m_x * rate;
+ endPoint.m_y = p1.m_y + v21.m_y * rate;
+
+ PathPoint midPoint;
+ midPoint.m_x = (startPoint.m_x + endPoint.m_x) * 0.5;
+ midPoint.m_y = (startPoint.m_y + endPoint.m_y) * 0.5;
+
+ PathVector vm1 = midPoint - p1;
+ double dm1 = vm1.length();
+ double d = _hypot(radius, span);
+
+ PathPoint centerPoint;
+ rate = d / dm1;
+ centerPoint.m_x = p1.m_x + vm1.m_x * rate;
+ centerPoint.m_y = p1.m_y + vm1.m_y * rate;
+
+ PlatformPathElement::ArcTo data = {
+ endPoint,
+ centerPoint,
+ { radius, radius },
+ cross < 0
+ };
+ PlatformPathElement pe(data);
+ append(pe);
+}
+
+void PlatformPath::closeSubpath()
+{
+ PlatformPathElement pe;
+ append(pe);
+}
+
+// add a circular arc centred at p with radius r from start angle sar (radians) to end angle ear
+void PlatformPath::addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise)
+{
+ float startX, startY, endX, endY;
+
+ normalizeAngle(sar);
+ normalizeAngle(ear);
+
+ getEllipsePointByAngle(sar, a, b, startX, startY);
+ getEllipsePointByAngle(ear, a, b, endX, endY);
+
+ transformArcPoint(startX, startY, p);
+ transformArcPoint(endX, endY, p);
+
+ FloatPoint start(startX, startY);
+ moveTo(start);
+
+ PlatformPathElement::ArcTo data = { { endX, endY }, { p.x(), p.y() }, { a, b }, !anticlockwise };
+ PlatformPathElement pe(data);
+ append(pe);
+}
+
+
+void PlatformPath::addRect(const FloatRect& r)
+{
+ moveTo(r.location());
+
+ float right = r.right() - 1;
+ float bottom = r.bottom() - 1;
+ addLineTo(FloatPoint(right, r.y()));
+ addLineTo(FloatPoint(right, bottom));
+ addLineTo(FloatPoint(r.x(), bottom));
+ addLineTo(r.location());
+}
+
+void PlatformPath::addEllipse(const FloatRect& r)
+{
+ FloatSize radius(r.width() * 0.5, r.height() * 0.5);
+ addEllipse(r.location() + radius, radius.width(), radius.height(), 0, 0, true);
+}
+
+void PlatformPath::apply(void* info, PathApplierFunction function) const
+{
+ PathElement pelement;
+ FloatPoint points[3];
+ pelement.points = points;
+
+ for (PlatformPathElements::const_iterator it(m_elements.begin()); it != m_elements.end(); ++it) {
+ pelement.type = it->type();
+ int n = it->numPoints();
+ for (int i = 0; i < n; ++i)
+ points[i] = it->pointAt(i);
+ function(info, &pelement);
+ }
+}
+
+} // namespace Webcore
diff --git a/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.h b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.h
new file mode 100644
index 0000000..4c86fc3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PlatformPathWinCE_h
+#define PlatformPathWinCE_h
+
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "Path.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class GraphicsContext;
+
+ struct PathPoint {
+ float m_x;
+ float m_y;
+ const float& x() const { return m_x; }
+ const float& y() const { return m_y; }
+ void set(float x, float y)
+ {
+ m_x = x;
+ m_y = y;
+ };
+ operator FloatPoint() const { return FloatPoint(m_x, m_y); }
+ void move(const FloatSize& offset)
+ {
+ m_x += offset.width();
+ m_y += offset.height();
+ }
+ PathPoint& operator=(const FloatPoint& p)
+ {
+ m_x = p.x();
+ m_y = p.y();
+ return *this;
+ }
+ void clear() { m_x = m_y = 0; }
+ };
+
+ struct PathPolygon: public Vector<PathPoint> {
+ void move(const FloatSize& offset);
+ void transform(const AffineTransform& t);
+ bool contains(const FloatPoint& point) const;
+ };
+
+ class PlatformPathElement {
+ public:
+ enum PlaformPathElementType {
+ PathMoveTo,
+ PathLineTo,
+ PathArcTo,
+ PathQuadCurveTo,
+ PathBezierCurveTo,
+ PathCloseSubpath,
+ };
+
+ struct MoveTo {
+ PathPoint m_end;
+ };
+
+ struct LineTo {
+ PathPoint m_end;
+ };
+
+ struct ArcTo {
+ PathPoint m_end;
+ PathPoint m_center;
+ PathPoint m_radius;
+ bool m_clockwise;
+ };
+
+ struct QuadCurveTo {
+ PathPoint m_point0;
+ PathPoint m_point1;
+ };
+
+ struct BezierCurveTo {
+ PathPoint m_point0;
+ PathPoint m_point1;
+ PathPoint m_point2;
+ };
+
+ PlatformPathElement(): m_type(PathCloseSubpath) { m_data.m_points[0].set(0, 0); }
+ PlatformPathElement(const MoveTo& data): m_type(PathMoveTo) { m_data.m_moveToData = data; }
+ PlatformPathElement(const LineTo& data): m_type(PathLineTo) { m_data.m_lineToData = data; }
+ PlatformPathElement(const ArcTo& data): m_type(PathArcTo) { m_data.m_arcToData = data; }
+ PlatformPathElement(const QuadCurveTo& data): m_type(PathQuadCurveTo) { m_data.m_quadCurveToData = data; }
+ PlatformPathElement(const BezierCurveTo& data): m_type(PathBezierCurveTo) { m_data.m_bezierCurveToData = data; }
+
+ const MoveTo& moveTo() const { return m_data.m_moveToData; }
+ const LineTo& lineTo() const { return m_data.m_lineToData; }
+ const ArcTo& arcTo() const { return m_data.m_arcToData; }
+ const QuadCurveTo& quadCurveTo() const { return m_data.m_quadCurveToData; }
+ const BezierCurveTo& bezierCurveTo() const { return m_data.m_bezierCurveToData; }
+ const PathPoint& lastPoint() const
+ {
+ int n = numPoints();
+ return n > 1 ? m_data.m_points[n - 1] : m_data.m_points[0];
+ }
+ const PathPoint& pointAt(int index) const { return m_data.m_points[index]; }
+ int numPoints() const;
+ int numControlPoints() const;
+ void move(const FloatSize& offset);
+ void transform(const AffineTransform& t);
+ PathElementType type() const;
+ PlaformPathElementType platformType() const { return m_type; }
+ void inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const;
+
+ private:
+ PlaformPathElementType m_type;
+ union {
+ MoveTo m_moveToData;
+ LineTo m_lineToData;
+ ArcTo m_arcToData;
+ QuadCurveTo m_quadCurveToData;
+ BezierCurveTo m_bezierCurveToData;
+ PathPoint m_points[4];
+ } m_data;
+ };
+
+ typedef Vector<PlatformPathElement> PlatformPathElements;
+
+ class PlatformPath {
+ public:
+ PlatformPath();
+ const PlatformPathElements& elements() const { return m_elements; }
+ void append(const PlatformPathElement& e);
+ void append(const PlatformPath& p);
+ void clear();
+ bool isEmpty() const { return m_elements.isEmpty(); }
+
+ void strokePath(HDC, const AffineTransform* tr) const;
+ void fillPath(HDC, const AffineTransform* tr) const;
+ FloatPoint lastPoint() const { return m_elements.isEmpty() ? FloatPoint(0, 0) : m_elements.last().lastPoint(); }
+
+ const FloatRect& boundingRect() const { return m_boundingRect; }
+ bool contains(const FloatPoint& point, WindRule rule) const;
+ void translate(const FloatSize& size);
+ void transform(const AffineTransform& t);
+
+ void moveTo(const FloatPoint&);
+ void addLineTo(const FloatPoint&);
+ void addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point);
+ void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint&);
+ void addArcTo(const FloatPoint&, const FloatPoint&, float radius);
+ void closeSubpath();
+ void addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise);
+ void addRect(const FloatRect& r);
+ void addEllipse(const FloatRect& r);
+ void apply(void* info, PathApplierFunction function) const;
+
+ private:
+ void ensureSubpath();
+ void addToSubpath(const PlatformPathElement& e);
+
+ PlatformPathElements m_elements;
+ FloatRect m_boundingRect;
+ Vector<PathPolygon> m_subpaths;
+ PathPoint m_currentPoint;
+ bool m_penLifted;
+ };
+
+}
+
+#endif // PlatformPathWinCE_h
diff --git a/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp b/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp
new file mode 100644
index 0000000..05d1535
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "SharedBitmap.h"
+
+#include "GDIExtras.h"
+#include "GraphicsContext.h"
+#include "GraphicsTypes.h"
+#include "TransformationMatrix.h"
+#include "WinCEGraphicsExtras.h"
+#include <wtf/HashSet.h>
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/PassOwnArrayPtr.h>
+#include <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+namespace WebCore {
+
+#ifndef NDEBUG
+static WTF::RefCountedLeakCounter sharedBitmapLeakCounter("SharedBitmap");
+#endif
+
+
+PassRefPtr<SharedBitmap> SharedBitmap::create(const IntSize& size, BitmapInfo::BitCount bitCount, bool initPixels)
+{
+ RefPtr<SharedBitmap> resultantBitmap = adoptRef(new SharedBitmap(size, bitCount, initPixels));
+ if (resultantBitmap && !resultantBitmap->bytes())
+ return 0;
+ return resultantBitmap.release();
+}
+
+PassRefPtr<SharedBitmap> SharedBitmap::create(const Vector<unsigned>& data, const IntSize& size, bool hasAlpha)
+{
+ RefPtr<SharedBitmap> result = create(size, BitmapInfo::BitCount32, false);
+ if (!result)
+ return 0;
+ memcpy(result->bytes(), data.data(), data.size() * sizeof(unsigned));
+ result->setHasAlpha(hasAlpha);
+ return result.release();
+}
+
+SharedBitmap::SharedBitmap(const IntSize& size, BitmapInfo::BitCount bitCount, bool initPixels)
+ : m_bmpInfo(BitmapInfo::createBottomUp(size, bitCount))
+ , m_locked(false)
+ , m_usesTransparentColor(false)
+ , m_transparentColor(RGB(0, 0, 0))
+ , m_pixels(0)
+ , m_hasAlpha(false)
+ , m_validHeight(abs(size.height()))
+ , m_hbitmap(0)
+{
+#ifndef NDEBUG
+ sharedBitmapLeakCounter.increment();
+#endif
+
+ unsigned bufferSize = m_bmpInfo.numPixels();
+ if (bitCount == BitmapInfo::BitCount16)
+ bufferSize /= 2;
+
+ m_pixelData = adoptArrayPtr(new unsigned[bufferSize]);
+ m_pixels = m_pixelData.get();
+
+ if (initPixels)
+ resetPixels();
+}
+
+SharedBitmap::~SharedBitmap()
+{
+#ifndef NDEBUG
+ sharedBitmapLeakCounter.decrement();
+#endif
+}
+
+void SharedBitmap::resetPixels(bool black)
+{
+ if (!m_pixels)
+ return;
+
+ unsigned bufferSize = m_bmpInfo.numPixels();
+ if (black) {
+ unsigned bufferSizeInBytes = bufferSize * (is16bit() ? 2 : 4);
+ memset(m_pixels, 0, bufferSizeInBytes);
+ return;
+ }
+
+ if (is16bit()) {
+ // Fill it with white color
+ wmemset(static_cast<wchar_t*>(m_pixels), 0xFFFF, bufferSize);
+ return;
+ }
+
+ // Make it white but transparent
+ unsigned* pixel = static_cast<unsigned*>(m_pixels);
+ const unsigned* bufferEnd = pixel + bufferSize;
+ while (pixel < bufferEnd)
+ *pixel++ = 0x00FFFFFF;
+}
+
+static inline unsigned short convert32To16(unsigned pixel)
+{
+ unsigned short r = static_cast<unsigned short>((pixel & 0x00F80000) >> 8);
+ unsigned short g = static_cast<unsigned short>((pixel & 0x0000FC00) >> 5);
+ unsigned short b = static_cast<unsigned short>((pixel & 0x000000F8) >> 3);
+ return r | g | b;
+}
+
+bool SharedBitmap::to16bit()
+{
+ if (m_locked)
+ return false;
+ if (is16bit())
+ return true;
+
+ BitmapInfo newBmpInfo = BitmapInfo::create(m_bmpInfo.size(), BitmapInfo::BitCount16);
+
+ int width = newBmpInfo.width();
+ int paddedWidth = newBmpInfo.paddedWidth();
+ int bufferSize = paddedWidth * newBmpInfo.height();
+ OwnArrayPtr<unsigned> newPixelData(new unsigned[bufferSize / 2]);
+ void* newPixels = newPixelData.get();
+
+ if (!newPixels)
+ return false;
+
+ unsigned short* p16 = static_cast<unsigned short*>(newPixels);
+ const unsigned* p32 = static_cast<const unsigned*>(m_pixels);
+
+ bool skips = paddedWidth != width;
+
+ const unsigned short* p16end = p16 + bufferSize;
+ while (p16 < p16end) {
+ for (unsigned short* p16lineEnd = p16 + width; p16 < p16lineEnd; )
+ *p16++ = convert32To16(*p32++);
+
+ if (skips)
+ *p16++ = 0;
+ }
+
+ if (m_hbitmap)
+ m_hbitmap = nullptr;
+ else
+ m_pixelData = newPixelData.release();
+
+ m_pixels = newPixels;
+ m_bmpInfo = newBmpInfo;
+
+ setHasAlpha(false);
+ return true;
+}
+
+bool SharedBitmap::freeMemory()
+{
+ if (m_locked)
+ return false;
+
+ if (m_hbitmap) {
+ m_hbitmap = nullptr;
+ m_pixels = 0;
+ return true;
+ }
+
+ if (m_pixels) {
+ m_pixelData = nullptr;
+ m_pixels = 0;
+ return true;
+ }
+
+ return false;
+}
+
+PassOwnPtr<HBITMAP> SharedBitmap::createHandle(void** pixels, BitmapInfo* bmpInfo, int height, bool use16bit) const
+{
+ if (!m_pixels)
+ return 0;
+
+ if (height == -1)
+ height = this->height();
+ *bmpInfo = BitmapInfo::createBottomUp(IntSize(width(), height), (use16bit || is16bit()) ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32);
+
+ OwnPtr<HBITMAP> hbmp = adoptPtr(CreateDIBSection(0, bmpInfo, DIB_RGB_COLORS, pixels, 0, 0));
+
+ if (!hbmp)
+ return 0;
+
+ OwnPtr<HDC> bmpDC = adoptPtr(CreateCompatibleDC(0));
+ HGDIOBJ hOldBmp = SelectObject(bmpDC.get(), hbmp.get());
+
+ StretchDIBits(bmpDC.get(), 0, 0, width(), height, 0, 0, width(), height, m_pixels, &m_bmpInfo, DIB_RGB_COLORS, SRCCOPY);
+
+ SelectObject(bmpDC.get(), hOldBmp);
+
+ return hbmp.release();
+}
+
+bool SharedBitmap::ensureHandle()
+{
+ if (m_hbitmap)
+ return true;
+
+ if (!m_pixels)
+ return false;
+
+ if (m_locked)
+ return false;
+
+ BitmapInfo bmpInfo;
+ void* pixels;
+ m_hbitmap = createHandle(&pixels, &bmpInfo, -1, !hasAlpha());
+
+ if (!m_hbitmap)
+ return false;
+
+ m_pixelData = nullptr;
+ m_pixels = pixels;
+ m_bmpInfo = bmpInfo;
+
+ return true;
+}
+
+void SharedBitmap::draw(GraphicsContext* ctxt, const IntRect& dstRect, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ if (!m_pixels)
+ return;
+ ctxt->drawBitmap(this, dstRect, srcRect, styleColorSpace, compositeOp);
+}
+
+void SharedBitmap::draw(HDC hdc, const IntRect& dstRect, const IntRect& srcRect, CompositeOperator compositeOp)
+{
+ if (!m_pixels)
+ return;
+
+ if (dstRect.isEmpty() || srcRect.isEmpty())
+ return;
+
+ HBITMAP hbitmap = 0;
+ OwnPtr<HBITMAP> hTempBitmap;
+ bool usingHandle = compositeOp == CompositeSourceOver && (hasAlpha() && hasAlphaBlendSupport() || usesTransparentColor());
+
+ if (usingHandle) {
+ if (ensureHandle())
+ hbitmap = m_hbitmap.get();
+ else {
+ void* pixels;
+ BitmapInfo bmpInfo;
+ hTempBitmap = createHandle(&pixels, &bmpInfo, -1, usesTransparentColor());
+ hbitmap = hTempBitmap.get();
+ }
+ }
+ if (!hbitmap) {
+ // FIXME: handle other composite operation types?
+ DWORD rop = compositeOp == CompositeCopy ? SRCCOPY
+ : compositeOp == CompositeXOR ? PATINVERT
+ : compositeOp == CompositeClear ? WHITENESS
+ : SRCCOPY;
+
+ StretchDIBits(hdc, dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(),
+ srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), m_pixels, &m_bmpInfo, DIB_RGB_COLORS, rop);
+ return;
+ }
+
+ OwnPtr<HDC> hmemdc = adoptPtr(CreateCompatibleDC(hdc));
+ HGDIOBJ hOldBmp = SelectObject(hmemdc.get(), hbitmap);
+
+ if (!usesTransparentColor() && hasAlphaBlendSupport()) {
+ static const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ bool success = alphaBlendIfSupported(hdc, dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(), hmemdc.get(),
+ srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), blend);
+ ASSERT_UNUSED(success, success);
+ } else {
+ TransparentBlt(hdc, dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(), hmemdc.get(),
+ srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), transparentColor());
+ }
+
+ SelectObject(hmemdc.get(), hOldBmp);
+}
+
+PassOwnPtr<HBITMAP> SharedBitmap::clipBitmap(const IntRect& rect, bool useAlpha, BitmapInfo& bmpInfo, void*& pixels)
+{
+ if (!bytes())
+ return 0;
+
+ int oldWidth = width();
+ int oldHeight = height();
+ int copyWidth = std::min<int>(rect.width(), oldWidth - rect.x());
+ int copyHeight = std::min<int>(rect.height(), oldHeight - rect.y());
+ if (!copyWidth || !copyHeight)
+ return 0;
+
+ bmpInfo = BitmapInfo::createBottomUp(IntSize(copyWidth, copyHeight), (useAlpha && is32bit()) ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16);
+ OwnPtr<HBITMAP> newBmp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0));
+
+ if (!newBmp)
+ return 0;
+
+ OwnPtr<HDC> dcNew = adoptPtr(CreateCompatibleDC(0));
+ HGDIOBJ tmpNew = SelectObject(dcNew.get(), newBmp.get());
+
+ StretchDIBits(dcNew.get(), 0, 0, copyWidth, copyHeight, rect.x(), rect.y(), copyWidth, copyHeight,
+ bytes(), &bitmapInfo(), DIB_RGB_COLORS, SRCCOPY);
+
+ SelectObject(dcNew.get(), tmpNew);
+ return newBmp.release();
+}
+
+PassRefPtr<SharedBitmap> SharedBitmap::clipBitmap(const IntRect& rect, bool useAlpha)
+{
+ int oldWidth = width();
+ int oldHeight = height();
+ int copyWidth = std::min<int>(rect.width(), oldWidth - rect.x());
+ int copyHeight = std::min<int>(rect.height(), oldHeight - rect.y());
+ if (!copyWidth || !copyHeight)
+ return 0;
+
+ RefPtr<SharedBitmap> newBmp = create(IntSize(copyWidth, copyHeight), useAlpha && is32bit() ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16, false);
+
+ if (!newBmp || !newBmp->bytes())
+ return 0;
+
+ DCHolder dcNew(newBmp.get());
+
+ StretchDIBits(dcNew.get(), 0, 0, copyWidth, copyHeight, rect.x(), rect.y(), copyWidth, copyHeight,
+ bytes(), &bitmapInfo(), DIB_RGB_COLORS, SRCCOPY);
+
+ return newBmp;
+}
+
+static void drawPatternSimple(HDC hdc, const RECT& destRect, HBITMAP hbmp, const POINT& phase)
+{
+ OwnPtr<HBRUSH> hBrush = adoptPtr(CreatePatternBrush(hbmp));
+ if (!hBrush)
+ return;
+
+ POINT oldOrg;
+ SetBrushOrgEx(hdc, destRect.left - phase.x, destRect.top - phase.y, &oldOrg);
+ FillRect(hdc, &destRect, hBrush.get());
+ SetBrushOrgEx(hdc, oldOrg.x, oldOrg.y, 0);
+}
+
+static void drawPatternSimple(HDC hdc, const RECT& destRect, const SharedBitmap* bmp, const SIZE& bmpSize, const POINT& phase)
+{
+ int dstY = destRect.top;
+ for (int sourceY = phase.y; dstY < destRect.bottom; ) {
+ int sourceH = std::min<int>(bmpSize.cy - sourceY, destRect.bottom - dstY);
+ int dstX = destRect.left;
+ for (int sourceX = phase.x; dstX < destRect.right; ) {
+ int sourceW = std::min<int>(bmpSize.cx - sourceX, destRect.right - dstX);
+
+ StretchDIBits(hdc, dstX, dstY, sourceW, sourceH, sourceX, sourceY, sourceW, sourceH,
+ bmp->bytes(), &bmp->bitmapInfo(), DIB_RGB_COLORS, SRCCOPY);
+
+ dstX += sourceW;
+ sourceX = 0;
+ }
+
+ dstY += sourceH;
+ sourceY = 0;
+ }
+}
+
+static LONG normalizePhase(LONG phase, int limit)
+{
+ if (!phase || limit < 2)
+ return 0;
+
+ if (limit == 2)
+ return phase & 1;
+
+ if (phase < 0) {
+ phase = -phase;
+ if (phase > limit)
+ phase = static_cast<LONG>(static_cast<unsigned>(phase) % static_cast<unsigned>(limit));
+ if (phase)
+ phase = limit - phase;
+ return phase;
+ }
+
+ if (phase < limit)
+ return phase;
+
+ return static_cast<LONG>(static_cast<unsigned>(phase) % static_cast<unsigned>(limit));
+}
+
+void SharedBitmap::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize)
+{
+ if (!m_pixels)
+ return;
+ ctxt->drawBitmapPattern(this, tileRectIn, patternTransform, phase, styleColorSpace, op, destRect, origSourceSize);
+}
+
+void SharedBitmap::drawPattern(HDC hdc, const AffineTransform& transform, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize)
+{
+ if (!m_pixels)
+ return;
+
+ if (tileRectIn.width() <= 0 || tileRectIn.height() <= 0)
+ return;
+
+ bool useAlpha = op == CompositeSourceOver && hasAlpha() && is32bit();
+
+ int bmpWidth = width();
+ int bmpHeight = height();
+
+ FloatRect tileRect(tileRectIn);
+ if (bmpWidth != origSourceSize.width()) {
+ double rate = static_cast<double>(bmpWidth) / origSourceSize.width();
+ double temp = tileRect.width() * rate;
+ tileRect.setX(tileRect.x() * rate);
+ tileRect.setWidth(temp);
+ temp = tileRect.height() * rate;
+ tileRect.setY(tileRect.y() * rate);
+ tileRect.setHeight(temp);
+ }
+
+ OwnPtr<HBITMAP> clippedBmp;
+
+ if (tileRect.x() || tileRect.y() || tileRect.width() != bmpWidth || tileRect.height() != bmpHeight) {
+ BitmapInfo patternBmpInfo;
+ void* patternPixels;
+ clippedBmp = clipBitmap(IntRect(tileRect), useAlpha, patternBmpInfo, patternPixels);
+ if (!clippedBmp)
+ return;
+
+ bmpWidth = tileRect.width();
+ bmpHeight = tileRect.height();
+ }
+
+ AffineTransform tf = transform;
+ tf *= patternTransform;
+
+ FloatRect trRect = tf.mapRect(destRect);
+
+ RECT clipBox;
+ int clipType = GetClipBox(hdc, &clipBox);
+ if (clipType == SIMPLEREGION)
+ trRect.intersect(FloatRect(clipBox.left, clipBox.top, clipBox.right - clipBox.left, clipBox.bottom - clipBox.top));
+ else if (clipType == COMPLEXREGION) {
+ OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
+ if (GetClipRgn(hdc, clipRgn.get()) > 0) {
+ DWORD regionDataSize = GetRegionData(clipRgn.get(), sizeof(RGNDATA), 0);
+ if (regionDataSize) {
+ Vector<RGNDATA> regionData(regionDataSize);
+ GetRegionData(clipRgn.get(), regionDataSize, regionData.data());
+ RECT* rect = reinterpret_cast<RECT*>(regionData[0].Buffer);
+ for (DWORD i = 0; i < regionData[0].rdh.nCount; ++i, ++rect)
+ trRect.intersect(FloatRect(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top));
+ }
+ }
+ }
+
+ if (trRect.width() <= 0 || trRect.height() <= 0)
+ return;
+
+ trRect.inflate(1);
+ IntRect visibleDstRect = enclosingIntRect(tf.inverse().mapRect(trRect));
+ visibleDstRect.intersect(IntRect(destRect));
+
+ if (visibleDstRect.width() <= 0 || visibleDstRect.height() <= 0)
+ return;
+
+ trRect = tf.mapRect(visibleDstRect);
+ RECT dstRectWin = {
+ stableRound(trRect.x()),
+ stableRound(trRect.y()),
+ stableRound(trRect.right()),
+ stableRound(trRect.bottom()),
+ };
+ if (dstRectWin.right <= dstRectWin.left || dstRectWin.bottom <= dstRectWin.top)
+ return;
+
+ SIZE bmpSize = { bmpWidth, bmpHeight };
+
+ // Relative to destination, in bitmap pixels
+ POINT phaseWin = { stableRound(visibleDstRect.x() - phase.x()), stableRound(visibleDstRect.y() - phase.y()) };
+ phaseWin.x = normalizePhase(phaseWin.x, bmpSize.cx);
+ phaseWin.y = normalizePhase(phaseWin.y, bmpSize.cy);
+
+ RECT srcRectWin = {
+ 0,
+ 0,
+ stableRound(visibleDstRect.right()) - stableRound(visibleDstRect.x()),
+ stableRound(visibleDstRect.bottom()) - stableRound(visibleDstRect.y())
+ };
+ if (srcRectWin.right <= 0 || srcRectWin.bottom <= 0)
+ return;
+
+ BitmapInfo bmpInfo = BitmapInfo::createBottomUp(IntSize(srcRectWin.right, srcRectWin.bottom), useAlpha ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16);
+ void* pixels;
+ OwnPtr<HBITMAP> hbmpTemp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0));
+
+ if (!hbmpTemp)
+ return;
+
+ OwnPtr<HDC> hmemdc = adoptPtr(CreateCompatibleDC(hdc));
+ HGDIOBJ oldBmp = SelectObject(hmemdc.get(), hbmpTemp.get());
+ if (clippedBmp)
+ drawPatternSimple(hmemdc.get(), srcRectWin, clippedBmp.get(), phaseWin);
+ else if ((op != CompositeSourceOver || canUseDIBits()) && srcRectWin.right <= bmpSize.cx * 2 && srcRectWin.bottom <= bmpSize.cy * 2)
+ drawPatternSimple(hmemdc.get(), srcRectWin, this, bmpSize, phaseWin);
+ else if (ensureHandle())
+ drawPatternSimple(hmemdc.get(), srcRectWin, getHandle(), phaseWin);
+ else {
+ void* pixels;
+ BitmapInfo bmpInfo;
+ OwnPtr<HBITMAP> hbmp = createHandle(&pixels, &bmpInfo, -1, false);
+ if (hbmp)
+ drawPatternSimple(hmemdc.get(), srcRectWin, hbmp.get(), phaseWin);
+ else {
+ SelectObject(hmemdc.get(), oldBmp);
+ return;
+ }
+ }
+
+ if (useAlpha && hasAlphaBlendSupport()) {
+ static const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ bool success = alphaBlendIfSupported(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left, dstRectWin.bottom - dstRectWin.top,
+ hmemdc.get(), 0, 0, srcRectWin.right, srcRectWin.bottom, blend);
+ ASSERT_UNUSED(success, success);
+ } else if (useAlpha && !hasAlphaBlendSupport() || op == CompositeSourceOver && usesTransparentColor()) {
+ TransparentBlt(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left,
+ dstRectWin.bottom - dstRectWin.top, hmemdc.get(), 0, 0, srcRectWin.right, srcRectWin.bottom, transparentColor());
+ } else {
+ DWORD bmpOp = op == CompositeCopy ? SRCCOPY
+ : op == CompositeSourceOver ? SRCCOPY
+ : op == CompositeXOR ? PATINVERT
+ : op == CompositeClear ? WHITENESS
+ : SRCCOPY; // FIXEME: other types?
+
+ StretchDIBits(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left,
+ dstRectWin.bottom - dstRectWin.top, 0, 0, srcRectWin.right, srcRectWin.bottom,
+ pixels, &bmpInfo, DIB_RGB_COLORS, bmpOp);
+ }
+ SelectObject(hmemdc.get(), oldBmp);
+}
+
+SharedBitmap::DCProvider* SharedBitmap::s_dcProvider = new SharedBitmap::DCProvider;
+
+HDC SharedBitmap::DCProvider::getDC(SharedBitmap* bmp, unsigned* key)
+{
+ if (!bmp || !bmp->ensureHandle())
+ return 0;
+
+ HDC hdc = CreateCompatibleDC(0);
+ if (!hdc)
+ return 0;
+
+ *key = reinterpret_cast<unsigned>(SelectObject(hdc, bmp->getHandle()));
+ RECT rect = { 0, 0, bmp->width(), bmp->height() };
+ OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgnIndirect(&rect));
+ SelectClipRgn(hdc, clipRgn.get());
+
+ return hdc;
+}
+
+void SharedBitmap::DCProvider::releaseDC(SharedBitmap*, HDC hdc, unsigned key1)
+{
+ if (!hdc)
+ return;
+
+ SelectObject(hdc, reinterpret_cast<HGDIOBJ>(key1));
+ DeleteDC(hdc);
+}
+
+void SharedBitmap::clearPixels(const IntRect& rect)
+{
+ if (!m_pixels)
+ return;
+
+ IntRect bmpRect(0, 0, width(), height());
+ bmpRect.intersect(rect);
+ if (is16bit()) {
+ unsigned w = m_bmpInfo.paddedWidth();
+ unsigned short* dst = static_cast<unsigned short*>(m_pixels);
+ dst += bmpRect.y() * w + bmpRect.x();
+ int wordsToSet = bmpRect.width();
+ const unsigned short* dstEnd = dst + bmpRect.height() * w;
+ while (dst < dstEnd) {
+ wmemset(reinterpret_cast<wchar_t*>(dst), 0, wordsToSet);
+ dst += w;
+ }
+ return;
+ }
+
+ unsigned w = width();
+ unsigned* dst = static_cast<unsigned*>(m_pixels);
+ dst += bmpRect.y() * w + bmpRect.x();
+ int wordsToSet = bmpRect.width() * 2;
+ const unsigned* dstEnd = dst + bmpRect.height() * w;
+ while (dst < dstEnd) {
+ wmemset(reinterpret_cast<wchar_t*>(dst), 0, wordsToSet);
+ dst += w;
+ }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/SharedBitmap.h b/Source/WebCore/platform/graphics/wince/SharedBitmap.h
new file mode 100644
index 0000000..82f5d54
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/SharedBitmap.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SharedBitmap_h
+#define SharedBitmap_h
+
+#include "AffineTransform.h"
+#include "BitmapInfo.h"
+#include "ColorSpace.h"
+#include "GraphicsTypes.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wingdi.h>
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatRect;
+class GraphicsContext;
+class IntRect;
+class IntSize;
+class TransformationMatrix;
+
+class SharedBitmap: public RefCounted<SharedBitmap> {
+public:
+ ~SharedBitmap();
+ static PassRefPtr<SharedBitmap> create(const IntSize&, BitmapInfo::BitCount = BitmapInfo::BitCount32, bool initPixels = true);
+ static PassRefPtr<SharedBitmap> create(const Vector<unsigned>&, const IntSize&, bool hasAlpha = true);
+
+ const BitmapInfo& bitmapInfo() const { return m_bmpInfo; }
+ void* bytes() { return m_pixels; }
+ const void* bytes() const { return m_pixels; }
+ unsigned width() const { return m_bmpInfo.width(); }
+ unsigned height() const { return m_bmpInfo.height(); }
+ unsigned validHeight() const { return m_validHeight; }
+ void setValidHeight(unsigned validHeight) { m_validHeight = validHeight; }
+ void resetPixels(bool black = false);
+ void clearPixels(const IntRect& r);
+ bool locked() const { return m_locked; }
+ void lock() { m_locked = true; }
+ void unlock() { m_locked = false; }
+ bool freeMemory();
+ bool is16bit() const { return m_bmpInfo.is16bit(); }
+ bool is32bit() const { return m_bmpInfo.is32bit(); }
+ bool to16bit();
+ bool hasAlpha() const { return m_hasAlpha; }
+ void setHasAlpha(bool alpha) { m_hasAlpha = alpha; }
+ bool ensureHandle();
+ HBITMAP getHandle() { return m_hbitmap.get(); }
+ PassOwnPtr<HBITMAP> createHandle(void** pixels, BitmapInfo* bmpInfo, int h = -1, bool use16bit = true) const;
+ bool usesTransparentColor() const { return m_usesTransparentColor; }
+ COLORREF transparentColor() const { return m_transparentColor; }
+ void setTransparentColor(COLORREF c)
+ {
+ m_usesTransparentColor = true;
+ m_transparentColor = c;
+ }
+ bool canUseDIBits() const { return !hasAlpha() && !usesTransparentColor(); }
+
+ PassOwnPtr<HBITMAP> clipBitmap(const IntRect& rect, bool useAlpha, BitmapInfo& bmpInfo, void*& pixels);
+
+ PassRefPtr<SharedBitmap> clipBitmap(const IntRect& rect, bool useAlpha);
+
+ void draw(GraphicsContext* ctxt, const IntRect& dstRect, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp);
+ void drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize);
+ void draw(HDC, const IntRect& dstRect, const IntRect& srcRect, CompositeOperator compositeOp);
+ void drawPattern(HDC, const AffineTransform&, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize);
+
+ class DCProvider {
+ public:
+ virtual HDC getDC(SharedBitmap*, unsigned*);
+ virtual void releaseDC(SharedBitmap*, HDC, unsigned);
+ };
+
+ static DCProvider* s_dcProvider;
+
+ HDC getDC(unsigned* key1) { return s_dcProvider->getDC(this, key1); }
+ void releaseDC(HDC hdc, unsigned key1) { s_dcProvider->releaseDC(this, hdc, key1); }
+
+ class DCHolder {
+ public:
+ DCHolder(SharedBitmap* bmp = 0) { setInternal(bmp); }
+ ~DCHolder() { clearInternal(); }
+ void set(SharedBitmap* bmp = 0)
+ {
+ clearInternal();
+ setInternal(bmp);
+ }
+ HDC get() const { return m_hdc; }
+ private:
+ DCHolder& operator=(const DCHolder&);
+ DCHolder(const DCHolder&);
+ void clearInternal()
+ {
+ if (m_hdc)
+ m_bitmap->releaseDC(m_hdc, m_key);
+ }
+ void setInternal(SharedBitmap* bmp)
+ {
+ m_bitmap = bmp;
+ m_hdc = bmp ? bmp->getDC(&m_key) : 0;
+ }
+ SharedBitmap* m_bitmap;
+ HDC m_hdc;
+ unsigned m_key;
+ };
+
+private:
+ SharedBitmap(const IntSize&, BitmapInfo::BitCount, bool initPixels);
+ BitmapInfo m_bmpInfo;
+ OwnPtr<HBITMAP> m_hbitmap;
+ void* m_pixels;
+ OwnArrayPtr<unsigned> m_pixelData;
+ COLORREF m_transparentColor;
+ int m_validHeight;
+ bool m_locked;
+ bool m_usesTransparentColor;
+ bool m_hasAlpha;
+};
+
+} // namespace WebCore
+
+#endif // SharedBitmap_h
diff --git a/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp b/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp
new file mode 100644
index 0000000..27a021e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "FloatRect.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "FontDescription.h"
+#include <wtf/MathExtras.h>
+#include <mlang.h>
+#include <tchar.h>
+
+namespace WebCore {
+
+extern HDC g_screenDC;
+
+void SimpleFontData::platformInit()
+{
+ if (!m_platformData.isValid())
+ return;
+
+ const TEXTMETRIC& tm = m_platformData.metrics();
+ m_isSystemFont = m_platformData.isSystemFont();
+
+ m_ascent = (tm.tmAscent * m_platformData.size() + 36) / 72;
+ m_descent = (tm.tmDescent * m_platformData.size() + 36) / 72;
+ m_lineGap = (tm.tmExternalLeading * m_platformData.size() + 36) / 72;
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+ m_xHeight = m_ascent * 0.56f;
+}
+
+void SimpleFontData::platformDestroy()
+{
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ FontDescription fontDesc(fontDescription);
+ fontDesc.setComputedSize(lroundf(scaleFactor * fontDesc.computedSize()));
+ fontDesc.setSpecifiedSize(lroundf(scaleFactor * fontDesc.specifiedSize()));
+ fontDesc.setKeywordSize(lroundf(scaleFactor * fontDesc.keywordSize()));
+ FontPlatformData* result = fontCache()->getCachedFontPlatformData(fontDesc, m_platformData.family());
+ return result ? new SimpleFontData(*result) : 0;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+DWORD getKnownFontCodePages(const wchar_t* family);
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ if (m_platformData.isDisabled())
+ return true;
+
+ // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC
+ // merely by testing code page intersection. This seems suspect though. Can't a font only partially
+ // cover a given code page?
+
+ // FIXME: in the case that we failed to get the interface, still use the font.
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
+#else
+ IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface();
+#endif
+ if (!langFontLink)
+ return true;
+
+ DWORD fontCodePages = m_platformData.codePages();
+ if (!fontCodePages)
+ return false;
+
+ DWORD acpCodePages = 0;
+ langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
+
+ DWORD actualCodePages;
+ long numCharactersProcessed;
+ while (length) {
+ langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed);
+ if (actualCodePages && !(actualCodePages & fontCodePages))
+ return false;
+
+ length -= numCharactersProcessed;
+ characters += numCharactersProcessed;
+ }
+
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ if (!m_platformData.isValid())
+ return;
+
+ const TEXTMETRIC& tm = m_platformData.metrics();
+
+ // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
+ // is *not* fixed pitch. Unbelievable but true.
+ m_treatAsFixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
+}
+
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const
+{
+ return FloatRect();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (m_platformData.isDisabled())
+ return 0;
+
+ HGDIOBJ hOldFont = SelectObject(g_screenDC, m_platformData.hfont());
+
+ SIZE fontSize;
+ wchar_t c = glyph;
+ GetTextExtentPoint32(g_screenDC, &c, 1, &fontSize);
+
+ SelectObject(g_screenDC, hOldFont);
+
+ return (float)fontSize.cx * (float)m_platformData.size() / 72.f;
+}
+
+
+void SimpleFontData::platformCharWidthInit()
+{
+ if (!m_platformData.isValid())
+ return;
+
+ const TEXTMETRIC& tm = m_platformData.metrics();
+ m_avgCharWidth = (tm.tmAveCharWidth * m_platformData.size() + 36) / 72;
+ m_maxCharWidth = (tm.tmMaxCharWidth * m_platformData.size() + 36) / 72;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wince/WinCEGraphicsExtras.h b/Source/WebCore/platform/graphics/wince/WinCEGraphicsExtras.h
new file mode 100644
index 0000000..4cab21c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wince/WinCEGraphicsExtras.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef WinCEGraphicsExtras_h
+#define WinCEGraphicsExtras_h
+
+// This file is used to contain small utilities used by WINCE graphics code.
+
+namespace WebCore {
+ // Always round to same direction. 0.5 is rounded to 1,
+ // and -0.5 (0.5 - 1) is rounded to 0 (1 - 1), so that it
+ // is consistent when transformation shifts.
+ static inline int stableRound(double d)
+ {
+ if (d > 0)
+ return static_cast<int>(d + 0.5);
+
+ int i = static_cast<int>(d);
+ return i - d > 0.5 ? i - 1 : i;
+ }
+}
+
+#endif WinCEGraphicsExtras_h
diff --git a/Source/WebCore/platform/graphics/wx/ColorWx.cpp b/Source/WebCore/platform/graphics/wx/ColorWx.cpp
new file mode 100644
index 0000000..0381c59
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/ColorWx.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006, 2007 Kevin Ollivier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#include <wx/defs.h>
+#include <wx/colour.h>
+
+namespace WebCore {
+
+Color::Color(const wxColour& color)
+{
+ m_color = makeRGBA((int)color.Red(), (int)color.Green(), (int)color.Blue(), (int)color.Alpha());
+}
+
+Color::operator wxColour() const
+{
+ return wxColour(red(), green(), blue(), alpha());
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/FloatRectWx.cpp b/Source/WebCore/platform/graphics/wx/FloatRectWx.cpp
new file mode 100644
index 0000000..bb460e5
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/FloatRectWx.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#include <wx/defs.h>
+#include <wx/graphics.h>
+
+namespace WebCore {
+
+#if USE(WXGC)
+FloatRect::FloatRect(const wxRect2DDouble& r)
+ : m_location(FloatPoint(r.m_x, r.m_y))
+ , m_size(FloatSize(r.m_width, r.m_height))
+{
+}
+
+FloatRect::operator wxRect2DDouble() const
+{
+ return wxRect2DDouble(x(), y(), width(), height());
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/FontCacheWx.cpp b/Source/WebCore/platform/graphics/wx/FontCacheWx.cpp
new file mode 100644
index 0000000..c594975
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/FontCacheWx.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+#include "Font.h"
+#include "FontPlatformData.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ SimpleFontData* fontData = 0;
+ fontData = getCachedFontData(font.fontDescription(), font.family().family());
+ if (!fontData->containsCharacters(characters, length))
+ fontData = getSimilarFontPlatformData(font);
+ if (!fontData->containsCharacters(characters, length))
+ fontData = getLastResortFallbackFont(font.fontDescription());
+
+ ASSERT(fontData);
+ return fontData;
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ SimpleFontData* simpleFontData = 0;
+#if OS(DARWIN)
+ // Attempt to find an appropriate font using a match based on
+ // the presence of keywords in the the requested names. For example, we'll
+ // match any name that contains "Arabic" to Geeza Pro.
+ const FontFamily* currFamily = &font.fontDescription().family();
+ while (currFamily && !simpleFontData) {
+ if (currFamily->family().length()) {
+ static String* matchWords[3] = { new String("Arabic"), new String("Pashto"), new String("Urdu") };
+ DEFINE_STATIC_LOCAL(AtomicString, geezaStr, ("Geeza Pro"));
+ for (int j = 0; j < 3 && !simpleFontData; ++j)
+ if (currFamily->family().contains(*matchWords[j], false))
+ simpleFontData = getCachedFontData(font.fontDescription(), geezaStr);
+ }
+ currFamily = currFamily->next();
+ }
+#endif
+ if (!simpleFontData)
+ simpleFontData = getCachedFontData(font.fontDescription(), font.family().family());
+
+ return simpleFontData;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick
+ // the default that the user would get without changing any prefs.
+ SimpleFontData* fallback = 0;
+#if OS(WINDOWS)
+ static AtomicString fallbackName("Arial Unicode MS");
+#else
+ static AtomicString fallbackName("Times New Roman");
+#endif
+ fallback = getCachedFontData(fontDescription, fallbackName);
+ ASSERT(fallback);
+
+ return fallback;
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ return new FontPlatformData(fontDescription,family);
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ notImplemented();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..6133372
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode)
+{
+ return FontPlatformData(size, bold, italic);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ return 0;
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& /* format */)
+{
+ return false;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.h
new file mode 100644
index 0000000..cc348e3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+ class FontPlatformData;
+ class SharedBuffer;
+
+ struct FontCustomPlatformData : Noncopyable {
+ public:
+ FontCustomPlatformData() { }
+ ~FontCustomPlatformData();
+
+ static bool supportsFormat(const String&);
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+ };
+
+ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/wx/FontPlatformData.h b/Source/WebCore/platform/graphics/wx/FontPlatformData.h
new file mode 100644
index 0000000..9ae8b54
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/FontPlatformData.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2006 Kevin Ollivier All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 FontPlatformData_h
+#define FontPlatformData_h
+
+#include "FontDescription.h"
+#include "FontOrientation.h"
+#include "StringImpl.h"
+#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/CString.h>
+
+#include <wx/defs.h>
+#include <wx/font.h>
+#include <wx/gdicmn.h>
+
+#if OS(DARWIN)
+#include <ApplicationServices/ApplicationServices.h>
+
+#if __OBJC__
+@class NSFont;
+#else
+class NSFont;
+#endif
+
+#ifndef BUILDING_ON_TIGER
+inline CTFontRef toCTFontRef(NSFont *nsFont) { return reinterpret_cast<CTFontRef>(nsFont); }
+#endif
+
+#endif
+
+namespace WebCore {
+
+class FontHolder: public WTF::RefCounted<FontHolder>
+{
+public:
+ FontHolder()
+ : m_font(0)
+ {}
+
+ FontHolder(wxFont* font)
+ : m_font(font)
+ {}
+
+ wxFont* font() { return m_font; }
+
+private:
+ wxFont* m_font;
+};
+
+class FontPlatformData {
+public:
+ enum FontState { UNINITIALIZED, DELETED, VALID };
+
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_fontState(DELETED)
+ , m_font(0)
+ , m_size(0)
+#if OS(DARWIN)
+ , m_atsuFontID(0)
+#endif
+ { }
+
+ ~FontPlatformData();
+
+ FontPlatformData(const FontDescription&, const AtomicString&);
+
+ FontPlatformData(float size, bool bold, bool italic)
+ : m_fontState(UNINITIALIZED)
+ , m_font(0)
+ , m_size(size)
+#if OS(DARWIN)
+ , m_atsuFontID(0)
+#endif
+ {
+ }
+
+ FontPlatformData()
+ : m_fontState(UNINITIALIZED)
+ , m_font(0)
+ , m_size(0)
+#if OS(DARWIN)
+ , m_atsuFontID(0)
+#endif
+ {
+ }
+
+ wxFont* font() const {
+ return m_font->font();
+ }
+
+ unsigned hash() const {
+ switch (m_fontState) {
+ case DELETED:
+ return -1;
+ case UNINITIALIZED:
+ return 0;
+ case VALID:
+ return computeHash();
+ }
+ }
+
+ unsigned computeHash() const;
+
+ float size() const { return m_size; }
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ if (m_font && m_fontState == VALID && other.m_fontState == VALID && other.m_font) {
+ wxFont* thisFont = m_font->font();
+ wxFont* otherFont = other.m_font->font();
+ return thisFont->IsOk() && otherFont->IsOk() && thisFont->IsSameAs(*otherFont);
+ }
+ else
+ return m_fontState == other.m_fontState;
+ }
+
+ bool isHashTableDeletedValue() const { return m_fontState == DELETED; }
+
+ bool roundsGlyphAdvances() const { return false; }
+
+ bool allowsLigatures() const { return false; }
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+#if OS(WINDOWS)
+ bool useGDI() const;
+ HFONT hfont() const;
+#endif
+
+#if OS(DARWIN)
+ ATSUFontID m_atsuFontID;
+ CGFontRef cgFont() const;
+ NSFont* nsFont() const { return m_nsFont; }
+ CTFontRef ctFont() const { return reinterpret_cast<CTFontRef>(m_nsFont); }
+ void cacheNSFont();
+#endif
+
+ float m_size;
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+private:
+ WTF::RefPtr<FontHolder> m_font;
+ FontState m_fontState;
+#if OS(DARWIN)
+ NSFont* m_nsFont;
+#endif
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
new file mode 100644
index 0000000..66c69ee
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "FontDescription.h"
+#include "PlatformString.h"
+#include <wx/defs.h>
+#include <wx/gdicmn.h>
+#include <wx/font.h>
+
+namespace WebCore {
+
+static wxFontFamily fontFamilyToWxFontFamily(const int family)
+{
+ switch (family) {
+ case FontDescription::StandardFamily:
+ return wxFONTFAMILY_DEFAULT;
+ case FontDescription::SerifFamily:
+ return wxFONTFAMILY_ROMAN;
+ case FontDescription::SansSerifFamily:
+ return wxFONTFAMILY_MODERN;
+ case FontDescription::MonospaceFamily:
+ return wxFONTFAMILY_TELETYPE; // TODO: Check these are equivalent
+ case FontDescription::CursiveFamily:
+ return wxFONTFAMILY_SCRIPT;
+ case FontDescription::FantasyFamily:
+ return wxFONTFAMILY_DECORATIVE;
+ default:
+ return wxFONTFAMILY_DEFAULT;
+ }
+}
+
+static wxFontWeight fontWeightToWxFontWeight(FontWeight weight)
+{
+ if (weight >= FontWeight600)
+ return wxFONTWEIGHT_BOLD;
+
+ if (weight <= FontWeight300)
+ return wxFONTWEIGHT_LIGHT;
+
+ return wxFONTWEIGHT_NORMAL;
+}
+
+static int italicToWxFontStyle(bool isItalic)
+{
+ if (isItalic)
+ return wxFONTSTYLE_ITALIC;
+
+ return wxFONTSTYLE_NORMAL;
+}
+
+FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicString& family)
+{
+// NB: The Windows wxFont constructor has two forms, one taking a wxSize (with pixels)
+// and one taking an int (points). When points are used, Windows calculates
+// a pixel size using an algorithm which causes the size to be way off. However,
+// this is a moot issue on Linux and Mac as they only accept the point argument. So,
+// we use the pixel size constructor on Windows, but we use point size on Linux and Mac.
+#if __WXMSW__
+ m_font = adoptRef(new FontHolder(new wxFont( wxSize(0, -desc.computedPixelSize()),
+ fontFamilyToWxFontFamily(desc.genericFamily()),
+ italicToWxFontStyle(desc.italic()),
+ fontWeightToWxFontWeight(desc.weight()),
+ false,
+ family.string()
+ )
+ ));
+#else
+ m_font = adoptRef(new FontHolder(new wxFont( desc.computedPixelSize(),
+ fontFamilyToWxFontFamily(desc.genericFamily()),
+ italicToWxFontStyle(desc.italic()),
+ fontWeightToWxFontWeight(desc.weight()),
+ false,
+ family.string()
+ )
+ ));
+#endif
+#if OS(DARWIN) && !defined(wxOSX_USE_CORE_TEXT)
+#if wxCHECK_VERSION(2,9,0)
+ m_atsuFontID = m_font->font()->OSXGetATSUFontID();
+#else
+ m_atsuFontID = m_font->font()->MacGetATSUFontID();
+#endif
+ m_nsFont = 0;
+ cacheNSFont();
+#endif
+ m_size = desc.computedPixelSize();
+ m_fontState = VALID;
+ m_size = desc.computedPixelSize();
+}
+
+unsigned FontPlatformData::computeHash() const
+{
+ wxFont* thisFont = m_font->font();
+ ASSERT(thisFont && thisFont->IsOk());
+
+ // make a hash that is unique for this font, but not globally unique - that is,
+ // a font whose properties are equal should generate the same hash
+ uintptr_t hashCodes[6] = {
+ thisFont->GetPointSize(),
+ thisFont->GetFamily(),
+ thisFont->GetStyle(),
+ thisFont->GetWeight(),
+ thisFont->GetUnderlined(),
+ StringImpl::computeHash(thisFont->GetFaceName().utf8_str())
+ };
+
+ return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ m_fontState = UNINITIALIZED;
+ m_font = 0;
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+#if OS(WINDOWS)
+bool FontPlatformData::useGDI() const
+{
+ return true;
+}
+
+HFONT FontPlatformData::hfont() const
+{
+ return static_cast<HFONT>(m_font->font()->GetHFONT());
+}
+#endif
+
+#if OS(DARWIN)
+CGFontRef FontPlatformData::cgFont() const
+{
+ CGFontRef cgFont = 0;
+#ifdef wxOSX_USE_CORE_TEXT && wxOSX_USE_CORE_TEXT
+ cgFont = CTFontCopyGraphicsFont((CTFontRef)m_font->font()->OSXGetCTFont(), 0);
+#else
+ ATSFontRef fontRef;
+
+ fontRef = FMGetATSFontRefFromFont(m_atsuFontID);
+
+ if (fontRef)
+ cgFont = CGFontCreateWithPlatformFont((void*)&fontRef);
+#endif
+ return cgFont;
+}
+#endif
+
+
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/FontPlatformDataWxMac.mm b/Source/WebCore/platform/graphics/wx/FontPlatformDataWxMac.mm
new file mode 100644
index 0000000..4290f04
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/FontPlatformDataWxMac.mm
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 Kevin Ollivier, Stefan Csomor All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include <wx/defs.h>
+#include <wx/font.h>
+#include <wx/fontutil.h>
+
+#if !wxCHECK_VERSION(2,9,0)
+#include <wx/mac/private.h>
+#else
+#include <wx/osx/private.h>
+#endif
+
+#if !wxCHECK_VERSION(2,9,0) || !wxOSX_USE_COCOA
+
+static inline double DegToRad(double deg)
+{
+ return (deg * M_PI) / 180.0;
+}
+
+static const NSAffineTransformStruct kSlantNSTransformStruct = { 1, 0, tan(DegToRad(11)), 1, 0, 0 };
+
+NSFont* OSXCreateNSFont(const wxNativeFontInfo* info)
+{
+ NSFont* nsFont;
+ int weight = 5;
+ NSFontTraitMask traits = 0;
+ if (info->GetWeight() == wxFONTWEIGHT_BOLD)
+ {
+ traits |= NSBoldFontMask;
+ weight = 9;
+ }
+ else if (info->GetWeight() == wxFONTWEIGHT_LIGHT)
+ weight = 3;
+
+ if (info->GetStyle() == wxFONTSTYLE_ITALIC || info->GetStyle() == wxFONTSTYLE_SLANT)
+ traits |= NSItalicFontMask;
+
+ nsFont = [[NSFontManager sharedFontManager] fontWithFamily:(NSString*)(CFStringRef)wxMacCFStringHolder(info->GetFaceName())
+ traits:traits weight:weight size:info->GetPointSize()];
+
+ if ( nsFont == nil )
+ {
+ NSFontTraitMask remainingTraits = traits;
+ nsFont = [[NSFontManager sharedFontManager] fontWithFamily:(NSString*)(CFStringRef)wxMacCFStringHolder(info->GetFaceName())
+ traits:0 weight:5 size:info->GetPointSize()];
+ if ( nsFont == nil )
+ {
+ if ( info->GetWeight() == wxFONTWEIGHT_BOLD )
+ {
+ nsFont = [NSFont boldSystemFontOfSize:info->GetPointSize()];
+ remainingTraits &= ~NSBoldFontMask;
+ }
+ else
+ nsFont = [NSFont systemFontOfSize:info->GetPointSize()];
+ }
+
+ // fallback - if in doubt, let go of the bold attribute
+ if ( nsFont && (remainingTraits & NSItalicFontMask) )
+ {
+ NSFont* nsFontWithTraits = nil;
+ if ( remainingTraits & NSBoldFontMask)
+ {
+ nsFontWithTraits = [[NSFontManager sharedFontManager] convertFont:nsFont toHaveTrait:NSBoldFontMask];
+ if ( nsFontWithTraits == nil )
+ {
+ nsFontWithTraits = [[NSFontManager sharedFontManager] convertFont:nsFont toHaveTrait:NSItalicFontMask];
+ if ( nsFontWithTraits != nil )
+ remainingTraits &= ~NSItalicFontMask;
+ }
+ else
+ {
+ remainingTraits &= ~NSBoldFontMask;
+ }
+ }
+ if ( remainingTraits & NSItalicFontMask)
+ {
+ if ( nsFontWithTraits == nil )
+ nsFontWithTraits = nsFont;
+
+ NSAffineTransform* transform = [NSAffineTransform transform];
+ [transform setTransformStruct:kSlantNSTransformStruct];
+ [transform scaleBy:info->GetPointSize()];
+ NSFontDescriptor* italicDesc = [[nsFontWithTraits fontDescriptor] fontDescriptorWithMatrix:transform];
+ if ( italicDesc != nil )
+ {
+ NSFont* f = [NSFont fontWithDescriptor:italicDesc size:(CGFloat)(info->GetPointSize())];
+ if ( f != nil )
+ nsFontWithTraits = f;
+ }
+ }
+ if ( nsFontWithTraits != nil )
+ nsFont = nsFontWithTraits;
+ }
+ }
+
+ wxASSERT_MSG(nsFont != nil,wxT("Couldn't create nsFont")) ;
+ wxMacCocoaRetain(nsFont);
+ return nsFont;
+}
+
+#endif
+
+namespace WebCore {
+
+void FontPlatformData::cacheNSFont()
+{
+ if (m_nsFont)
+ return;
+
+#if wxCHECK_VERSION(2,9,1) && wxOSX_USE_COCOA
+ if (m_font && m_font->font())
+ m_nsFont = (NSFont*)m_font->font()->OSXGetNSFont();
+#else
+ m_nsFont = OSXCreateNSFont(m_font->font()->GetNativeFontInfo());
+#endif
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/FontWx.cpp b/Source/WebCore/platform/graphics/wx/FontWx.cpp
new file mode 100644
index 0000000..c01e249
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/FontWx.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+
+#if OS(WINDOWS)
+#include "UniscribeController.h"
+typedef WebCore::UniscribeController ComplexTextController;
+#endif
+
+#if OS(DARWIN)
+#include "mac/ComplexTextController.h"
+#endif
+
+#include <wx/dcclient.h>
+#include "fontprops.h"
+#include "non-kerned-drawing.h"
+
+namespace WebCore {
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+#if OS(WINDOWS) || OS(DARWIN)
+ return true;
+#else
+ return false;
+#endif
+}
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ // prepare DC
+ Color color = graphicsContext->fillColor();
+
+ // We can't use wx drawing methods on Win/Linux because they automatically kern text
+ // so we've created a function with platform dependent drawing implementations that
+ // will hopefully be folded into wx once the API has solidified.
+ // see platform/wx/wxcode/<platform> for the implementations.
+ drawTextWithSpacing(graphicsContext, font, color, glyphBuffer, from, numGlyphs, point);
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
+{
+#if OS(WINDOWS) || OS(DARWIN)
+ ComplexTextController it(this, run);
+ it.advance(from);
+ float beforeWidth = it.runWidthSoFar();
+ it.advance(to);
+ float afterWidth = it.runWidthSoFar();
+
+ // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
+ if (run.rtl()) {
+#if OS(WINDOWS)
+ it.advance(run.length());
+ float totalWidth = it.runWidthSoFar();
+ return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
+#else
+ float totalWidth = it.totalWidth();
+ return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
+#endif
+ }
+
+ return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
+#else
+ notImplemented();
+ return FloatRect();
+#endif
+}
+
+float Font::getGlyphsAndAdvancesForComplexText(const TextRun& /* run */, int /* from */, int /* to */, GlyphBuffer& /* glyphBuffer */, ForTextEmphasisOrNot /* forTextEmphasis */) const
+{
+ // FIXME: Implement this by moving most of the drawComplexText() implementation in here. Set up the
+ // ComplexTextController according to forTextEmphasis.
+ notImplemented();
+ return 0;
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+#if OS(WINDOWS) || OS(DARWIN)
+ // This glyph buffer holds our glyphs + advances + font data for each glyph.
+ GlyphBuffer glyphBuffer;
+
+ float startX = point.x();
+ ComplexTextController controller(this, run);
+ controller.advance(from);
+ float beforeWidth = controller.runWidthSoFar();
+ controller.advance(to, &glyphBuffer);
+
+ // We couldn't generate any glyphs for the run. Give up.
+ if (glyphBuffer.isEmpty())
+ return;
+
+ float afterWidth = controller.runWidthSoFar();
+
+ if (run.rtl()) {
+#if OS(WINDOWS)
+ controller.advance(run.length());
+ startX += controller.runWidthSoFar() - afterWidth;
+#else
+ startX += controller.totalWidth() + controller.finalRoundingWidth() - afterWidth;
+ for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
+ glyphBuffer.swap(i, end);
+#endif
+ } else
+ startX += beforeWidth;
+
+ // Draw the glyph buffer now at the starting point returned in startX.
+ FloatPoint startPoint(startX, point.y());
+ drawGlyphBuffer(context, glyphBuffer, startPoint);
+#else
+ notImplemented();
+#endif
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
+{
+ GlyphBuffer glyphBuffer;
+ float initialAdvance = getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer, ForTextEmphasis);
+
+ if (glyphBuffer.isEmpty())
+ return;
+
+ drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const
+{
+#if OS(WINDOWS) || OS(DARWIN)
+ ComplexTextController controller(this, run, fallbackFonts);
+#if OS(WINDOWS)
+ controller.advance(run.length());
+ return controller.runWidthSoFar();
+#else
+ return controller.totalWidth();
+#endif
+#else
+ notImplemented();
+ return 0;
+#endif
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float x, bool includePartialGlyphs) const
+{
+#if OS(WINDOWS) || OS(DARWIN)
+ ComplexTextController controller(this, run);
+ return controller.offsetForPosition(x, includePartialGlyphs);
+#else
+ notImplemented();
+ return 0;
+#endif
+}
+}
diff --git a/Source/WebCore/platform/graphics/wx/GlyphMapWx.cpp b/Source/WebCore/platform/graphics/wx/GlyphMapWx.cpp
new file mode 100644
index 0000000..ebf86e4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/GlyphMapWx.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+#include <unicode/utf16.h>
+
+namespace WebCore
+{
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ bool isUtf16 = bufferLength != length;
+
+ for (unsigned i = 0; i < length; i++) {
+ UChar32 character;
+
+ if(isUtf16) {
+ UChar lead = buffer[i * 2];
+ UChar trail = buffer[i * 2 + 1];
+ character = U16_GET_SUPPLEMENTARY(lead, trail);
+ } else {
+ character = buffer[i];
+ }
+
+ setGlyphDataForIndex(offset + i, character, fontData);
+ }
+
+ return true;
+}
+
+} \ No newline at end of file
diff --git a/Source/WebCore/platform/graphics/wx/GradientWx.cpp b/Source/WebCore/platform/graphics/wx/GradientWx.cpp
new file mode 100644
index 0000000..fc4661e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/GradientWx.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "CSSParser.h"
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ notImplemented();
+}
+
+PlatformGradient Gradient::platformGradient()
+{
+ notImplemented();
+ return 0;
+}
+
+void Gradient::fill(GraphicsContext*, const FloatRect&)
+{
+ notImplemented();
+}
+
+} //namespace
diff --git a/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
new file mode 100644
index 0000000..cee6aee
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
@@ -0,0 +1,666 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "Font.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "Pen.h"
+#include <wtf/MathExtras.h>
+
+#include <math.h>
+#include <stdio.h>
+
+#include <wx/defs.h>
+#include <wx/window.h>
+#include <wx/dcclient.h>
+#include <wx/dcgraph.h>
+#include <wx/graphics.h>
+
+#if __WXMAC__
+#include <Carbon/Carbon.h>
+#elif __WXMSW__
+#include <windows.h>
+#endif
+
+namespace WebCore {
+
+int getWxCompositingOperation(CompositeOperator op, bool hasAlpha)
+{
+ // FIXME: Add support for more operators.
+ if (op == CompositeSourceOver && !hasAlpha)
+ op = CompositeCopy;
+
+ int function;
+ switch (op) {
+ case CompositeClear:
+ function = wxCLEAR;
+ case CompositeCopy:
+ function = wxCOPY;
+ break;
+ default:
+ function = wxCOPY;
+ }
+ return function;
+}
+
+static int strokeStyleToWxPenStyle(int p)
+{
+ if (p == SolidStroke)
+ return wxSOLID;
+ if (p == DottedStroke)
+ return wxDOT;
+ if (p == DashedStroke)
+ return wxLONG_DASH;
+ if (p == NoStroke)
+ return wxTRANSPARENT;
+
+ return wxSOLID;
+}
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContextPlatformPrivate();
+ ~GraphicsContextPlatformPrivate();
+
+#if USE(WXGC)
+ wxGCDC* context;
+#else
+ wxWindowDC* context;
+#endif
+ int mswDCStateID;
+ wxRegion gtkCurrentClipRgn;
+ wxRegion gtkPaintClipRgn;
+};
+
+GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate() :
+ context(0),
+ mswDCStateID(0),
+ gtkCurrentClipRgn(wxRegion()),
+ gtkPaintClipRgn(wxRegion())
+{
+}
+
+GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
+{
+}
+
+
+void GraphicsContext::platformInit(PlatformGraphicsContext* context)
+{
+ m_data = new GraphicsContextPlatformPrivate;
+ setPaintingDisabled(!context);
+
+ if (context) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
+ setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
+ }
+#if USE(WXGC)
+ m_data->context = (wxGCDC*)context;
+#else
+ m_data->context = (wxWindowDC*)context;
+#endif
+}
+
+void GraphicsContext::platformDestroy()
+{
+ delete m_data;
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ return (PlatformGraphicsContext*)m_data->context;
+}
+
+void GraphicsContext::savePlatformState()
+{
+ if (m_data->context)
+ {
+#if USE(WXGC)
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->PushState();
+#else
+ // when everything is working with USE_WXGC, we can remove this
+ #if __WXMAC__
+ CGContextRef context;
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ if (gc)
+ context = (CGContextRef)gc->GetNativeContext();
+ if (context)
+ CGContextSaveGState(context);
+ #elif __WXMSW__
+ HDC dc = (HDC)m_data->context->GetHDC();
+ m_data->mswDCStateID = ::SaveDC(dc);
+ #elif __WXGTK__
+ m_data->gtkCurrentClipRgn = m_data->context->m_currentClippingRegion;
+ m_data->gtkPaintClipRgn = m_data->context->m_paintClippingRegion;
+ #endif
+#endif // __WXMAC__
+ }
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ if (m_data->context)
+ {
+#if USE(WXGC)
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->PopState();
+#else
+ #if __WXMAC__
+ CGContextRef context;
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ if (gc)
+ context = (CGContextRef)gc->GetNativeContext();
+ if (context)
+ CGContextRestoreGState(context);
+ #elif __WXMSW__
+ HDC dc = (HDC)m_data->context->GetHDC();
+ ::RestoreDC(dc, m_data->mswDCStateID);
+ #elif __WXGTK__
+ m_data->context->m_currentClippingRegion = m_data->gtkCurrentClipRgn;
+ m_data->context->m_paintClippingRegion = m_data->gtkPaintClipRgn;
+ #endif
+
+#endif // USE_WXGC
+ }
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawLine(point1.x(), point1.y(), point2.x(), point2.y());
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawEllipticArc(rect.x(), rect.y(), rect.width(), rect.height(), startAngle, angleSpan);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (npoints <= 1)
+ return;
+
+ wxPoint* polygon = new wxPoint[npoints];
+ for (size_t i = 0; i < npoints; i++)
+ polygon[i] = wxPoint(points[i].x(), points[i].y());
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawPolygon((int)npoints, polygon);
+ delete [] polygon;
+}
+
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ // FIXME: IMPLEMENT!!
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ savePlatformState();
+
+ m_data->context->SetPen(*wxTRANSPARENT_PEN);
+ m_data->context->SetBrush(wxBrush(color));
+ m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
+
+ restorePlatformState();
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::clip(const FloatRect& r)
+{
+ wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context);
+ wxPoint pos(0, 0);
+
+ if (windc) {
+#if !defined(__WXGTK__) || wxCHECK_VERSION(2,9,0)
+ wxWindow* window = windc->GetWindow();
+#else
+ wxWindow* window = windc->m_owner;
+#endif
+ if (window) {
+ wxWindow* parent = window->GetParent();
+ // we need to convert from WebView "global" to WebFrame "local" coords.
+ // FIXME: We only want to go to the top WebView.
+ while (parent) {
+ pos += window->GetPosition();
+ parent = parent->GetParent();
+ }
+ }
+ }
+
+ m_data->context->SetClippingRegion(r.x() - pos.x, r.y() - pos.y, r.width() + pos.x, r.height() + pos.y);
+}
+
+void GraphicsContext::clipOut(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clipOut(const IntRect&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clipPath(const Path&, WindRule)
+{
+ notImplemented();
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ IntPoint endPoint = origin + IntSize(width, 0);
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), wxSOLID));
+ m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
+}
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
+{
+ switch (style) {
+ case TextCheckingSpellingLineStyle:
+ m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
+ break;
+ case TextCheckingGrammarLineStyle:
+ m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
+ break;
+ default:
+ return;
+ }
+ m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
+}
+
+void GraphicsContext::clip(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+#if USE(WXGC)
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ if (gc) {
+ wxGraphicsMatrix matrix = gc->GetTransform();
+ double a, b, c, d, e, f;
+ matrix.Get(&a, &b, &c, &d, &e, &f);
+ return AffineTransform(a, b, c, d, e, f);
+ }
+#endif
+ return AffineTransform();
+}
+
+void GraphicsContext::translate(float tx, float ty)
+{
+#if USE(WXGC)
+ if (m_data->context) {
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->Translate(tx, ty);
+ }
+#endif
+}
+
+void GraphicsContext::rotate(float angle)
+{
+#if USE(WXGC)
+ if (m_data->context) {
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->Rotate(angle);
+ }
+#endif
+}
+
+void GraphicsContext::scale(const FloatSize& scale)
+{
+#if USE(WXGC)
+ if (m_data->context) {
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->Scale(scale.width(), scale.height());
+ }
+#endif
+}
+
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ FloatRect result;
+
+ wxCoord x = (wxCoord)frect.x();
+ wxCoord y = (wxCoord)frect.y();
+
+ x = m_data->context->LogicalToDeviceX(x);
+ y = m_data->context->LogicalToDeviceY(y);
+ result.setX((float)x);
+ result.setY((float)y);
+ x = (wxCoord)frect.width();
+ y = (wxCoord)frect.height();
+ x = m_data->context->LogicalToDeviceXRel(x);
+ y = m_data->context->LogicalToDeviceYRel(y);
+ result.setWidth((float)x);
+ result.setHeight((float)y);
+ return result;
+}
+
+void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ if (m_data->context)
+ {
+#if wxCHECK_VERSION(2,9,0)
+ m_data->context->SetLogicalFunction(static_cast<wxRasterOperationMode>(getWxCompositingOperation(op, false)));
+#else
+ m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
+#endif
+ }
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->context)
+ m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->context)
+ m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle())));
+
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->context)
+ m_data->context->SetBrush(wxBrush(color));
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+
+#if USE(WXGC)
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ if (gc)
+ gc->ConcatTransform(transform);
+#endif
+ return;
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+ notImplemented();
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ return InterpolationDefault;
+}
+
+void GraphicsContext::fillPath(const Path& path)
+{
+#if USE(WXGC)
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ if (gc)
+ gc->FillPath(path.platformPath());
+#endif
+}
+
+void GraphicsContext::strokePath(const Path& path)
+{
+#if USE(WXGC)
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ if (gc)
+ gc->StrokePath(path.platformPath());
+#endif
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+}
+
+void GraphicsContext::setPlatformShadow(FloatSize const&, float, Color const&, ColorSpace)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ notImplemented();
+}
+
+void GraphicsContext::beginTransparencyLayer(float)
+{
+ notImplemented();
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ notImplemented();
+}
+
+void GraphicsContext::clearRect(const FloatRect&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::strokeRect(const FloatRect&, float)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setLineCap(LineCap)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setLineDash(const DashArray&, float dashOffset)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setLineJoin(LineJoin)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setMiterLimit(float)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setAlpha(float)
+{
+ notImplemented();
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ notImplemented();
+}
+
+#if OS(WINDOWS)
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ if (dstRect.isEmpty())
+ return 0;
+
+ // Create a bitmap DC in which to draw.
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.bmiHeader.biWidth = dstRect.width();
+ bitmapInfo.bmiHeader.biHeight = dstRect.height();
+ bitmapInfo.bmiHeader.biPlanes = 1;
+ bitmapInfo.bmiHeader.biBitCount = 32;
+ bitmapInfo.bmiHeader.biCompression = BI_RGB;
+ bitmapInfo.bmiHeader.biSizeImage = 0;
+ bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biClrUsed = 0;
+ bitmapInfo.bmiHeader.biClrImportant = 0;
+
+ void* pixels = 0;
+ HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ if (!bitmap)
+ return 0;
+
+ HDC displayDC = ::GetDC(0);
+ HDC bitmapDC = ::CreateCompatibleDC(displayDC);
+ ::ReleaseDC(0, displayDC);
+
+ ::SelectObject(bitmapDC, bitmap);
+
+ // Fill our buffer with clear if we're going to alpha blend.
+ if (supportAlphaBlend) {
+ BITMAP bmpInfo;
+ GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 0, bufferSize);
+ }
+ return bitmapDC;
+}
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ if (hdc) {
+
+ if (!dstRect.isEmpty()) {
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ wxBitmap bmp;
+ bmp.SetHBITMAP(bitmap);
+#if !wxCHECK_VERSION(2,9,0)
+ if (supportAlphaBlend)
+ bmp.UseAlpha();
+#endif
+ m_data->context->DrawBitmap(bmp, dstRect.x(), dstRect.y(), supportAlphaBlend);
+
+ ::DeleteObject(bitmap);
+ }
+
+ ::DeleteDC(hdc);
+ }
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/IconWx.cpp b/Source/WebCore/platform/graphics/wx/IconWx.cpp
new file mode 100644
index 0000000..d3cc961
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/IconWx.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+Icon::~Icon()
+{
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ notImplemented();
+ return 0;
+}
+
+void Icon::paint(GraphicsContext* ctx, const IntRect& rect)
+{
+ notImplemented();
+}
+
+}
+
diff --git a/Source/WebCore/platform/graphics/wx/ImageBufferData.h b/Source/WebCore/platform/graphics/wx/ImageBufferData.h
new file mode 100644
index 0000000..d4a6114
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/ImageBufferData.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ImageBufferData_h
+#define ImageBufferData_h
+
+
+#include "OwnPtr.h"
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/Source/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/Source/WebCore/platform/graphics/wx/ImageBufferWx.cpp
new file mode 100644
index 0000000..ba33287
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/ImageBufferWx.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize&)
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize&, ColorSpace imageColorSpace, RenderingMode, bool& success) :
+ m_data(IntSize())
+{
+ notImplemented();
+ success = false;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ notImplemented();
+ return 0;
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ notImplemented();
+ return 0;
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ notImplemented();
+ return 0;
+}
+
+void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ notImplemented();
+}
+
+void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ notImplemented();
+}
+
+String ImageBuffer::toDataURL(const String&, const double*) const
+{
+ notImplemented();
+ return String();
+}
+
+bool ImageBuffer::drawsUsingCopy() const
+{
+ return true;
+}
+
+PassRefPtr<Image> ImageBuffer::copyImage() const
+{
+ notImplemented();
+ return 0;
+}
+
+void ImageBuffer::clip(GraphicsContext*, const FloatRect&) const
+{
+ notImplemented();
+}
+
+void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
+ CompositeOperator op, bool useLowQualityScale)
+{
+ RefPtr<Image> imageCopy = copyImage();
+ context->drawImage(imageCopy.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
+}
+
+void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ RefPtr<Image> imageCopy = copyImage();
+ imageCopy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>&)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/wx/ImageWx.cpp b/Source/WebCore/platform/graphics/wx/ImageWx.cpp
new file mode 100644
index 0000000..b51bde8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/ImageWx.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Kevin Ollivier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageObserver.h"
+#include "NotImplemented.h"
+#include "SharedBuffer.h"
+
+#include <math.h>
+#include <stdio.h>
+
+#include <wx/defs.h>
+#include <wx/bitmap.h>
+#include <wx/dc.h>
+#include <wx/dcmemory.h>
+#include <wx/dcgraph.h>
+#include <wx/graphics.h>
+#include <wx/image.h>
+#include <wx/thread.h>
+
+namespace WebCore {
+
+// this is in GraphicsContextWx.cpp
+int getWxCompositingOperation(CompositeOperator op, bool hasAlpha);
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ delete m_frame;
+ m_frame = 0;
+ return true;
+ }
+ return false;
+}
+
+// ================================================
+// Image Class
+// ================================================
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ // FIXME: We need to have some 'placeholder' graphics for things like missing
+ // plugins or broken images.
+ Vector<char> arr;
+ RefPtr<Image> img = BitmapImage::create();
+ RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size());
+ img->setData(buffer, true);
+ return img.release();
+}
+
+void BitmapImage::initPlatformData()
+{
+ // FIXME: NYI
+}
+
+// Drawing Routines
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ if (!m_source.initialized())
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+#if USE(WXGC)
+ wxGCDC* context = (wxGCDC*)ctxt->platformContext();
+ wxGraphicsContext* gc = context->GetGraphicsContext();
+ wxGraphicsBitmap* bitmap = frameAtIndex(m_currentFrame);
+#else
+ wxWindowDC* context = ctxt->platformContext();
+ wxBitmap* bitmap = frameAtIndex(m_currentFrame);
+#endif
+
+ startAnimation();
+ if (!bitmap) // If it's too early we won't have an image yet.
+ return;
+
+ // If we're drawing a sub portion of the image or scaling then create
+ // a pattern transformation on the image and draw the transformed pattern.
+ // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ // FIXME: NYI
+
+ ctxt->save();
+
+ // Set the compositing operation.
+ ctxt->setCompositeOperation(op);
+
+#if USE(WXGC)
+ float scaleX = src.width() / dst.width();
+ float scaleY = src.height() / dst.height();
+
+ FloatRect adjustedDestRect = dst;
+ FloatSize selfSize = currentFrameSize();
+
+ if (src.size() != selfSize) {
+ adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY));
+ adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY));
+ }
+
+ gc->Clip(dst.x(), dst.y(), dst.width(), dst.height());
+#if wxCHECK_VERSION(2,9,0)
+ gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height());
+#else
+ gc->DrawGraphicsBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height());
+#endif
+
+#else // USE(WXGC)
+ IntRect srcIntRect(src);
+ IntRect dstIntRect(dst);
+ bool rescaling = false;
+ if ((dstIntRect.width() != srcIntRect.width()) || (dstIntRect.height() != srcIntRect.height()))
+ {
+ rescaling = true;
+ wxImage img = bitmap->ConvertToImage();
+ img.Rescale(dstIntRect.width(), dstIntRect.height());
+ bitmap = new wxBitmap(img);
+ }
+
+ wxMemoryDC mydc;
+ ASSERT(bitmap->GetRefData());
+ mydc.SelectObject(*bitmap);
+
+ context->Blit((wxCoord)dstIntRect.x(),(wxCoord)dstIntRect.y(), (wxCoord)dstIntRect.width(), (wxCoord)dstIntRect.height(), &mydc,
+ (wxCoord)srcIntRect.x(), (wxCoord)srcIntRect.y(), wxCOPY, true);
+ mydc.SelectObject(wxNullBitmap);
+
+ // NB: delete is causing crashes during page load, but not during the deletion
+ // itself. It occurs later on when a valid bitmap created in frameAtIndex
+ // suddenly becomes invalid after returning. It's possible these errors deal
+ // with reentrancy and threding problems.
+ //delete bitmap;
+ if (rescaling)
+ {
+ delete bitmap;
+ bitmap = NULL;
+ }
+#endif
+
+ ctxt->restore();
+
+ if (ImageObserver* observer = imageObserver())
+ observer->didDraw(this);
+}
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator, const FloatRect& dstRect)
+{
+
+
+#if USE(WXGC)
+ wxGCDC* context = (wxGCDC*)ctxt->platformContext();
+ wxGraphicsBitmap* bitmap = nativeImageForCurrentFrame();
+#else
+ wxWindowDC* context = ctxt->platformContext();
+ wxBitmap* bitmap = nativeImageForCurrentFrame();
+#endif
+
+ if (!bitmap) // If it's too early we won't have an image yet.
+ return;
+
+ ctxt->save();
+ ctxt->clip(IntRect(dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height()));
+
+ float currentW = 0;
+ float currentH = 0;
+
+#if USE(WXGC)
+ wxGraphicsContext* gc = context->GetGraphicsContext();
+
+ float adjustedX = phase.x() + srcRect.x() *
+ narrowPrecisionToFloat(patternTransform.a());
+ float adjustedY = phase.y() + srcRect.y() *
+ narrowPrecisionToFloat(patternTransform.d());
+
+ gc->ConcatTransform(patternTransform);
+#else
+ wxMemoryDC mydc;
+ mydc.SelectObject(*bitmap);
+#endif
+
+ wxPoint origin(context->GetDeviceOrigin());
+ wxSize clientSize(context->GetSize());
+
+ while ( currentW < dstRect.width() && currentW < clientSize.x - origin.x ) {
+ while ( currentH < dstRect.height() && currentH < clientSize.y - origin.y) {
+#if USE(WXGC)
+#if wxCHECK_VERSION(2,9,0)
+ gc->DrawBitmap(*bitmap, adjustedX + currentW, adjustedY + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height());
+#else
+ gc->DrawGraphicsBitmap(*bitmap, adjustedX + currentW, adjustedY + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height());
+#endif
+#else
+ context->Blit((wxCoord)dstRect.x() + currentW, (wxCoord)dstRect.y() + currentH,
+ (wxCoord)srcRect.width(), (wxCoord)srcRect.height(), &mydc,
+ (wxCoord)srcRect.x(), (wxCoord)srcRect.y(), wxCOPY, true);
+#endif
+ currentH += srcRect.height();
+ }
+ currentW += srcRect.width();
+ currentH = 0;
+ }
+ ctxt->restore();
+
+#if !USE(WXGC)
+ mydc.SelectObject(wxNullBitmap);
+#endif
+
+ // NB: delete is causing crashes during page load, but not during the deletion
+ // itself. It occurs later on when a valid bitmap created in frameAtIndex
+ // suddenly becomes invalid after returning. It's possible these errors deal
+ // with reentrancy and threding problems.
+ //delete bitmap;
+
+ startAnimation();
+
+ if (ImageObserver* observer = imageObserver())
+ observer->didDraw(this);
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_checkedForSolidColor = true;
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/IntPointWx.cpp b/Source/WebCore/platform/graphics/wx/IntPointWx.cpp
new file mode 100644
index 0000000..389ac9f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/IntPointWx.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006, 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include <wx/defs.h>
+#include <wx/gdicmn.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const wxPoint& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator wxPoint() const
+{
+ return wxPoint(m_x, m_y);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/IntRectWx.cpp b/Source/WebCore/platform/graphics/wx/IntRectWx.cpp
new file mode 100644
index 0000000..10c1b55
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/IntRectWx.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006, 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include <wx/defs.h>
+#include <wx/gdicmn.h>
+
+namespace WebCore {
+
+IntRect::IntRect(const wxRect& r)
+ : m_location(IntPoint(r.x, r.y))
+ , m_size(IntSize(r.width, r.height))
+{
+}
+
+IntRect::operator wxRect() const
+{
+ return wxRect(x(), y(), width(), height());
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/IntSizeWx.cpp b/Source/WebCore/platform/graphics/wx/IntSizeWx.cpp
new file mode 100644
index 0000000..8c82854
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/IntSizeWx.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 Kevin Watters. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "IntSize.h"
+
+#include <wx/defs.h>
+#include <wx/gdicmn.h>
+
+namespace WebCore {
+
+IntSize::IntSize(const wxSize& s)
+ : m_width(s.x)
+ , m_height(s.y)
+{
+}
+
+IntSize::operator wxSize() const
+{
+ return wxSize(m_width, m_height);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/PathWx.cpp b/Source/WebCore/platform/graphics/wx/PathWx.cpp
new file mode 100644
index 0000000..f5355f2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/PathWx.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+#include "StrokeStyleApplier.h"
+
+#include <stdio.h>
+
+#include <wx/defs.h>
+#include <wx/graphics.h>
+
+namespace WebCore {
+
+int getWxWindRuleForWindRule(WindRule rule)
+{
+ if (rule == RULE_EVENODD)
+ return wxODDEVEN_RULE;
+
+ return wxWINDING_RULE;
+}
+
+Path::Path()
+{
+ m_path = 0;
+ // NB: This only supports the 'default' renderer as determined by wx on
+ // each platform. If an app uses a non-default renderer (e.g. Cairo on Win),
+ // there will be problems, but there's no way we can determine which
+ // renderer an app is using right now with wx API, so we will just handle
+ // the common case.
+#if USE(WXGC)
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ if (renderer) {
+ wxGraphicsPath path = renderer->CreatePath();
+ m_path = new wxGraphicsPath(path);
+ }
+#endif
+}
+
+Path::~Path()
+{
+ clear();
+}
+
+Path::Path(const Path& path)
+{
+ m_path = new wxGraphicsPath(*path.m_path);
+}
+
+bool Path::contains(const FloatPoint& point, const WindRule rule) const
+{
+#if USE(WXGC)
+ if (m_path) {
+#if wxCHECK_VERSION(2,9,0)
+ return m_path->Contains(point.x(), point.y(), static_cast<wxPolygonFillMode>(getWxWindRuleForWindRule(rule)));
+#else
+ return m_path->Contains(point.x(), point.y(), getWxWindRuleForWindRule(rule));
+#endif
+ }
+#endif
+ return false;
+}
+
+void Path::translate(const FloatSize&)
+{
+ notImplemented();
+}
+
+FloatRect Path::boundingRect() const
+{
+#if USE(WXGC)
+ if (m_path) {
+ return m_path->GetBox();
+ }
+#endif
+
+ return FloatRect();
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ notImplemented();
+ return FloatRect();
+}
+
+bool Path::strokeContains(StrokeStyleApplier*, const FloatPoint&) const
+{
+ notImplemented();
+ return false;
+}
+
+Path& Path::operator=(const Path& path)
+{
+ *m_path = *path.platformPath();
+ return *this;
+}
+
+void Path::clear()
+{
+ if (m_path)
+ delete m_path;
+
+#if USE(WXGC)
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ if (renderer) {
+ wxGraphicsPath path = renderer->CreatePath();
+ m_path = new wxGraphicsPath(path);
+ }
+#endif
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->MoveToPoint(point.x(), point.y());
+#endif
+}
+
+void Path::addLineTo(const FloatPoint& point)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddLineToPoint(point.x(), point.y());
+#endif
+}
+
+void Path::addQuadCurveTo(const FloatPoint& control, const FloatPoint& end)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddQuadCurveToPoint(control.x(), control.y(), end.x(), end.y());
+#endif
+}
+
+void Path::addBezierCurveTo(const FloatPoint& control1, const FloatPoint& control2, const FloatPoint& end)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddCurveToPoint(control1.x(), control1.y(), control2.x(), control2.y(), end.x(), end.y());
+#endif
+}
+
+void Path::addArcTo(const FloatPoint& point1, const FloatPoint& point2, float radius)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddArcToPoint(point1.x(), point1.y(), point2.x(), point2.y(), radius);
+#endif
+}
+
+void Path::closeSubpath()
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->CloseSubpath();
+#endif
+}
+
+void Path::addArc(const FloatPoint& point, float radius, float startAngle, float endAngle, bool clockwise)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddArc(point.x(), point.y(), radius, startAngle, endAngle, clockwise);
+#endif
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddRectangle(rect.x(), rect.y(), rect.width(), rect.height());
+#endif
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddEllipse(rect.x(), rect.y(), rect.width(), rect.height());
+#endif
+}
+
+void Path::transform(const AffineTransform& transform)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->Transform(transform);
+#endif
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ notImplemented();
+}
+
+bool Path::isEmpty() const
+{
+#if USE(WXGC)
+ if (m_path) {
+ wxDouble x, y, width, height;
+ m_path->GetBox(&x, &y, &width, &height);
+ return (width == 0 && height == 0);
+ }
+#endif
+ return true;
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
+
+FloatPoint Path::currentPoint() const
+{
+ // FIXME: return current point of subpath.
+ float quietNaN = std::numeric_limits<float>::quiet_NaN();
+ return FloatPoint(quietNaN, quietNaN);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/PenWx.cpp b/Source/WebCore/platform/graphics/wx/PenWx.cpp
new file mode 100644
index 0000000..5a131e3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/PenWx.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Pen.h"
+
+#include <wx/defs.h>
+#include <wx/pen.h>
+#include <wx/colour.h>
+
+namespace WebCore {
+
+// Pen style conversion functions
+static int penStyleToWxPenStyle(int p)
+{
+ if (p == Pen::SolidLine)
+ return wxSOLID;
+ if (p == Pen::DotLine)
+ return wxDOT;
+ if (p == Pen::DashLine)
+ return wxLONG_DASH;
+ if (p == Pen::NoPen)
+ return wxTRANSPARENT;
+
+ return wxSOLID;
+}
+
+static Pen::PenStyle wxPenStyleToPenStyle(int p)
+{
+ if (p == wxSOLID)
+ return Pen::SolidLine;
+ if (p == wxDOT)
+ return Pen::DotLine;
+ if (p == wxLONG_DASH || p == wxSHORT_DASH || p == wxDOT_DASH || p == wxUSER_DASH)
+ return Pen::DashLine;
+ if (p == wxTRANSPARENT)
+ return Pen::NoPen;
+
+ return Pen::SolidLine;
+}
+
+Pen::Pen(const wxPen& p)
+{
+ wxColour color = p.GetColour();
+ setColor(Color(color.Red(), color.Green(), color.Blue()));
+ setWidth(p.GetWidth());
+ setStyle(wxPenStyleToPenStyle(p.GetStyle()));
+}
+
+Pen::operator wxPen() const
+{
+ return wxPen(wxColour(m_color.red(), m_color.blue(), m_color.green()), width(), penStyleToWxPenStyle(style()));
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/Source/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
new file mode 100644
index 0000000..0e24bfc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include <wtf/MathExtras.h>
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+
+#if OS(DARWIN)
+#include "WebCoreSystemInterface.h"
+#endif
+
+#include <wx/defs.h>
+#include <wx/dcscreen.h>
+#include <wx/string.h>
+#include "fontprops.h"
+
+namespace WebCore
+{
+
+void SimpleFontData::platformInit()
+{
+ wxFont *font = m_platformData.font();
+ if (font && font->IsOk()) {
+ wxFontProperties props = wxFontProperties(font);
+ m_ascent = props.GetAscent();
+ m_descent = props.GetDescent();
+ m_lineSpacing = props.GetLineSpacing();
+ m_xHeight = props.GetXHeight();
+ m_unitsPerEm = 1; // FIXME!
+ m_lineGap = props.GetLineGap();
+ }
+
+ m_syntheticBoldOffset = 0.0f;
+
+#if OS(WINDOWS)
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+ m_isSystemFont = false;
+#endif
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ m_avgCharWidth = 0.f;
+ m_maxCharWidth = 0.f;
+ initCharWidths();
+}
+
+void SimpleFontData::platformDestroy()
+{
+#if OS(WINDOWS)
+ if (m_scriptFontProperties) {
+ delete m_scriptFontProperties;
+ m_scriptFontProperties = 0;
+ }
+
+ if (m_scriptCache)
+ ScriptFreeCache(&m_scriptCache);
+#endif
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ FontDescription desc = FontDescription(fontDescription);
+ desc.setSpecifiedSize(scaleFactor * fontDescription.computedSize());
+ FontPlatformData platformData(desc, desc.family().family());
+ return new SimpleFontData(platformData, isCustomFont(), false);
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ // FIXME: We will need to implement this to load non-ASCII encoding sites
+#if OS(WINDOWS)
+ return wxFontContainsCharacters(m_platformData.hfont(), characters, length);
+#elif OS(DARWIN)
+ return wxFontContainsCharacters(m_platformData.nsFont(), characters, length);
+#endif
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ if (m_platformData.font() && m_platformData.font()->Ok())
+ m_treatAsFixedPitch = m_platformData.font()->IsFixedWidth();
+ else
+ m_treatAsFixedPitch = false;
+}
+
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const
+{
+ return FloatRect();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+#if __WXMSW__
+ // under Windows / wxMSW we currently always use GDI fonts.
+ return widthForGDIGlyph(glyph);
+#elif OS(DARWIN)
+ float pointSize = m_platformData.size();
+ CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
+ CGSize advance;
+ NSFont* nsfont = (NSFont*)m_platformData.nsFont();
+ if (!wkGetGlyphTransformedAdvances(m_platformData.cgFont(), nsfont, &m, &glyph, &advance)) {
+ // LOG_ERROR("Unable to cache glyph widths for %@ %f", [nsfont displayName], pointSize);
+ advance.width = 0;
+ }
+ return advance.width + m_syntheticBoldOffset;
+#else
+ // TODO: fix this! Make GetTextExtents a method of wxFont in 2.9
+ int width = 10;
+ GetTextExtent(*m_platformData.font(), (wxChar)glyph, &width, NULL);
+ return width;
+#endif
+}
+
+#if OS(WINDOWS)
+SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const
+{
+ // AFAICT this is never called even by the Win port anymore.
+ return 0;
+}
+
+void SimpleFontData::initGDIFont()
+{
+ // unused by wx port
+}
+
+void SimpleFontData::platformCommonDestroy()
+{
+ // unused by wx port
+}
+
+float SimpleFontData::widthForGDIGlyph(Glyph glyph) const
+{
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ return width;
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp b/Source/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
new file mode 100644
index 0000000..1937986
--- /dev/null
+++ b/Source/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+#include "TransformationMatrix.h"
+
+#include "Assertions.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+
+#include <stdio.h>
+#include <wx/defs.h>
+#include <wx/graphics.h>
+
+namespace WebCore {
+
+#if USE(WXGC)
+TransformationMatrix::operator wxGraphicsMatrix() const
+{
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ ASSERT(renderer);
+
+ wxGraphicsMatrix matrix = renderer->CreateMatrix(a(), b(), c(), d(), e(), f());
+ return matrix;
+}
+
+AffineTransform::operator wxGraphicsMatrix() const
+{
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ ASSERT(renderer);
+
+ wxGraphicsMatrix matrix = renderer->CreateMatrix(a(), b(), c(), d(), e(), f());
+ return matrix;
+}
+#endif
+
+}