summaryrefslogtreecommitdiffstats
path: root/WebCore/platform
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform')
-rw-r--r--WebCore/platform/AsyncFileSystem.h10
-rw-r--r--WebCore/platform/ColorData.gperf299
-rw-r--r--WebCore/platform/CrossThreadCopier.cpp1
-rw-r--r--WebCore/platform/KURL.cpp27
-rw-r--r--WebCore/platform/KURL.h6
-rw-r--r--WebCore/platform/KURLGoogle.cpp28
-rw-r--r--WebCore/platform/Language.cpp79
-rw-r--r--WebCore/platform/Language.h34
-rw-r--r--WebCore/platform/Logging.cpp10
-rw-r--r--WebCore/platform/Logging.h1
-rw-r--r--WebCore/platform/PlatformKeyboardEvent.h2
-rw-r--r--WebCore/platform/ScrollView.cpp24
-rw-r--r--WebCore/platform/ScrollbarTheme.h2
-rw-r--r--WebCore/platform/ScrollbarThemeComposite.cpp2
-rw-r--r--WebCore/platform/Widget.h4
-rw-r--r--WebCore/platform/android/FileSystemAndroid.cpp4
-rw-r--r--WebCore/platform/audio/AudioResampler.cpp128
-rw-r--r--WebCore/platform/audio/AudioResampler.h68
-rw-r--r--WebCore/platform/audio/AudioUtilities.cpp58
-rw-r--r--WebCore/platform/audio/AudioUtilities.h45
-rw-r--r--WebCore/platform/audio/EqualPowerPanner.cpp112
-rw-r--r--WebCore/platform/audio/EqualPowerPanner.h53
-rw-r--r--WebCore/platform/audio/HRTFPanner.cpp229
-rw-r--r--WebCore/platform/audio/HRTFPanner.h68
-rw-r--r--WebCore/platform/brew/ClipboardBrew.cpp2
-rw-r--r--WebCore/platform/brew/FileSystemBrew.cpp21
-rw-r--r--WebCore/platform/brew/PlatformKeyboardEventBrew.cpp95
-rw-r--r--WebCore/platform/brew/ScreenBrew.cpp8
-rw-r--r--WebCore/platform/chromium/ChromiumBridge.h42
-rw-r--r--WebCore/platform/chromium/ChromiumDataObject.cpp215
-rw-r--r--WebCore/platform/chromium/ChromiumDataObject.h127
-rw-r--r--WebCore/platform/chromium/ChromiumDataObjectLegacy.cpp249
-rw-r--r--WebCore/platform/chromium/ChromiumDataObjectLegacy.h119
-rw-r--r--WebCore/platform/chromium/ClipboardChromium.cpp302
-rw-r--r--WebCore/platform/chromium/ClipboardChromium.h3
-rw-r--r--WebCore/platform/chromium/ClipboardChromiumWin.cpp10
-rw-r--r--WebCore/platform/chromium/ClipboardMimeTypes.cpp10
-rw-r--r--WebCore/platform/chromium/ClipboardMimeTypes.h10
-rw-r--r--WebCore/platform/chromium/DragDataChromium.cpp44
-rw-r--r--WebCore/platform/chromium/GeolocationServiceChromium.cpp4
-rw-r--r--WebCore/platform/chromium/LanguageChromium.cpp (renamed from WebCore/platform/chromium/Language.cpp)2
-rw-r--r--WebCore/platform/chromium/PasteboardChromium.cpp3
-rw-r--r--WebCore/platform/chromium/PopupMenuChromium.cpp16
-rw-r--r--WebCore/platform/chromium/ReadableDataObject.cpp67
-rw-r--r--WebCore/platform/chromium/ReadableDataObject.h22
-rw-r--r--WebCore/platform/chromium/ScrollbarThemeChromium.cpp2
-rw-r--r--WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp188
-rw-r--r--WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm6
-rw-r--r--WebCore/platform/chromium/ThemeChromiumMac.mm2
-rw-r--r--WebCore/platform/chromium/WritableDataObject.cpp82
-rw-r--r--WebCore/platform/chromium/WritableDataObject.h37
-rw-r--r--WebCore/platform/cocoa/KeyEventCocoa.mm51
-rw-r--r--WebCore/platform/efl/LanguageEfl.cpp (renamed from WebCore/platform/efl/Language.cpp)2
-rw-r--r--WebCore/platform/efl/PlatformKeyboardEventEfl.cpp12
-rw-r--r--WebCore/platform/efl/RenderThemeEfl.cpp35
-rw-r--r--WebCore/platform/efl/RenderThemeEfl.h8
-rw-r--r--WebCore/platform/efl/SharedBufferEfl.cpp2
-rw-r--r--WebCore/platform/efl/SharedTimerEfl.cpp80
-rw-r--r--WebCore/platform/efl/WidgetEfl.cpp2
-rw-r--r--WebCore/platform/graphics/ANGLEWebKitBridge.cpp2
-rw-r--r--WebCore/platform/graphics/Color.cpp6
-rw-r--r--WebCore/platform/graphics/Color.h5
-rw-r--r--WebCore/platform/graphics/ColorSpace.h6
-rw-r--r--WebCore/platform/graphics/ContextShadow.cpp21
-rw-r--r--WebCore/platform/graphics/ContextShadow.h9
-rw-r--r--WebCore/platform/graphics/FloatRect.h9
-rw-r--r--WebCore/platform/graphics/GraphicsContext.cpp16
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h11
-rw-r--r--WebCore/platform/graphics/GraphicsContext3D.cpp241
-rw-r--r--WebCore/platform/graphics/GraphicsContext3D.h43
-rw-r--r--WebCore/platform/graphics/GraphicsContextPrivate.h4
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.cpp3
-rw-r--r--WebCore/platform/graphics/ImageBuffer.cpp10
-rw-r--r--WebCore/platform/graphics/ImageBuffer.h14
-rw-r--r--WebCore/platform/graphics/IntRect.h5
-rw-r--r--WebCore/platform/graphics/Path.cpp203
-rw-r--r--WebCore/platform/graphics/Path.h11
-rw-r--r--WebCore/platform/graphics/brew/ImageBrew.cpp4
-rw-r--r--WebCore/platform/graphics/cairo/CairoUtilities.cpp101
-rw-r--r--WebCore/platform/graphics/cairo/CairoUtilities.h14
-rw-r--r--WebCore/platform/graphics/cairo/ContextShadowCairo.cpp229
-rw-r--r--WebCore/platform/graphics/cairo/FloatRectCairo.cpp45
-rw-r--r--WebCore/platform/graphics/cairo/FontCacheFreeType.cpp79
-rw-r--r--WebCore/platform/graphics/cairo/FontCairo.cpp152
-rw-r--r--WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp131
-rw-r--r--WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h5
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp480
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h5
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferCairo.cpp2
-rw-r--r--WebCore/platform/graphics/cairo/ImageCairo.cpp70
-rw-r--r--WebCore/platform/graphics/cairo/PathCairo.cpp36
-rw-r--r--WebCore/platform/graphics/cg/ColorCG.cpp93
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp112
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp93
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.h41
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h6
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferCG.cpp54
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferData.h3
-rw-r--r--WebCore/platform/graphics/cg/ImageCG.cpp17
-rw-r--r--WebCore/platform/graphics/cg/PathCG.cpp52
-rw-r--r--WebCore/platform/graphics/chromium/ContentLayerChromium.cpp129
-rw-r--r--WebCore/platform/graphics/chromium/ContentLayerChromium.h8
-rw-r--r--WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp23
-rw-r--r--WebCore/platform/graphics/chromium/FontLinux.cpp779
-rw-r--r--WebCore/platform/graphics/chromium/GLES2Canvas.cpp4
-rw-r--r--WebCore/platform/graphics/chromium/ImageLayerChromium.cpp14
-rw-r--r--WebCore/platform/graphics/chromium/LayerChromium.cpp14
-rw-r--r--WebCore/platform/graphics/chromium/LayerChromium.h7
-rw-r--r--WebCore/platform/graphics/chromium/LayerRendererChromium.cpp41
-rw-r--r--WebCore/platform/graphics/chromium/LayerRendererChromium.h16
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.cpp2
-rw-r--r--WebCore/platform/graphics/chromium/VideoFrameChromium.h6
-rw-r--r--WebCore/platform/graphics/chromium/VideoFrameProvider.h2
-rw-r--r--WebCore/platform/graphics/chromium/VideoLayerChromium.cpp56
-rw-r--r--WebCore/platform/graphics/chromium/VideoLayerChromium.h16
-rw-r--r--WebCore/platform/graphics/efl/ImageEfl.cpp3
-rw-r--r--WebCore/platform/graphics/efl/IntRectEfl.cpp (renamed from WebCore/platform/graphics/filters/ImageBufferFilter.cpp)25
-rw-r--r--WebCore/platform/graphics/filters/FEBlend.cpp6
-rw-r--r--WebCore/platform/graphics/filters/FEColorMatrix.cpp4
-rw-r--r--WebCore/platform/graphics/filters/FEComponentTransfer.cpp4
-rw-r--r--WebCore/platform/graphics/filters/FEComposite.cpp48
-rw-r--r--WebCore/platform/graphics/filters/FEComposite.h2
-rw-r--r--WebCore/platform/graphics/filters/FEConvolveMatrix.cpp4
-rw-r--r--WebCore/platform/graphics/filters/FEConvolveMatrix.h2
-rw-r--r--WebCore/platform/graphics/filters/FEDisplacementMap.cpp15
-rw-r--r--WebCore/platform/graphics/filters/FEDisplacementMap.h2
-rw-r--r--WebCore/platform/graphics/filters/FEFlood.cpp6
-rw-r--r--WebCore/platform/graphics/filters/FEFlood.h2
-rw-r--r--WebCore/platform/graphics/filters/FEGaussianBlur.cpp51
-rw-r--r--WebCore/platform/graphics/filters/FEGaussianBlur.h3
-rw-r--r--WebCore/platform/graphics/filters/FELighting.cpp9
-rw-r--r--WebCore/platform/graphics/filters/FELighting.h2
-rw-r--r--WebCore/platform/graphics/filters/FEMerge.cpp4
-rw-r--r--WebCore/platform/graphics/filters/FEMorphology.cpp22
-rw-r--r--WebCore/platform/graphics/filters/FEMorphology.h2
-rw-r--r--WebCore/platform/graphics/filters/FEOffset.cpp30
-rw-r--r--WebCore/platform/graphics/filters/FEOffset.h2
-rw-r--r--WebCore/platform/graphics/filters/FETile.cpp40
-rw-r--r--WebCore/platform/graphics/filters/FETile.h2
-rw-r--r--WebCore/platform/graphics/filters/FETurbulence.cpp8
-rw-r--r--WebCore/platform/graphics/filters/FETurbulence.h2
-rw-r--r--WebCore/platform/graphics/filters/Filter.h7
-rw-r--r--WebCore/platform/graphics/filters/FilterEffect.cpp33
-rw-r--r--WebCore/platform/graphics/filters/FilterEffect.h33
-rw-r--r--WebCore/platform/graphics/filters/ImageBufferFilter.h57
-rw-r--r--WebCore/platform/graphics/filters/SourceAlpha.cpp22
-rw-r--r--WebCore/platform/graphics/filters/SourceAlpha.h6
-rw-r--r--WebCore/platform/graphics/filters/SourceGraphic.cpp20
-rw-r--r--WebCore/platform/graphics/filters/SourceGraphic.h6
-rw-r--r--WebCore/platform/graphics/gpu/DrawingBuffer.cpp37
-rw-r--r--WebCore/platform/graphics/gpu/DrawingBuffer.h40
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp4
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp4
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp7
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp4
-rw-r--r--WebCore/platform/graphics/gpu/PODInterval.h26
-rw-r--r--WebCore/platform/graphics/gpu/PODIntervalTree.h17
-rw-r--r--WebCore/platform/graphics/gpu/PODRedBlackTree.h17
-rw-r--r--WebCore/platform/graphics/gpu/Shader.cpp5
-rw-r--r--WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp34
-rw-r--r--WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h9
-rw-r--r--WebCore/platform/graphics/gpu/SolidFillShader.cpp5
-rw-r--r--WebCore/platform/graphics/gpu/TexShader.cpp5
-rw-r--r--WebCore/platform/graphics/gpu/Texture.cpp4
-rw-r--r--WebCore/platform/graphics/gpu/Texture.h4
-rw-r--r--WebCore/platform/graphics/gpu/TilingData.cpp5
-rw-r--r--WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm84
-rw-r--r--WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp4
-rw-r--r--WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp2
-rw-r--r--WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h4
-rw-r--r--WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp4
-rw-r--r--WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp5
-rw-r--r--WebCore/platform/graphics/gtk/FontGtk.cpp50
-rw-r--r--WebCore/platform/graphics/gtk/ImageBufferGtk.cpp3
-rw-r--r--WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp4
-rw-r--r--WebCore/platform/graphics/haiku/PathHaiku.cpp6
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.mm24
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContext3DMac.mm4
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContextMac.mm24
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm12
-rw-r--r--WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp21
-rw-r--r--WebCore/platform/graphics/openvg/PathOpenVG.cpp12
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp5
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp44
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.cpp36
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.h1
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferQt.cpp14
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp86
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h12
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp37
-rw-r--r--WebCore/platform/graphics/qt/TextureMapperQt.cpp225
-rw-r--r--WebCore/platform/graphics/skia/ImageBufferSkia.cpp7
-rw-r--r--WebCore/platform/graphics/skia/ImageSkia.cpp17
-rw-r--r--WebCore/platform/graphics/skia/PathSkia.cpp56
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.cpp19
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.h9
-rw-r--r--WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp1444
-rw-r--r--WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h96
-rw-r--r--WebCore/platform/graphics/texmap/TextureMapper.h120
-rw-r--r--WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h70
-rw-r--r--WebCore/platform/graphics/transforms/AffineTransform.cpp14
-rw-r--r--WebCore/platform/graphics/transforms/AffineTransform.h5
-rw-r--r--WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h2
-rw-r--r--WebCore/platform/graphics/transforms/MatrixTransformOperation.h2
-rw-r--r--WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h2
-rw-r--r--WebCore/platform/graphics/transforms/RotateTransformOperation.h3
-rw-r--r--WebCore/platform/graphics/transforms/SkewTransformOperation.h3
-rw-r--r--WebCore/platform/graphics/transforms/TranslateTransformOperation.h4
-rw-r--r--WebCore/platform/graphics/win/FontCGWin.cpp6
-rw-r--r--WebCore/platform/graphics/win/GDIExtras.cpp43
-rw-r--r--WebCore/platform/graphics/win/GDIExtras.h65
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp12
-rw-r--r--WebCore/platform/graphics/win/GraphicsLayerCACF.cpp8
-rw-r--r--WebCore/platform/graphics/win/ImageCGWin.cpp4
-rw-r--r--WebCore/platform/graphics/win/ImageCairoWin.cpp8
-rw-r--r--[-rwxr-xr-x]WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp0
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp41
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h8
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp6
-rw-r--r--WebCore/platform/graphics/win/WKCACFContextFlusher.cpp23
-rw-r--r--WebCore/platform/graphics/win/WKCACFContextFlusher.h8
-rw-r--r--WebCore/platform/graphics/win/WKCACFLayer.cpp13
-rw-r--r--WebCore/platform/graphics/win/WKCACFLayer.h4
-rw-r--r--[-rwxr-xr-x]WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp70
-rw-r--r--[-rwxr-xr-x]WebCore/platform/graphics/win/WKCACFLayerRenderer.h10
-rw-r--r--WebCore/platform/graphics/win/WebLayer.cpp4
-rw-r--r--WebCore/platform/graphics/win/WebTiledLayer.cpp2
-rw-r--r--WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp161
-rw-r--r--WebCore/platform/graphics/wince/ImageWinCE.cpp4
-rw-r--r--WebCore/platform/graphics/wince/PathWinCE.cpp5
-rw-r--r--WebCore/platform/graphics/wince/PlatformPathWinCE.cpp37
-rw-r--r--WebCore/platform/graphics/wince/PlatformPathWinCE.h1
-rw-r--r--WebCore/platform/graphics/wx/GraphicsContextWx.cpp4
-rw-r--r--WebCore/platform/graphics/wx/PathWx.cpp6
-rw-r--r--WebCore/platform/gtk/ClipboardGtk.cpp75
-rw-r--r--WebCore/platform/gtk/CursorGtk.cpp30
-rw-r--r--WebCore/platform/gtk/DataObjectGtk.cpp88
-rw-r--r--WebCore/platform/gtk/DataObjectGtk.h22
-rw-r--r--WebCore/platform/gtk/DragDataGtk.cpp6
-rw-r--r--WebCore/platform/gtk/FileChooserGtk.cpp1
-rw-r--r--WebCore/platform/gtk/GtkVersioning.c165
-rw-r--r--WebCore/platform/gtk/GtkVersioning.h10
-rw-r--r--WebCore/platform/gtk/LanguageGtk.cpp (renamed from WebCore/platform/gtk/Language.cpp)5
-rw-r--r--WebCore/platform/gtk/PasteboardHelper.cpp44
-rw-r--r--WebCore/platform/gtk/PlatformScreenGtk.cpp5
-rw-r--r--WebCore/platform/gtk/PopupMenuGtk.cpp4
-rw-r--r--WebCore/platform/gtk/RenderThemeGtk.cpp134
-rw-r--r--WebCore/platform/gtk/ScrollbarThemeGtk.cpp9
-rw-r--r--WebCore/platform/gtk/gtk2drawing.c1895
-rw-r--r--WebCore/platform/gtk/gtk3drawing.c1416
-rw-r--r--WebCore/platform/gtk/gtkdrawing.h208
-rw-r--r--WebCore/platform/image-decoders/ImageDecoder.cpp14
-rw-r--r--WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp123
-rw-r--r--WebCore/platform/image-decoders/webp/WEBPImageDecoder.h (renamed from WebCore/platform/text/StringBuilder.h)49
-rw-r--r--WebCore/platform/mac/Language.mm106
-rw-r--r--WebCore/platform/mac/LoggingMac.mm1
-rw-r--r--WebCore/platform/mac/ScrollbarThemeMac.mm7
-rw-r--r--WebCore/platform/mac/SharedTimerMac.mm139
-rw-r--r--WebCore/platform/mac/WebCoreSystemInterface.h1
-rw-r--r--WebCore/platform/mac/WebCoreSystemInterface.mm1
-rw-r--r--WebCore/platform/network/BlobData.cpp44
-rw-r--r--WebCore/platform/network/BlobData.h70
-rw-r--r--WebCore/platform/network/BlobRegistryImpl.cpp7
-rw-r--r--WebCore/platform/network/BlobResourceHandle.cpp4
-rw-r--r--WebCore/platform/network/CredentialStorage.cpp8
-rw-r--r--WebCore/platform/network/DataURL.cpp92
-rw-r--r--WebCore/platform/network/DataURL.h37
-rw-r--r--WebCore/platform/network/HTTPHeaderMap.cpp20
-rw-r--r--WebCore/platform/network/HTTPHeaderMap.h13
-rw-r--r--WebCore/platform/network/ProxyServer.cpp75
-rw-r--r--WebCore/platform/network/ProxyServer.h79
-rw-r--r--WebCore/platform/network/ResourceHandle.h19
-rw-r--r--WebCore/platform/network/ResourceHandleInternal.h23
-rw-r--r--WebCore/platform/network/ResourceRawHeaders.h41
-rw-r--r--WebCore/platform/network/ResourceRequestBase.cpp7
-rw-r--r--WebCore/platform/network/ResourceRequestBase.h18
-rw-r--r--WebCore/platform/network/ResourceResponseBase.cpp23
-rw-r--r--WebCore/platform/network/ResourceResponseBase.h10
-rw-r--r--WebCore/platform/network/android/ResourceRequest.h6
-rw-r--r--WebCore/platform/network/android/ResourceResponse.h6
-rw-r--r--WebCore/platform/network/cf/ProxyServerCFNet.cpp98
-rw-r--r--WebCore/platform/network/cf/ResourceRequest.h8
-rw-r--r--WebCore/platform/network/cf/ResourceResponse.h6
-rw-r--r--WebCore/platform/network/cf/SocketStreamHandle.h1
-rw-r--r--WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp6
-rw-r--r--WebCore/platform/network/chromium/ResourceRequest.cpp15
-rw-r--r--WebCore/platform/network/chromium/ResourceRequest.h9
-rw-r--r--WebCore/platform/network/chromium/ResourceResponse.cpp58
-rw-r--r--WebCore/platform/network/chromium/ResourceResponse.h15
-rw-r--r--WebCore/platform/network/curl/ProxyServerCurl.cpp40
-rw-r--r--WebCore/platform/network/curl/ResourceHandleCurl.cpp15
-rw-r--r--WebCore/platform/network/curl/ResourceHandleManager.cpp75
-rw-r--r--WebCore/platform/network/curl/ResourceRequest.h6
-rw-r--r--WebCore/platform/network/curl/ResourceResponse.h10
-rw-r--r--WebCore/platform/network/mac/FormDataStreamMac.mm2
-rw-r--r--WebCore/platform/network/mac/ResourceRequest.h8
-rw-r--r--WebCore/platform/network/mac/ResourceResponse.h7
-rw-r--r--WebCore/platform/network/qt/ProxyServerQt.cpp73
-rw-r--r--WebCore/platform/network/qt/QNetworkReplyHandler.cpp66
-rw-r--r--WebCore/platform/network/qt/QNetworkReplyHandler.h5
-rw-r--r--WebCore/platform/network/qt/ResourceRequest.h6
-rw-r--r--WebCore/platform/network/qt/ResourceResponse.h9
-rw-r--r--WebCore/platform/network/qt/SocketStreamHandle.h4
-rw-r--r--WebCore/platform/network/qt/SocketStreamHandlePrivate.h2
-rw-r--r--WebCore/platform/network/qt/SocketStreamHandleQt.cpp2
-rw-r--r--WebCore/platform/network/soup/ProxyServerSoup.cpp39
-rw-r--r--WebCore/platform/network/soup/ResourceHandleSoup.cpp572
-rw-r--r--WebCore/platform/network/soup/ResourceRequest.h9
-rw-r--r--WebCore/platform/network/soup/ResourceRequestSoup.cpp23
-rw-r--r--WebCore/platform/network/soup/ResourceResponse.h10
-rw-r--r--WebCore/platform/network/soup/cache/soup-directory-input-stream.c200
-rw-r--r--WebCore/platform/network/soup/cache/soup-directory-input-stream.h62
-rw-r--r--WebCore/platform/network/soup/cache/soup-http-input-stream.c921
-rw-r--r--WebCore/platform/network/soup/cache/soup-http-input-stream.h77
-rw-r--r--WebCore/platform/network/soup/cache/soup-request-data.c170
-rw-r--r--WebCore/platform/network/soup/cache/soup-request-data.h52
-rw-r--r--WebCore/platform/network/soup/cache/soup-request-file.c331
-rw-r--r--WebCore/platform/network/soup/cache/soup-request-file.h54
-rw-r--r--WebCore/platform/network/soup/cache/soup-request-http.c340
-rw-r--r--WebCore/platform/network/soup/cache/soup-request-http.h54
-rw-r--r--WebCore/platform/network/soup/cache/soup-request.c312
-rw-r--r--WebCore/platform/network/soup/cache/soup-request.h100
-rw-r--r--WebCore/platform/network/soup/cache/soup-requester.c188
-rw-r--r--WebCore/platform/network/soup/cache/soup-requester.h81
-rw-r--r--WebCore/platform/network/soup/cache/webkit/soup-cache-private.h42
-rw-r--r--WebCore/platform/network/soup/cache/webkit/soup-cache.c1653
-rw-r--r--WebCore/platform/network/soup/cache/webkit/soup-cache.h102
-rw-r--r--WebCore/platform/network/win/CookieJarWin.cpp10
-rw-r--r--WebCore/platform/network/win/ResourceHandleWin.cpp8
-rw-r--r--WebCore/platform/qt/ClipboardQt.cpp4
-rw-r--r--WebCore/platform/qt/CursorQt.cpp6
-rw-r--r--WebCore/platform/qt/LanguageQt.cpp (renamed from WebCore/platform/qt/Language.cpp)2
-rw-r--r--WebCore/platform/qt/PlatformBridge.h5
-rw-r--r--WebCore/platform/qt/PlatformKeyboardEventQt.cpp87
-rw-r--r--WebCore/platform/qt/QWebPageClient.h1
-rw-r--r--WebCore/platform/qt/QtMobileWebStyle.cpp (renamed from WebCore/platform/qt/Maemo5Webstyle.cpp)75
-rw-r--r--WebCore/platform/qt/QtMobileWebStyle.h (renamed from WebCore/platform/qt/Maemo5Webstyle.h)10
-rw-r--r--WebCore/platform/qt/RenderThemeQt.cpp5
-rw-r--r--WebCore/platform/sql/SQLiteDatabase.cpp8
-rw-r--r--WebCore/platform/sql/SQLiteDatabase.h1
-rw-r--r--WebCore/platform/text/Base64.cpp77
-rw-r--r--WebCore/platform/text/Base64.h12
-rw-r--r--WebCore/platform/text/LineEnding.cpp135
-rw-r--r--WebCore/platform/text/LineEnding.h19
-rw-r--r--WebCore/platform/text/StringBuffer.h35
-rw-r--r--WebCore/platform/text/StringBuilder.cpp132
-rw-r--r--WebCore/platform/text/TextEncoding.cpp4
-rw-r--r--WebCore/platform/text/TextEncodingRegistry.cpp9
-rw-r--r--WebCore/platform/text/brew/TextBoundariesBrew.cpp74
-rw-r--r--WebCore/platform/text/brew/TextBreakIteratorBrew.cpp312
-rw-r--r--WebCore/platform/text/brew/TextCodecBrew.cpp214
-rw-r--r--WebCore/platform/text/brew/TextCodecBrew.h61
-rw-r--r--WebCore/platform/text/qt/TextBreakIteratorQt.cpp7
-rw-r--r--WebCore/platform/text/wince/TextCodecWinCE.cpp3
-rw-r--r--WebCore/platform/win/ClipboardUtilitiesWin.cpp8
-rw-r--r--WebCore/platform/win/ClipboardWin.cpp4
-rw-r--r--WebCore/platform/win/LanguageWin.cpp (renamed from WebCore/platform/win/Language.cpp)8
-rw-r--r--WebCore/platform/win/PlatformScreenWin.cpp8
-rw-r--r--WebCore/platform/win/PopupMenuWin.cpp6
-rw-r--r--WebCore/platform/win/WebCoreTextRenderer.cpp4
-rw-r--r--WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp2
362 files changed, 16586 insertions, 6464 deletions
diff --git a/WebCore/platform/AsyncFileSystem.h b/WebCore/platform/AsyncFileSystem.h
index 1bf7580..3104ebc 100644
--- a/WebCore/platform/AsyncFileSystem.h
+++ b/WebCore/platform/AsyncFileSystem.h
@@ -59,6 +59,10 @@ public:
static bool isAvailable();
+ // Subclass must implement this if it supports synchronous operations.
+ // This should return false if there are no pending operations.
+ virtual bool waitForOperationToComplete() { return false; }
+
// Creates and returns a new platform-specific AsyncFileSystem instance if the platform has its own implementation.
static PassOwnPtr<AsyncFileSystem> create(const String& rootPath);
@@ -76,10 +80,16 @@ public:
virtual void copy(const String& srcPath, const String& destPath, PassOwnPtr<AsyncFileSystemCallbacks>) = 0;
// Deletes a file or directory at a given path.
+ // It is an error to try to remove a directory that is not empty.
// AsyncFileSystemCallbacks::didSucceed() is called when the operation is completed successfully.
// AsyncFileSystemCallbacks::didFail() is called otherwise.
virtual void remove(const String& path, PassOwnPtr<AsyncFileSystemCallbacks>) = 0;
+ // Recursively deletes a directory at a given path.
+ // AsyncFileSystemCallbacks::didSucceed() is called when the operation is completed successfully.
+ // AsyncFileSystemCallbacks::didFail() is called otherwise.
+ virtual void removeRecursively(const String& path, PassOwnPtr<AsyncFileSystemCallbacks>) = 0;
+
// Retrieves the metadata information of the file or directory at a given path.
// AsyncFileSystemCallbacks::didReadMetadata() is called when the operation is completed successfully.
// AsyncFileSystemCallbacks::didFail() is called otherwise.
diff --git a/WebCore/platform/ColorData.gperf b/WebCore/platform/ColorData.gperf
index dd726cc..f83e793 100644
--- a/WebCore/platform/ColorData.gperf
+++ b/WebCore/platform/ColorData.gperf
@@ -10,152 +10,153 @@ struct NamedColor;
%define hash-function-name colordata_hash_function
%enum
%%
-aliceblue, 0xf0f8ff
-antiquewhite, 0xfaebd7
-aqua, 0x00ffff
-aquamarine, 0x7fffd4
-azure, 0xf0ffff
-beige, 0xf5f5dc
-bisque, 0xffe4c4
-black, 0x000000
-blanchedalmond, 0xffebcd
-blue, 0x0000ff
-blueviolet, 0x8a2be2
-brown, 0xa52a2a
-burlywood, 0xdeb887
-cadetblue, 0x5f9ea0
-chartreuse, 0x7fff00
-chocolate, 0xd2691e
-coral, 0xff7f50
-cornflowerblue, 0x6495ed
-cornsilk, 0xfff8dc
-crimson, 0xdc143c
-cyan, 0x00ffff
-darkblue, 0x00008b
-darkcyan, 0x008b8b
-darkgoldenrod, 0xb8860b
-darkgray, 0xa9a9a9
-darkgrey, 0xa9a9a9
-darkgreen, 0x006400
-darkkhaki, 0xbdb76b
-darkmagenta, 0x8b008b
-darkolivegreen, 0x556b2f
-darkorange, 0xff8c00
-darkorchid, 0x9932cc
-darkred, 0x8b0000
-darksalmon, 0xe9967a
-darkseagreen, 0x8fbc8f
-darkslateblue, 0x483d8b
-darkslategray, 0x2f4f4f
-darkslategrey, 0x2f4f4f
-darkturquoise, 0x00ced1
-darkviolet, 0x9400d3
-deeppink, 0xff1493
-deepskyblue, 0x00bfff
-dimgray, 0x696969
-dimgrey, 0x696969
-dodgerblue, 0x1e90ff
-firebrick, 0xb22222
-floralwhite, 0xfffaf0
-forestgreen, 0x228b22
-fuchsia, 0xff00ff
-gainsboro, 0xdcdcdc
-ghostwhite, 0xf8f8ff
-gold, 0xffd700
-goldenrod, 0xdaa520
-gray, 0x808080
-grey, 0x808080
-green, 0x008000
-greenyellow, 0xadff2f
-honeydew, 0xf0fff0
-hotpink, 0xff69b4
-indianred, 0xcd5c5c
-indigo, 0x4b0082
-ivory, 0xfffff0
-khaki, 0xf0e68c
-lavender, 0xe6e6fa
-lavenderblush, 0xfff0f5
-lawngreen, 0x7cfc00
-lemonchiffon, 0xfffacd
-lightblue, 0xadd8e6
-lightcoral, 0xf08080
-lightcyan, 0xe0ffff
-lightgoldenrodyellow, 0xfafad2
-lightgray, 0xd3d3d3
-lightgrey, 0xd3d3d3
-lightgreen, 0x90ee90
-lightpink, 0xffb6c1
-lightsalmon, 0xffa07a
-lightseagreen, 0x20b2aa
-lightskyblue, 0x87cefa
-lightslateblue, 0x8470ff
-lightslategray, 0x778899
-lightslategrey, 0x778899
-lightsteelblue, 0xb0c4de
-lightyellow, 0xffffe0
-lime, 0x00ff00
-limegreen, 0x32cd32
-linen, 0xfaf0e6
-magenta, 0xff00ff
-maroon, 0x800000
-mediumaquamarine, 0x66cdaa
-mediumblue, 0x0000cd
-mediumorchid, 0xba55d3
-mediumpurple, 0x9370d8
-mediumseagreen, 0x3cb371
-mediumslateblue, 0x7b68ee
-mediumspringgreen, 0x00fa9a
-mediumturquoise, 0x48d1cc
-mediumvioletred, 0xc71585
-midnightblue, 0x191970
-mintcream, 0xf5fffa
-mistyrose, 0xffe4e1
-moccasin, 0xffe4b5
-navajowhite, 0xffdead
-navy, 0x000080
-oldlace, 0xfdf5e6
-olive, 0x808000
-olivedrab, 0x6b8e23
-orange, 0xffa500
-orangered, 0xff4500
-orchid, 0xda70d6
-palegoldenrod, 0xeee8aa
-palegreen, 0x98fb98
-paleturquoise, 0xafeeee
-palevioletred, 0xd87093
-papayawhip, 0xffefd5
-peachpuff, 0xffdab9
-peru, 0xcd853f
-pink, 0xffc0cb
-plum, 0xdda0dd
-powderblue, 0xb0e0e6
-purple, 0x800080
-red, 0xff0000
-rosybrown, 0xbc8f8f
-royalblue, 0x4169e1
-saddlebrown, 0x8b4513
-salmon, 0xfa8072
-sandybrown, 0xf4a460
-seagreen, 0x2e8b57
-seashell, 0xfff5ee
-sienna, 0xa0522d
-silver, 0xc0c0c0
-skyblue, 0x87ceeb
-slateblue, 0x6a5acd
-slategray, 0x708090
-slategrey, 0x708090
-snow, 0xfffafa
-springgreen, 0x00ff7f
-steelblue, 0x4682b4
-tan, 0xd2b48c
-teal, 0x008080
-thistle, 0xd8bfd8
-tomato, 0xff6347
-turquoise, 0x40e0d0
-violet, 0xee82ee
-violetred, 0xd02090
-wheat, 0xf5deb3
-white, 0xffffff
-whitesmoke, 0xf5f5f5
-yellow, 0xffff00
-yellowgreen, 0x9acd32
+aliceblue, 0xfff0f8ff
+antiquewhite, 0xfffaebd7
+aqua, 0xff00ffff
+aquamarine, 0xff7fffd4
+azure, 0xfff0ffff
+beige, 0xfff5f5dc
+bisque, 0xffffe4c4
+black, 0xff000000
+blanchedalmond, 0xffffebcd
+blue, 0xff0000ff
+blueviolet, 0xff8a2be2
+brown, 0xffa52a2a
+burlywood, 0xffdeb887
+cadetblue, 0xff5f9ea0
+chartreuse, 0xff7fff00
+chocolate, 0xffd2691e
+coral, 0xffff7f50
+cornflowerblue, 0xff6495ed
+cornsilk, 0xfffff8dc
+crimson, 0xffdc143c
+cyan, 0xff00ffff
+darkblue, 0xff00008b
+darkcyan, 0xff008b8b
+darkgoldenrod, 0xffb8860b
+darkgray, 0xffa9a9a9
+darkgrey, 0xffa9a9a9
+darkgreen, 0xff006400
+darkkhaki, 0xffbdb76b
+darkmagenta, 0xff8b008b
+darkolivegreen, 0xff556b2f
+darkorange, 0xffff8c00
+darkorchid, 0xff9932cc
+darkred, 0xff8b0000
+darksalmon, 0xffe9967a
+darkseagreen, 0xff8fbc8f
+darkslateblue, 0xff483d8b
+darkslategray, 0xff2f4f4f
+darkslategrey, 0xff2f4f4f
+darkturquoise, 0xff00ced1
+darkviolet, 0xff9400d3
+deeppink, 0xffff1493
+deepskyblue, 0xff00bfff
+dimgray, 0xff696969
+dimgrey, 0xff696969
+dodgerblue, 0xff1e90ff
+firebrick, 0xffb22222
+floralwhite, 0xfffffaf0
+forestgreen, 0xff228b22
+fuchsia, 0xffff00ff
+gainsboro, 0xffdcdcdc
+ghostwhite, 0xfff8f8ff
+gold, 0xffffd700
+goldenrod, 0xffdaa520
+gray, 0xff808080
+grey, 0xff808080
+green, 0xff008000
+greenyellow, 0xffadff2f
+honeydew, 0xfff0fff0
+hotpink, 0xffff69b4
+indianred, 0xffcd5c5c
+indigo, 0xff4b0082
+ivory, 0xfffffff0
+khaki, 0xfff0e68c
+lavender, 0xffe6e6fa
+lavenderblush, 0xfffff0f5
+lawngreen, 0xff7cfc00
+lemonchiffon, 0xfffffacd
+lightblue, 0xffadd8e6
+lightcoral, 0xfff08080
+lightcyan, 0xffe0ffff
+lightgoldenrodyellow, 0xfffafad2
+lightgray, 0xffd3d3d3
+lightgrey, 0xffd3d3d3
+lightgreen, 0xff90ee90
+lightpink, 0xffffb6c1
+lightsalmon, 0xffffa07a
+lightseagreen, 0xff20b2aa
+lightskyblue, 0xff87cefa
+lightslateblue, 0xff8470ff
+lightslategray, 0xff778899
+lightslategrey, 0xff778899
+lightsteelblue, 0xffb0c4de
+lightyellow, 0xffffffe0
+lime, 0xff00ff00
+limegreen, 0xff32cd32
+linen, 0xfffaf0e6
+magenta, 0xffff00ff
+maroon, 0xff800000
+mediumaquamarine, 0xff66cdaa
+mediumblue, 0xff0000cd
+mediumorchid, 0xffba55d3
+mediumpurple, 0xff9370d8
+mediumseagreen, 0xff3cb371
+mediumslateblue, 0xff7b68ee
+mediumspringgreen, 0xff00fa9a
+mediumturquoise, 0xff48d1cc
+mediumvioletred, 0xffc71585
+midnightblue, 0xff191970
+mintcream, 0xfff5fffa
+mistyrose, 0xffffe4e1
+moccasin, 0xffffe4b5
+navajowhite, 0xffffdead
+navy, 0xff000080
+oldlace, 0xfffdf5e6
+olive, 0xff808000
+olivedrab, 0xff6b8e23
+orange, 0xffffa500
+orangered, 0xffff4500
+orchid, 0xffda70d6
+palegoldenrod, 0xffeee8aa
+palegreen, 0xff98fb98
+paleturquoise, 0xffafeeee
+palevioletred, 0xffd87093
+papayawhip, 0xffffefd5
+peachpuff, 0xffffdab9
+peru, 0xffcd853f
+pink, 0xffffc0cb
+plum, 0xffdda0dd
+powderblue, 0xffb0e0e6
+purple, 0xff800080
+red, 0xffff0000
+rosybrown, 0xffbc8f8f
+royalblue, 0xff4169e1
+saddlebrown, 0xff8b4513
+salmon, 0xfffa8072
+sandybrown, 0xfff4a460
+seagreen, 0xff2e8b57
+seashell, 0xfffff5ee
+sienna, 0xffa0522d
+silver, 0xffc0c0c0
+skyblue, 0xff87ceeb
+slateblue, 0xff6a5acd
+slategray, 0xff708090
+slategrey, 0xff708090
+snow, 0xfffffafa
+springgreen, 0xff00ff7f
+steelblue, 0xff4682b4
+tan, 0xffd2b48c
+teal, 0xff008080
+thistle, 0xffd8bfd8
+tomato, 0xffff6347
+transparent, 0x00000000
+turquoise, 0xff40e0d0
+violet, 0xffee82ee
+violetred, 0xffd02090
+wheat, 0xfff5deb3
+white, 0xffffffff
+whitesmoke, 0xfff5f5f5
+yellow, 0xffffff00
+yellowgreen, 0xff9acd32
diff --git a/WebCore/platform/CrossThreadCopier.cpp b/WebCore/platform/CrossThreadCopier.cpp
index 683ba54..4280486 100644
--- a/WebCore/platform/CrossThreadCopier.cpp
+++ b/WebCore/platform/CrossThreadCopier.cpp
@@ -37,6 +37,7 @@
#include "ResourceError.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
+#include "SerializedScriptValue.h"
namespace WebCore {
diff --git a/WebCore/platform/KURL.cpp b/WebCore/platform/KURL.cpp
index 16b84b5..3ac5d86 100644
--- a/WebCore/platform/KURL.cpp
+++ b/WebCore/platform/KURL.cpp
@@ -616,6 +616,33 @@ bool KURL::hasFragmentIdentifier() const
return m_fragmentEnd != m_queryEnd;
}
+void KURL::copyParsedQueryTo(ParsedURLParameters& parameters) const
+{
+ const UChar* pos = m_string.characters() + m_pathEnd + 1;
+ const UChar* end = m_string.characters() + m_queryEnd;
+ while (pos < end) {
+ const UChar* parameterStart = pos;
+ while (pos < end && *pos != '&')
+ ++pos;
+ const UChar* parameterEnd = pos;
+ if (pos < end) {
+ ASSERT(*pos == '&');
+ ++pos;
+ }
+ if (parameterStart == parameterEnd)
+ continue;
+ const UChar* nameStart = parameterStart;
+ const UChar* equalSign = parameterStart;
+ while (equalSign < parameterEnd && *equalSign != '=')
+ ++equalSign;
+ if (equalSign == nameStart)
+ continue;
+ String name(nameStart, equalSign - nameStart);
+ String value = equalSign == parameterEnd ? String() : String(equalSign + 1, parameterEnd - equalSign - 1);
+ parameters.set(name, value);
+ }
+}
+
String KURL::baseAsString() const
{
return m_string.left(m_pathAfterLastSlash);
diff --git a/WebCore/platform/KURL.h b/WebCore/platform/KURL.h
index e5e8ec4..cbf0d8b 100644
--- a/WebCore/platform/KURL.h
+++ b/WebCore/platform/KURL.h
@@ -27,6 +27,7 @@
#define KURL_h
#include "PlatformString.h"
+#include <wtf/HashMap.h>
#if PLATFORM(CF)
typedef const struct __CFURL* CFURLRef;
@@ -59,6 +60,8 @@ namespace WebCore {
class TextEncoding;
struct KURLHash;
+typedef HashMap<String, String> ParsedURLParameters;
+
enum ParsedURLStringTag { ParsedURLString };
class KURL {
@@ -133,6 +136,8 @@ public:
String fragmentIdentifier() const;
bool hasFragmentIdentifier() const;
+ void copyParsedQueryTo(ParsedURLParameters&) const;
+
String baseAsString() const;
String prettyURL() const;
@@ -141,6 +146,7 @@ public:
// Returns true if the current URL's protocol is the same as the null-
// terminated ASCII argument. The argument must be lower-case.
bool protocolIs(const char*) const;
+ bool protocolIsData() const { return protocolIs("data"); }
bool protocolInHTTPFamily() const;
bool isLocalFile() const;
diff --git a/WebCore/platform/KURLGoogle.cpp b/WebCore/platform/KURLGoogle.cpp
index 3d23fcf..726bc57 100644
--- a/WebCore/platform/KURLGoogle.cpp
+++ b/WebCore/platform/KURLGoogle.cpp
@@ -549,6 +549,34 @@ bool KURL::hasFragmentIdentifier() const
return m_url.m_parsed.ref.len >= 0;
}
+void KURL::copyParsedQueryTo(ParsedURLParameters& parameters) const
+{
+ String query = m_url.componentString(m_url.m_parsed.query);
+ const UChar* pos = query.characters();
+ const UChar* end = query.characters() + query.length();
+ while (pos < end) {
+ const UChar* parameterStart = pos;
+ while (pos < end && *pos != '&')
+ ++pos;
+ const UChar* parameterEnd = pos;
+ if (pos < end) {
+ ASSERT(*pos == '&');
+ ++pos;
+ }
+ if (parameterStart == parameterEnd)
+ continue;
+ const UChar* nameStart = parameterStart;
+ const UChar* equalSign = parameterStart;
+ while (equalSign < parameterEnd && *equalSign != '=')
+ ++equalSign;
+ if (equalSign == nameStart)
+ continue;
+ String name(nameStart, equalSign - nameStart);
+ String value = equalSign == parameterEnd ? String() : String(equalSign + 1, parameterEnd - equalSign - 1);
+ parameters.set(name, value);
+ }
+}
+
String KURL::baseAsString() const
{
// FIXME: There is probably a more efficient way to do this?
diff --git a/WebCore/platform/Language.cpp b/WebCore/platform/Language.cpp
new file mode 100644
index 0000000..6cf2597
--- /dev/null
+++ b/WebCore/platform/Language.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "Language.h"
+
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+typedef HashMap<void*, LanguageChangeObserverFunction> ObserverMap;
+static ObserverMap& observerMap()
+{
+ DEFINE_STATIC_LOCAL(ObserverMap, map, ());
+ return map;
+}
+
+void addLanguageChangeObserver(void* context, LanguageChangeObserverFunction customObserver)
+{
+ observerMap().set(context, customObserver);
+}
+
+void removeLanguageChangeObserver(void* context)
+{
+ ASSERT(observerMap().contains(context));
+ observerMap().remove(context);
+}
+
+void languageDidChange()
+{
+ ObserverMap::iterator end = observerMap().end();
+ for (ObserverMap::iterator iter = observerMap().begin(); iter != end; ++iter)
+ iter->second(iter->first);
+}
+
+static String& languageOverride()
+{
+ DEFINE_STATIC_LOCAL(String, override, ());
+ return override;
+}
+
+String defaultLanguage()
+{
+ const String& override = languageOverride();
+ if (!override.isNull())
+ return override;
+
+ return platformDefaultLanguage();
+}
+
+void overrideDefaultLanguage(const String& override)
+{
+ languageOverride() = override;
+}
+
+}
diff --git a/WebCore/platform/Language.h b/WebCore/platform/Language.h
index 4c92755..656caee 100644
--- a/WebCore/platform/Language.h
+++ b/WebCore/platform/Language.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2003, 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
@@ -10,17 +10,17 @@
* notice, this 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.
+ * 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 Language_h
@@ -30,8 +30,16 @@
namespace WebCore {
- String defaultLanguage();
+String defaultLanguage();
+void overrideDefaultLanguage(const String&);
+// The observer function will be called when system language changes (unless it's overridden by overrideDefaultLanguage()).
+typedef void (*LanguageChangeObserverFunction)(void* context);
+void addLanguageChangeObserver(void* context, LanguageChangeObserverFunction);
+void removeLanguageChangeObserver(void* context);
+
+String platformDefaultLanguage();
+void languageDidChange();
}
#endif
diff --git a/WebCore/platform/Logging.cpp b/WebCore/platform/Logging.cpp
index 7fb15b1..8f64282 100644
--- a/WebCore/platform/Logging.cpp
+++ b/WebCore/platform/Logging.cpp
@@ -33,13 +33,11 @@ WTFLogChannel LogNotYetImplemented = { 0x00000001, "WebCoreLogLevel", WTFLogChan
WTFLogChannel LogFrames = { 0x00000010, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogLoading = { 0x00000020, "WebCoreLogLevel", WTFLogChannelOff };
-
WTFLogChannel LogPopupBlocking = { 0x00000040, "WebCoreLogLevel", WTFLogChannelOff };
-
WTFLogChannel LogEvents = { 0x00000080, "WebCoreLogLevel", WTFLogChannelOff };
+
WTFLogChannel LogEditing = { 0x00000100, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogLiveConnect = { 0x00000200, "WebCoreLogLevel", WTFLogChannelOff };
-
WTFLogChannel LogIconDatabase = { 0x00000400, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogSQLDatabase = { 0x00000800, "WebCoreLogLevel", WTFLogChannelOff };
@@ -49,6 +47,7 @@ WTFLogChannel LogHistory = { 0x00004000, "WebCoreLogLevel", WTFLogChan
WTFLogChannel LogPageCache = { 0x00008000, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogPlatformLeaks = { 0x00010000, "WebCoreLogLevel", WTFLogChannelOff };
+WTFLogChannel LogResourceLoading = { 0x00020000, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogNetwork = { 0x00100000, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogFTP = { 0x00200000, "WebCoreLogLevel", WTFLogChannelOff };
@@ -56,10 +55,10 @@ WTFLogChannel LogThreading = { 0x00400000, "WebCoreLogLevel", WTFLogChan
WTFLogChannel LogStorageAPI = { 0x00800000, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogMedia = { 0x01000000, "WebCoreLogLevel", WTFLogChannelOff };
-
WTFLogChannel LogPlugins = { 0x02000000, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogArchives = { 0x04000000, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogProgress = { 0x08000000, "WebCoreLogLevel", WTFLogChannelOff };
+
WTFLogChannel LogFileAPI = { 0x10000000, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel* getChannelFromName(const String& channelName)
@@ -106,6 +105,9 @@ WTFLogChannel* getChannelFromName(const String& channelName)
if (equalIgnoringCase(channelName, String("PlatformLeaks")))
return &LogPlatformLeaks;
+ if (equalIgnoringCase(channelName, String("ResourceLoading")))
+ return &LogResourceLoading;
+
if (equalIgnoringCase(channelName, String("Plugins")))
return &LogPlugins;
diff --git a/WebCore/platform/Logging.h b/WebCore/platform/Logging.h
index df3c6fd..11ad1db 100644
--- a/WebCore/platform/Logging.h
+++ b/WebCore/platform/Logging.h
@@ -49,6 +49,7 @@ namespace WebCore {
extern WTFLogChannel LogHistory;
extern WTFLogChannel LogPageCache;
extern WTFLogChannel LogPlatformLeaks;
+ extern WTFLogChannel LogResourceLoading;
extern WTFLogChannel LogNetwork;
extern WTFLogChannel LogFTP;
extern WTFLogChannel LogThreading;
diff --git a/WebCore/platform/PlatformKeyboardEvent.h b/WebCore/platform/PlatformKeyboardEvent.h
index 6ec4879..7ce7017 100644
--- a/WebCore/platform/PlatformKeyboardEvent.h
+++ b/WebCore/platform/PlatformKeyboardEvent.h
@@ -186,6 +186,8 @@ namespace WebCore {
#if PLATFORM(QT)
PlatformKeyboardEvent(QKeyEvent*);
QKeyEvent* qtEvent() const { return m_qtEvent; }
+ uint32_t nativeModifiers() const;
+ uint32_t nativeScanCode() const;
#endif
#if PLATFORM(WX)
diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp
index 0e95e22..fac37d7 100644
--- a/WebCore/platform/ScrollView.cpp
+++ b/WebCore/platform/ScrollView.cpp
@@ -718,27 +718,27 @@ void ScrollView::wheelEvent(PlatformWheelEvent& e)
return;
}
- // Determine how much we want to scroll. If we can move at all, we will accept the event.
+ // Accept the event if we have a scrollbar in that direction and can still
+ // scroll any further.
+ float deltaX = m_horizontalScrollbar ? e.deltaX() : 0;
+ float deltaY = m_verticalScrollbar ? e.deltaY() : 0;
IntSize maxScrollDelta = maximumScrollPosition() - scrollPosition();
- if ((e.deltaX() < 0 && maxScrollDelta.width() > 0) ||
- (e.deltaX() > 0 && scrollOffset().width() > 0) ||
- (e.deltaY() < 0 && maxScrollDelta.height() > 0) ||
- (e.deltaY() > 0 && scrollOffset().height() > 0)) {
+ if ((deltaX < 0 && maxScrollDelta.width() > 0)
+ || (deltaX > 0 && scrollOffset().width() > 0)
+ || (deltaY < 0 && maxScrollDelta.height() > 0)
+ || (deltaY > 0 && scrollOffset().height() > 0)) {
e.accept();
- float deltaX = e.deltaX();
- float deltaY = e.deltaY();
if (e.granularity() == ScrollByPageWheelEvent) {
- ASSERT(deltaX == 0);
+ ASSERT(!e.deltaX());
bool negative = deltaY < 0;
deltaY = max(max(static_cast<float>(visibleHeight()) * Scrollbar::minFractionToStepWhenPaging(), static_cast<float>(visibleHeight() - Scrollbar::maxOverlapBetweenPages())), 1.0f);
if (negative)
deltaY = -deltaY;
}
- // Should we fall back on scrollBy() if there is no scrollbar for a non-zero delta?
- if (deltaY && m_verticalScrollbar)
+ if (deltaY)
m_verticalScrollbar->scroll(ScrollUp, ScrollByPixel, deltaY);
- if (deltaX && m_horizontalScrollbar)
+ if (deltaX)
m_horizontalScrollbar->scroll(ScrollLeft, ScrollByPixel, deltaX);
}
}
@@ -837,7 +837,7 @@ void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect)
void ScrollView::paintPanScrollIcon(GraphicsContext* context)
{
static Image* panScrollIcon = Image::loadPlatformResource("panIcon").releaseRef();
- context->drawImage(panScrollIcon, DeviceColorSpace, m_panScrollIconPoint);
+ context->drawImage(panScrollIcon, ColorSpaceDeviceRGB, m_panScrollIconPoint);
}
void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
diff --git a/WebCore/platform/ScrollbarTheme.h b/WebCore/platform/ScrollbarTheme.h
index c5c2094..0efaf7a 100644
--- a/WebCore/platform/ScrollbarTheme.h
+++ b/WebCore/platform/ScrollbarTheme.h
@@ -73,7 +73,7 @@ public:
virtual void invalidatePart(Scrollbar*, ScrollbarPart) {}
- virtual void paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect) { context->fillRect(cornerRect, Color::white, DeviceColorSpace); }
+ virtual void paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect) { context->fillRect(cornerRect, Color::white, ColorSpaceDeviceRGB); }
virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&) { return false; }
virtual bool shouldSnapBackToDragOrigin(Scrollbar*, const PlatformMouseEvent&) { return false; }
diff --git a/WebCore/platform/ScrollbarThemeComposite.cpp b/WebCore/platform/ScrollbarThemeComposite.cpp
index fdac14d..bf00ebb 100644
--- a/WebCore/platform/ScrollbarThemeComposite.cpp
+++ b/WebCore/platform/ScrollbarThemeComposite.cpp
@@ -298,7 +298,7 @@ void ScrollbarThemeComposite::paintScrollCorner(ScrollView* view, GraphicsContex
Page* page = frameView->frame() ? frameView->frame()->page() : 0;
if (page && page->settings()->shouldPaintCustomScrollbars() && page->chrome()->client()->paintCustomScrollCorner(context, cornerRect))
return;
- context->fillRect(cornerRect, Color::white, DeviceColorSpace);
+ context->fillRect(cornerRect, Color::white, ColorSpaceDeviceRGB);
}
}
diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h
index 089a1e9..85612ed 100644
--- a/WebCore/platform/Widget.h
+++ b/WebCore/platform/Widget.h
@@ -232,6 +232,10 @@ public:
const String edjeThemeRecursive() const;
#endif
+#if PLATFORM(CHROMIUM)
+ virtual bool isPluginContainer() const { return false; }
+#endif
+
// Virtual methods to convert points to/from the containing ScrollView
virtual IntRect convertToContainingView(const IntRect&) const;
virtual IntRect convertFromContainingView(const IntRect&) const;
diff --git a/WebCore/platform/android/FileSystemAndroid.cpp b/WebCore/platform/android/FileSystemAndroid.cpp
index 3513958..5ab8929 100644
--- a/WebCore/platform/android/FileSystemAndroid.cpp
+++ b/WebCore/platform/android/FileSystemAndroid.cpp
@@ -28,8 +28,11 @@
#include "config.h"
#include "FileSystem.h"
+<<<<<<< HEAD
#include "PlatformBridge.h"
#include "StringBuilder.h"
+=======
+>>>>>>> webkit.org at r70209
#include "cutils/log.h"
#include <dirent.h>
#include <dlfcn.h>
@@ -37,6 +40,7 @@
#include <fnmatch.h>
#include <sys/stat.h>
#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
namespace WebCore {
diff --git a/WebCore/platform/audio/AudioResampler.cpp b/WebCore/platform/audio/AudioResampler.cpp
new file mode 100644
index 0000000..7f8221e
--- /dev/null
+++ b/WebCore/platform/audio/AudioResampler.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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 ENABLE(WEB_AUDIO)
+
+#include "AudioResampler.h"
+
+#include "AudioBus.h"
+#include <algorithm>
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+const double AudioResampler::MaxRate = 8.0;
+
+AudioResampler::AudioResampler()
+ : m_rate(1.0)
+{
+ m_kernels.append(adoptPtr(new AudioResamplerKernel(this)));
+ m_sourceBus = adoptPtr(new AudioBus(1, 0, false));
+}
+
+AudioResampler::AudioResampler(unsigned numberOfChannels)
+ : m_rate(1.0)
+{
+ for (unsigned i = 0; i < numberOfChannels; ++i)
+ m_kernels.append(adoptPtr(new AudioResamplerKernel(this)));
+
+ m_sourceBus = adoptPtr(new AudioBus(numberOfChannels, 0, false));
+}
+
+void AudioResampler::configureChannels(unsigned numberOfChannels)
+{
+ unsigned currentSize = m_kernels.size();
+ if (numberOfChannels == currentSize)
+ return; // already setup
+
+ // First deal with adding or removing kernels.
+ if (numberOfChannels > currentSize) {
+ for (unsigned i = currentSize; i < numberOfChannels; ++i)
+ m_kernels.append(adoptPtr(new AudioResamplerKernel(this)));
+ } else
+ m_kernels.resize(numberOfChannels);
+
+ // Reconfigure our source bus to the new channel size.
+ m_sourceBus = adoptPtr(new AudioBus(numberOfChannels, 0, false));
+}
+
+void AudioResampler::process(AudioSourceProvider* provider, AudioBus* destinationBus, size_t framesToProcess)
+{
+ ASSERT(provider);
+ if (!provider)
+ return;
+
+ unsigned numberOfChannels = m_kernels.size();
+
+ // Make sure our configuration matches the bus we're rendering to.
+ bool channelsMatch = (destinationBus && destinationBus->numberOfChannels() == numberOfChannels);
+ ASSERT(channelsMatch);
+ if (!channelsMatch)
+ return;
+
+ // Setup the source bus.
+ for (unsigned i = 0; i < numberOfChannels; ++i) {
+ // Figure out how many frames we need to get from the provider, and a pointer to the buffer.
+ size_t framesNeeded;
+ float* fillPointer = m_kernels[i]->getSourcePointer(framesToProcess, &framesNeeded);
+ ASSERT(fillPointer);
+ if (!fillPointer)
+ return;
+
+ m_sourceBus->setChannelMemory(i, fillPointer, framesNeeded);
+ }
+
+ // Ask the provider to supply the desired number of source frames.
+ provider->provideInput(m_sourceBus.get(), m_sourceBus->length());
+
+ // Now that we have the source data, resample each channel into the destination bus.
+ // FIXME: optimize for the common stereo case where it's faster to process both left/right channels in the same inner loop.
+ for (unsigned i = 0; i < numberOfChannels; ++i) {
+ float* destination = destinationBus->channel(i)->data();
+ m_kernels[i]->process(destination, framesToProcess);
+ }
+}
+
+void AudioResampler::setRate(double rate)
+{
+ if (isnan(rate) || isinf(rate) || rate <= 0.0)
+ return;
+
+ m_rate = min(AudioResampler::MaxRate, rate);
+}
+
+void AudioResampler::reset()
+{
+ unsigned numberOfChannels = m_kernels.size();
+ for (unsigned i = 0; i < numberOfChannels; ++i)
+ m_kernels[i]->reset();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/AudioResampler.h b/WebCore/platform/audio/AudioResampler.h
new file mode 100644
index 0000000..ed352b8
--- /dev/null
+++ b/WebCore/platform/audio/AudioResampler.h
@@ -0,0 +1,68 @@
+/*
+ * 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 AudioResampler_h
+#define AudioResampler_h
+
+#include "AudioBus.h"
+#include "AudioResamplerKernel.h"
+#include "AudioSourceProvider.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// AudioResampler resamples the audio stream from an AudioSourceProvider.
+// The audio stream may be single or multi-channel.
+// The default constructor defaults to single-channel (mono).
+
+class AudioResampler {
+public:
+ AudioResampler();
+ AudioResampler(unsigned numberOfChannels);
+ ~AudioResampler() { }
+
+ // Given an AudioSourceProvider, process() resamples the source stream into destinationBus.
+ void process(AudioSourceProvider*, AudioBus* destinationBus, size_t framesToProcess);
+
+ // Resets the processing state.
+ void reset();
+
+ void configureChannels(unsigned numberOfChannels);
+
+ // 0 < rate <= MaxRate
+ void setRate(double rate);
+ double rate() const { return m_rate; }
+
+ static const double MaxRate;
+
+private:
+ double m_rate;
+ Vector<OwnPtr<AudioResamplerKernel> > m_kernels;
+ OwnPtr<AudioBus> m_sourceBus;
+};
+
+} // namespace WebCore
+
+#endif // AudioResampler_h
diff --git a/WebCore/platform/audio/AudioUtilities.cpp b/WebCore/platform/audio/AudioUtilities.cpp
new file mode 100644
index 0000000..32f4335
--- /dev/null
+++ b/WebCore/platform/audio/AudioUtilities.cpp
@@ -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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this 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 "AudioUtilities.h"
+
+#include <math.h>
+
+namespace WebCore {
+
+namespace AudioUtilities {
+
+double decibelsToLinear(double decibels)
+{
+ return pow(10.0, 0.05 * decibels);
+}
+
+double linearToDecibels(double linear)
+{
+ // It's not possible to calculate decibels for a zero linear value since it would be -Inf.
+ // -1000.0 dB represents a very tiny linear value in case we ever reach this case.
+ ASSERT(linear);
+ if (!linear)
+ return -1000.0;
+
+ return 20.0 * log10(linear);
+}
+
+double discreteTimeConstantForSampleRate(double timeConstant, double sampleRate)
+{
+ return 1.0 - pow(1.0 / M_E, 1.0 / (sampleRate * timeConstant));
+}
+
+} // AudioUtilites
+
+} // WebCore
diff --git a/WebCore/platform/audio/AudioUtilities.h b/WebCore/platform/audio/AudioUtilities.h
new file mode 100644
index 0000000..7cf44ce
--- /dev/null
+++ b/WebCore/platform/audio/AudioUtilities.h
@@ -0,0 +1,45 @@
+/*
+ * 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 AudioUtilities_h
+#define AudioUtilities_h
+
+namespace WebCore {
+
+namespace AudioUtilities {
+
+// Standard functions for converting to and from decibel values from linear.
+double linearToDecibels(double);
+double decibelsToLinear(double);
+
+// timeConstant is the time it takes a first-order linear time-invariant system
+// to reach the value 1 - 1/e (around 63.2%) given a step input response.
+// discreteTimeConstantForSampleRate() will return the discrete time-constant for the specific sampleRate.
+double discreteTimeConstantForSampleRate(double timeConstant, double sampleRate);
+
+} // AudioUtilites
+
+} // WebCore
+
+#endif // AudioUtilities_h
diff --git a/WebCore/platform/audio/EqualPowerPanner.cpp b/WebCore/platform/audio/EqualPowerPanner.cpp
new file mode 100644
index 0000000..2e4e10f
--- /dev/null
+++ b/WebCore/platform/audio/EqualPowerPanner.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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this 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 ENABLE(WEB_AUDIO)
+
+#include "EqualPowerPanner.h"
+
+#include "AudioBus.h"
+#include "AudioUtilities.h"
+#include <math.h>
+
+// Use a 50ms smoothing / de-zippering time-constant.
+const double SmoothingTimeConstant = 0.050;
+
+namespace WebCore {
+
+EqualPowerPanner::EqualPowerPanner(double sampleRate)
+ : Panner(PanningModelEqualPower)
+ , m_isFirstRender(true)
+ , m_gainL(0.0)
+ , m_gainR(0.0)
+{
+ m_smoothingConstant = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, sampleRate);
+}
+
+void EqualPowerPanner::pan(double azimuth, double /*elevation*/, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess)
+{
+ // FIXME: implement stereo sources
+ bool isInputSafe = inputBus && inputBus->numberOfChannels() == 1 && framesToProcess <= inputBus->length();
+ ASSERT(isInputSafe);
+ if (!isInputSafe)
+ return;
+
+ bool isOutputSafe = outputBus && outputBus->numberOfChannels() == 2 && framesToProcess <= outputBus->length();
+ ASSERT(isOutputSafe);
+ if (!isOutputSafe)
+ return;
+
+ AudioChannel* channel = inputBus->channel(0);
+ float* sourceP = channel->data();
+ float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->data();
+ float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->data();
+
+ if (!sourceP || !destinationL || !destinationR)
+ return;
+
+ // Pan smoothly from left to right with azimuth going from -30 -> +30 degrees.
+ double desiredPanPosition;
+ if (azimuth > 30.0)
+ desiredPanPosition = 1.0;
+ else if (azimuth < -30.0)
+ desiredPanPosition = 0.0;
+ else
+ desiredPanPosition = (azimuth + 30.0) / 60.0;
+
+ double desiredGainL = 0.5 * cos(M_PI * desiredPanPosition) + 0.5;
+ double desiredGainR = sqrt(1.0 - desiredGainL*desiredGainL);
+
+ // Don't de-zipper on first render call.
+ if (m_isFirstRender) {
+ m_isFirstRender = false;
+ m_gainL = desiredGainL;
+ m_gainR = desiredGainR;
+ }
+
+ // Cache in local variables.
+ double gainL = m_gainL;
+ double gainR = m_gainR;
+
+ // Get local copy of smoothing constant.
+ const double SmoothingConstant = m_smoothingConstant;
+
+ int n = framesToProcess;
+
+ while (n--) {
+ float input = *sourceP++;
+ gainL += (desiredGainL - gainL) * SmoothingConstant;
+ gainR += (desiredGainR - gainR) * SmoothingConstant;
+ *destinationL++ = static_cast<float>(input * gainL);
+ *destinationR++ = static_cast<float>(input * gainR);
+ }
+
+ m_gainL = gainL;
+ m_gainR = gainR;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/EqualPowerPanner.h b/WebCore/platform/audio/EqualPowerPanner.h
new file mode 100644
index 0000000..f20617e
--- /dev/null
+++ b/WebCore/platform/audio/EqualPowerPanner.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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this 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 EqualPowerPanner_h
+#define EqualPowerPanner_h
+
+#include "Panner.h"
+
+namespace WebCore {
+
+// Common type of stereo panner as found in normal audio mixing equipment.
+
+class EqualPowerPanner : public Panner {
+public:
+ EqualPowerPanner(double sampleRate);
+
+ virtual void pan(double azimuth, double elevation, AudioBus* inputBus, AudioBus* outputBuf, size_t framesToProcess);
+
+ virtual void reset() { m_isFirstRender = true; }
+
+private:
+ // For smoothing / de-zippering
+ bool m_isFirstRender;
+ double m_smoothingConstant;
+
+ double m_gainL;
+ double m_gainR;
+};
+
+} // namespace WebCore
+
+#endif // EqualPowerPanner_h
diff --git a/WebCore/platform/audio/HRTFPanner.cpp b/WebCore/platform/audio/HRTFPanner.cpp
new file mode 100644
index 0000000..56f06f1
--- /dev/null
+++ b/WebCore/platform/audio/HRTFPanner.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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 ENABLE(WEB_AUDIO)
+
+#include "HRTFPanner.h"
+
+#include "AudioBus.h"
+#include "FFTConvolver.h"
+#include "HRTFDatabase.h"
+#include "HRTFDatabaseLoader.h"
+#include <algorithm>
+#include <math.h>
+#include <wtf/RefPtr.h>
+
+using namespace std;
+
+namespace WebCore {
+
+// The value of 2 milliseconds is larger than the largest delay which exists in any HRTFKernel from the default HRTFDatabase (0.0136 seconds).
+// We ASSERT the delay values used in process() with this value.
+const double MaxDelayTimeSeconds = 0.002;
+
+HRTFPanner::HRTFPanner(double sampleRate)
+ : Panner(PanningModelHRTF)
+ , m_sampleRate(sampleRate)
+ , m_isFirstRender(true)
+ , m_azimuthIndex(0)
+ , m_convolverL(fftSizeForSampleRate(sampleRate))
+ , m_convolverR(fftSizeForSampleRate(sampleRate))
+ , m_delayLineL(MaxDelayTimeSeconds, sampleRate)
+ , m_delayLineR(MaxDelayTimeSeconds, sampleRate)
+{
+}
+
+HRTFPanner::~HRTFPanner()
+{
+}
+
+size_t HRTFPanner::fftSizeForSampleRate(double sampleRate)
+{
+ // The HRTF impulse responses (loaded as audio resources) are 512 sample-frames @44.1KHz.
+ // Currently, we truncate the impulse responses to half this size, but an FFT-size of twice impulse response size is needed (for convolution).
+ // So for sample rates around 44.1KHz an FFT size of 512 is good. We double that size for higher sample rates.
+ ASSERT(sampleRate >= 44100 && sampleRate <= 96000.0);
+ return (sampleRate <= 48000.0) ? 512 : 1024;
+}
+
+void HRTFPanner::reset()
+{
+ m_isFirstRender = true;
+ m_convolverL.reset();
+ m_convolverR.reset();
+ m_delayLineL.reset();
+ m_delayLineR.reset();
+}
+
+static bool wrapDistance(int i, int j, int length)
+{
+ int directDistance = abs(i - j);
+ int indirectDistance = length - directDistance;
+
+ return indirectDistance < directDistance;
+}
+
+int HRTFPanner::calculateDesiredAzimuthIndexAndBlend(double azimuth, double& azimuthBlend)
+{
+ // Convert the azimuth angle from the range -180 -> +180 into the range 0 -> 360.
+ // The azimuth index may then be calculated from this positive value.
+ if (azimuth < 0)
+ azimuth += 360.0;
+
+ HRTFDatabase* database = HRTFDatabaseLoader::defaultHRTFDatabase();
+ ASSERT(database);
+
+ int numberOfAzimuths = database->numberOfAzimuths();
+ const double angleBetweenAzimuths = 360.0 / numberOfAzimuths;
+
+ // Calculate the azimuth index and the blend (0 -> 1) for interpolation.
+ double desiredAzimuthIndexFloat = azimuth / angleBetweenAzimuths;
+ int desiredAzimuthIndex = static_cast<int>(desiredAzimuthIndexFloat);
+ azimuthBlend = desiredAzimuthIndexFloat - static_cast<double>(desiredAzimuthIndex);
+
+ // We don't immediately start using this azimuth index, but instead approach this index from the last index we rendered at.
+ // This minimizes the clicks and graininess for moving sources which occur otherwise.
+ desiredAzimuthIndex = max(0, desiredAzimuthIndex);
+ desiredAzimuthIndex = min(numberOfAzimuths - 1, desiredAzimuthIndex);
+ return desiredAzimuthIndex;
+}
+
+void HRTFPanner::pan(double desiredAzimuth, double elevation, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess)
+{
+ unsigned numInputChannels = inputBus ? inputBus->numberOfChannels() : 0;
+
+ bool isInputGood = inputBus && numInputChannels >= 1 && numInputChannels <= 2;
+ ASSERT(isInputGood);
+
+ bool isOutputGood = outputBus && outputBus->numberOfChannels() == 2 && framesToProcess <= outputBus->length();
+ ASSERT(isOutputGood);
+
+ if (!isInputGood || !isOutputGood) {
+ if (outputBus)
+ outputBus->zero();
+ return;
+ }
+
+ // This code only runs as long as the context is alive and after database has been loaded.
+ HRTFDatabase* database = HRTFDatabaseLoader::defaultHRTFDatabase();
+ ASSERT(database);
+ if (!database) {
+ outputBus->zero();
+ return;
+ }
+
+ // IRCAM HRTF azimuths values from the loaded database is reversed from the panner's notion of azimuth.
+ double azimuth = -desiredAzimuth;
+
+ bool isAzimuthGood = azimuth >= -180.0 && azimuth <= 180.0;
+ ASSERT(isAzimuthGood);
+ if (!isAzimuthGood) {
+ outputBus->zero();
+ return;
+ }
+
+ // Normally, we'll just be dealing with mono sources.
+ // If we have a stereo input, implement stereo panning with left source processed by left HRTF, and right source by right HRTF.
+ AudioChannel* inputChannelL = inputBus->channelByType(AudioBus::ChannelLeft);
+ AudioChannel* inputChannelR = numInputChannels > 1 ? inputBus->channelByType(AudioBus::ChannelRight) : 0;
+
+ // Get source and destination pointers.
+ float* sourceL = inputChannelL->data();
+ float* sourceR = numInputChannels > 1 ? inputChannelR->data() : sourceL;
+ float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->data();
+ float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->data();
+
+ double azimuthBlend;
+ int desiredAzimuthIndex = calculateDesiredAzimuthIndexAndBlend(azimuth, azimuthBlend);
+
+ // This algorithm currently requires that we process in power-of-two size chunks at least 128.
+ ASSERT(1UL << static_cast<int>(log2(framesToProcess)) == framesToProcess);
+ ASSERT(framesToProcess >= 128);
+
+ const unsigned framesPerSegment = 128;
+ const unsigned numberOfSegments = framesToProcess / framesPerSegment;
+
+ for (unsigned segment = 0; segment < numberOfSegments; ++segment) {
+ if (m_isFirstRender) {
+ // Snap exactly to desired position (first time and after reset()).
+ m_azimuthIndex = desiredAzimuthIndex;
+ m_isFirstRender = false;
+ } else {
+ // Each segment renders with an azimuth index closer by one to the desired azimuth index.
+ // Because inter-aural time delay is mostly a factor of azimuth and the delay is where the clicks and graininess come from,
+ // we don't bother smoothing the elevations.
+ int numberOfAzimuths = database->numberOfAzimuths();
+ bool wrap = wrapDistance(m_azimuthIndex, desiredAzimuthIndex, numberOfAzimuths);
+ if (wrap) {
+ if (m_azimuthIndex < desiredAzimuthIndex)
+ m_azimuthIndex = (m_azimuthIndex - 1 + numberOfAzimuths) % numberOfAzimuths;
+ else if (m_azimuthIndex > desiredAzimuthIndex)
+ m_azimuthIndex = (m_azimuthIndex + 1) % numberOfAzimuths;
+ } else {
+ if (m_azimuthIndex < desiredAzimuthIndex)
+ m_azimuthIndex = (m_azimuthIndex + 1) % numberOfAzimuths;
+ else if (m_azimuthIndex > desiredAzimuthIndex)
+ m_azimuthIndex = (m_azimuthIndex - 1 + numberOfAzimuths) % numberOfAzimuths;
+ }
+ }
+
+ // Get the HRTFKernels and interpolated delays.
+ HRTFKernel* kernelL;
+ HRTFKernel* kernelR;
+ double frameDelayL;
+ double frameDelayR;
+ database->getKernelsFromAzimuthElevation(azimuthBlend, m_azimuthIndex, elevation, kernelL, kernelR, frameDelayL, frameDelayR);
+
+ ASSERT(kernelL && kernelR);
+ if (!kernelL || !kernelR) {
+ outputBus->zero();
+ return;
+ }
+
+ ASSERT(frameDelayL / sampleRate() < MaxDelayTimeSeconds && frameDelayR / sampleRate() < MaxDelayTimeSeconds);
+
+ // Calculate the source and destination pointers for the current segment.
+ unsigned offset = segment * framesPerSegment;
+ float* segmentSourceL = sourceL + offset;
+ float* segmentSourceR = sourceR + offset;
+ float* segmentDestinationL = destinationL + offset;
+ float* segmentDestinationR = destinationR + offset;
+
+ // First run through delay lines for inter-aural time difference.
+ m_delayLineL.setDelayFrames(frameDelayL);
+ m_delayLineR.setDelayFrames(frameDelayR);
+ m_delayLineL.process(segmentSourceL, segmentDestinationL, framesPerSegment);
+ m_delayLineR.process(segmentSourceR, segmentDestinationR, framesPerSegment);
+
+ // Now do the convolutions in-place.
+ m_convolverL.process(kernelL->fftFrame(), segmentDestinationL, segmentDestinationL, framesPerSegment);
+ m_convolverR.process(kernelR->fftFrame(), segmentDestinationR, segmentDestinationR, framesPerSegment);
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/HRTFPanner.h b/WebCore/platform/audio/HRTFPanner.h
new file mode 100644
index 0000000..6c13d48
--- /dev/null
+++ b/WebCore/platform/audio/HRTFPanner.h
@@ -0,0 +1,68 @@
+/*
+ * 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 HRTFPanner_h
+#define HRTFPanner_h
+
+#include "DelayDSPKernel.h"
+#include "FFTConvolver.h"
+#include "Panner.h"
+
+namespace WebCore {
+
+class HRTFPanner : public Panner {
+public:
+ explicit HRTFPanner(double sampleRate);
+ virtual ~HRTFPanner();
+
+ // Panner
+ virtual void pan(double azimuth, double elevation, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess);
+ virtual void reset();
+
+ size_t fftSize() { return fftSizeForSampleRate(m_sampleRate); }
+ static size_t fftSizeForSampleRate(double sampleRate);
+
+ double sampleRate() const { return m_sampleRate; }
+
+private:
+ // Given an azimuth angle in the range -180 -> +180, returns the corresponding azimuth index for the database,
+ // and azimuthBlend which is an interpolation value from 0 -> 1.
+ int calculateDesiredAzimuthIndexAndBlend(double azimuth, double& azimuthBlend);
+
+ double m_sampleRate;
+
+ // m_isFirstRender and m_azimuthIndex are used to avoid harshly changing from rendering at one azimuth angle to another angle very far away.
+ // Changing the azimuth gradually produces a smoother sound.
+ bool m_isFirstRender;
+ int m_azimuthIndex;
+
+ FFTConvolver m_convolverL;
+ FFTConvolver m_convolverR;
+ DelayDSPKernel m_delayLineL;
+ DelayDSPKernel m_delayLineR;
+};
+
+} // namespace WebCore
+
+#endif // HRTFPanner_h
diff --git a/WebCore/platform/brew/ClipboardBrew.cpp b/WebCore/platform/brew/ClipboardBrew.cpp
index 10025d6..c0504bc 100644
--- a/WebCore/platform/brew/ClipboardBrew.cpp
+++ b/WebCore/platform/brew/ClipboardBrew.cpp
@@ -42,7 +42,7 @@ PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy, DragData*, Frame*
}
ClipboardBrew::ClipboardBrew(ClipboardAccessPolicy policy, ClipboardType clipboardType)
- : Clipboard(clipboardType, isForDragging)
+ : Clipboard(policy, clipboardType)
{
}
diff --git a/WebCore/platform/brew/FileSystemBrew.cpp b/WebCore/platform/brew/FileSystemBrew.cpp
index a723e63..e207b55 100644
--- a/WebCore/platform/brew/FileSystemBrew.cpp
+++ b/WebCore/platform/brew/FileSystemBrew.cpp
@@ -30,24 +30,23 @@
#include "FileSystem.h"
#include "NotImplemented.h"
-#include "PlatformString.h"
-#include "StringBuilder.h"
#include <AEEAppGen.h>
#include <AEEFile.h>
#include <AEEStdLib.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
#include <wtf/RandomNumber.h>
+#include <wtf/brew/RefPtrBrew.h>
#include <wtf/brew/ShellBrew.h>
#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
namespace WebCore {
bool getFileSize(const String& path, long long& result)
{
- OwnPtr<IFileMgr> fileMgr = createInstance<IFileMgr>(AEECLSID_FILEMGR);
+ PlatformRefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
FileInfo info;
if (IFILEMGR_GetInfo(fileMgr.get(), path.utf8().data(), &info) == SUCCESS) {
@@ -67,21 +66,21 @@ bool getFileModificationTime(const String& path, time_t& result)
bool fileExists(const String& path)
{
- OwnPtr<IFileMgr> fileMgr = createInstance<IFileMgr>(AEECLSID_FILEMGR);
+ PlatformRefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
return (IFILEMGR_Test(fileMgr.get(), path.utf8().data()) == SUCCESS);
}
bool deleteFile(const String& path)
{
- OwnPtr<IFileMgr> fileMgr = createInstance<IFileMgr>(AEECLSID_FILEMGR);
+ PlatformRefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
return (IFILEMGR_Remove(fileMgr.get(), path.utf8().data()) == SUCCESS);
}
bool deleteEmptyDirectory(const String& path)
{
- OwnPtr<IFileMgr> fileMgr = createInstance<IFileMgr>(AEECLSID_FILEMGR);
+ PlatformRefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
return (IFILEMGR_RmDir(fileMgr.get(), path.utf8().data()) == SUCCESS);
}
@@ -110,7 +109,7 @@ CString fileSystemRepresentation(const String& path)
static String canonicalPath(const String& path)
{
- OwnPtr<IFileMgr> fileMgr = createInstance<IFileMgr>(AEECLSID_FILEMGR);
+ PlatformRefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
// Get the buffer size required to resolve the path.
int canonPathLen;
@@ -163,7 +162,7 @@ static bool makeAllDirectories(IFileMgr* fileManager, const String& path)
bool makeAllDirectories(const String& path)
{
- OwnPtr<IFileMgr> fileMgr = createInstance<IFileMgr>(AEECLSID_FILEMGR);
+ PlatformRefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
return makeAllDirectories(fileMgr.get(), canonicalPath(path));
}
@@ -193,7 +192,7 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
// use "fs:/~/tmp" as our temporary directory.
String tempPath("fs:/~/tmp");
- OwnPtr<IFileMgr> fileMgr = createInstance<IFileMgr>(AEECLSID_FILEMGR);
+ PlatformRefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
// Create the temporary directory if it does not exist.
IFILEMGR_MkDir(fileMgr.get(), tempPath.utf8().data());
diff --git a/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp b/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp
index 3384a4f..fc6a753 100644
--- a/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp
+++ b/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp
@@ -30,9 +30,14 @@
#include "WindowsKeyboardCodes.h"
#include <AEEEvent.h>
+#include <AEEIKeysMapping.h>
+#include <AEEKeysMapping.bid>
#include <AEEStdDef.h>
#include <AEEVCodes.h>
+#include <wtf/brew/RefPtrBrew.h>
+#include <wtf/brew/ShellBrew.h>
+
namespace WebCore {
static String keyIdentifierForBrewKeyCode(uint16 keyCode)
@@ -143,23 +148,93 @@ static int windowsKeyCodeForKeyEvent(uint16 code)
static inline String singleCharacterString(UChar c)
{
- return String(&c, 1);
+ UChar text;
+
+ // Some key codes are not mapped to Unicode characters. Convert them to Unicode characters here.
+ switch (c) {
+ case AVK_0:
+ text = VK_0;
+ break;
+ case AVK_1:
+ text = VK_1;
+ break;
+ case AVK_2:
+ text = VK_2;
+ break;
+ case AVK_3:
+ text = VK_3;
+ break;
+ case AVK_4:
+ text = VK_4;
+ break;
+ case AVK_5:
+ text = VK_5;
+ break;
+ case AVK_6:
+ text = VK_6;
+ break;
+ case AVK_7:
+ text = VK_7;
+ break;
+ case AVK_8:
+ text = VK_8;
+ break;
+ case AVK_9:
+ text = VK_9;
+ break;
+ case AVK_STAR:
+ text = '*';
+ break;
+ case AVK_POUND:
+ text = '#';
+ break;
+ case AVK_FUNCTION1:
+ text = '=';
+ break;
+ case AVK_FUNCTION2:
+ text = '/';
+ break;
+ case AVK_FUNCTION3:
+ text = '_';
+ break;
+ case AVK_PUNC1:
+ text = ',';
+ break;
+ case AVK_PUNC2:
+ text = '.';
+ break;
+ case AVK_SPACE:
+ text = VK_SPACE;
+ break;
+ default:
+ text = c;
+ break;
+ }
+
+ return String(&text, 1);
}
PlatformKeyboardEvent::PlatformKeyboardEvent(AEEEvent event, uint16 code, uint32 modifiers, Type type)
: m_type(type)
- , m_text((type == Char) ? singleCharacterString(code) : String())
- , m_unmodifiedText((type == Char) ? singleCharacterString(code) : String())
- , m_keyIdentifier((type == Char) ? String() : keyIdentifierForBrewKeyCode(code))
- , m_autoRepeat(modifiers & KB_AUTOREPEAT)
- , m_windowsVirtualKeyCode((type == RawKeyDown || type == KeyUp) ? windowsKeyCodeForKeyEvent(code) : 0)
- , m_nativeVirtualKeyCode(code)
, m_isKeypad(false)
- , m_shiftKey(modifiers & (KB_LSHIFT | KB_RSHIFT))
- , m_ctrlKey(modifiers & (KB_LCTRL | KB_RCTRL))
- , m_altKey(modifiers & (KB_LALT | KB_RALT))
, m_metaKey(false)
+ , m_windowsVirtualKeyCode((type == RawKeyDown || type == KeyUp) ? windowsKeyCodeForKeyEvent(code) : 0)
{
+ if ((m_type == Char) && modifiers) {
+ PlatformRefPtr<IKeysMapping> keysMapping = createRefPtrInstance<IKeysMapping>(AEECLSID_KeysMapping);
+ int result = IKeysMapping_GetMapping(keysMapping.get(), code, modifiers, reinterpret_cast<AECHAR*>(&code));
+ if (result == AEE_SUCCESS) // Reset the modifier when key code is successfully mapped.
+ modifiers = 0;
+ }
+
+ m_text = (type == Char) ? singleCharacterString(code) : String();
+ m_unmodifiedText = (type == Char) ? singleCharacterString(code) : String();
+ m_keyIdentifier = (type == Char) ? String() : keyIdentifierForBrewKeyCode(code);
+ m_nativeVirtualKeyCode = code;
+ m_autoRepeat = modifiers & KB_AUTOREPEAT;
+ m_shiftKey = modifiers & (KB_LSHIFT | KB_RSHIFT);
+ m_ctrlKey = modifiers & (KB_LCTRL | KB_RCTRL);
+ m_altKey = modifiers & (KB_LALT | KB_RALT);
}
void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool)
diff --git a/WebCore/platform/brew/ScreenBrew.cpp b/WebCore/platform/brew/ScreenBrew.cpp
index b141b34..53e53d0 100644
--- a/WebCore/platform/brew/ScreenBrew.cpp
+++ b/WebCore/platform/brew/ScreenBrew.cpp
@@ -36,6 +36,7 @@
#include <AEEAppGen.h>
#include <AEEStdLib.h>
+#include <wtf/brew/RefPtrBrew.h>
namespace WebCore {
@@ -48,17 +49,14 @@ struct DisplayInfo {
static void getDisplayInfo(DisplayInfo& info)
{
IDisplay* display = reinterpret_cast<AEEApplet*>(GETAPPINSTANCE())->m_pIDisplay;
- IBitmap* bitmap = IDisplay_GetDestination(display);
- ASSERT(bitmap);
+ PlatformRefPtr<IBitmap> bitmap = adoptPlatformRef(IDisplay_GetDestination(display));
AEEBitmapInfo bitmapInfo;
- IBitmap_GetInfo(bitmap, &bitmapInfo, sizeof(AEEBitmapInfo));
+ IBitmap_GetInfo(bitmap.get(), &bitmapInfo, sizeof(AEEBitmapInfo));
info.width = bitmapInfo.cx;
info.height = bitmapInfo.cy;
info.depth = bitmapInfo.nDepth;
-
- IBitmap_Release(bitmap);
}
FloatRect screenRect(Widget*)
diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h
index 121ec4b..74bad04 100644
--- a/WebCore/platform/chromium/ChromiumBridge.h
+++ b/WebCore/platform/chromium/ChromiumBridge.h
@@ -154,9 +154,10 @@ namespace WebCore {
// Forms --------------------------------------------------------------
static void notifyFormStateChanged(const Document*);
+#if !ENABLE(CLIENT_BASED_GEOLOCATION)
// Geolocation --------------------------------------------------------
static GeolocationServiceBridge* createGeolocationServiceBridge(GeolocationServiceChromium*);
-
+#endif
// Databases ----------------------------------------------------------
// Returns a handle to the DB file and ooptionally a handle to its containing directory
static PlatformFileHandle databaseOpenFile(const String& vfsFleName, int desiredFlags);
@@ -254,6 +255,45 @@ namespace WebCore {
GraphicsContext*, int part, int state, int classicState, const IntRect&);
static void paintProgressBar(
GraphicsContext*, const IntRect& barRect, const IntRect& valueRect, bool determinate, double animatedSeconds);
+#elif OS(LINUX)
+ // The UI part which is being accessed.
+ enum ThemePart {
+ PartScrollbarDownArrow,
+ PartScrollbarLeftArrow,
+ PartScrollbarRightArrow,
+ PartScrollbarUpArrow,
+ PartScrollbarHorizontalThumb,
+ PartScrollbarVerticalThumb,
+ PartScrollbarHoriztonalTrack,
+ PartScrollbarVerticalTrack,
+ };
+
+ // The current state of the associated Part.
+ enum ThemePaintState {
+ StateDisabled,
+ StateHover,
+ StateNormal,
+ StatePressed,
+ };
+
+ struct ScrollbarTrackExtraParams {
+ // The bounds of the entire track, as opposed to the part being painted.
+ int trackX;
+ int trackY;
+ int trackWidth;
+ int trackHeight;
+ };
+
+ union ThemePaintExtraParams {
+ ScrollbarTrackExtraParams scrollbarTrack;
+ };
+
+ // Gets the size of the given theme part. For variable sized items
+ // like vertical scrollbar thumbs, the width will be the required width of
+ // the track while the height will be the minimum height.
+ static IntSize getThemePartSize(ThemePart);
+ // Paint the given the given theme part.
+ static void paintThemePart(GraphicsContext*, ThemePart, ThemePaintState, const IntRect&, const ThemePaintExtraParams*);
#endif
// Trace Event --------------------------------------------------------
diff --git a/WebCore/platform/chromium/ChromiumDataObject.cpp b/WebCore/platform/chromium/ChromiumDataObject.cpp
index 8352669..78b794b 100644
--- a/WebCore/platform/chromium/ChromiumDataObject.cpp
+++ b/WebCore/platform/chromium/ChromiumDataObject.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Google 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
@@ -33,54 +33,187 @@
namespace WebCore {
-void ChromiumDataObject::clear()
+ChromiumDataObject::ChromiumDataObject(PassRefPtr<ChromiumDataObjectLegacy> data)
+ : RefCounted<ChromiumDataObject>()
+ , m_legacyData(data)
+{
+}
+
+ChromiumDataObject::ChromiumDataObject(PassRefPtr<ReadableDataObject> data)
+ : RefCounted<ChromiumDataObject>()
+ , m_readableData(data)
+{
+}
+
+ChromiumDataObject::ChromiumDataObject(PassRefPtr<WritableDataObject> data)
+ : RefCounted<ChromiumDataObject>()
+ , m_writableData(data)
+{
+}
+
+PassRefPtr<ChromiumDataObject> ChromiumDataObject::create(PassRefPtr<ChromiumDataObjectLegacy> data)
+{
+ return adoptRef(new ChromiumDataObject(data));
+}
+
+PassRefPtr<ChromiumDataObject> ChromiumDataObject::createReadable(Clipboard::ClipboardType clipboardType)
+{
+ return adoptRef(new ChromiumDataObject(ReadableDataObject::create(clipboardType)));
+}
+
+PassRefPtr<ChromiumDataObject> ChromiumDataObject::createWritable(Clipboard::ClipboardType clipboardType)
+{
+ return adoptRef(new ChromiumDataObject(WritableDataObject::create(clipboardType)));
+}
+
+void ChromiumDataObject::clearData(const String& type)
+{
+ if (m_legacyData)
+ m_legacyData->clearData(type);
+ else
+ m_writableData->clearData(type);
+}
+
+void ChromiumDataObject::clearAll()
{
- clearAllExceptFiles();
- filenames.clear();
+ if (m_legacyData)
+ m_legacyData->clearAll();
+ else
+ m_writableData->clearAll();
}
void ChromiumDataObject::clearAllExceptFiles()
{
- url = KURL();
- urlTitle = "";
- uriList.clear();
- downloadMetadata = "";
- fileExtension = "";
- plainText = "";
- textHtml = "";
- htmlBaseUrl = KURL();
- fileContentFilename = "";
- if (fileContent)
- fileContent->clear();
+ if (m_legacyData)
+ m_legacyData->clearAllExceptFiles();
+ else
+ m_writableData->clearAllExceptFiles();
}
bool ChromiumDataObject::hasData() const
{
- return !url.isEmpty()
- || !uriList.isEmpty()
- || !downloadMetadata.isEmpty()
- || !fileExtension.isEmpty()
- || !filenames.isEmpty()
- || !plainText.isEmpty()
- || !textHtml.isEmpty()
- || fileContent;
+ if (m_legacyData)
+ return m_legacyData->hasData();
+ return m_readableData->hasData();
+}
+
+HashSet<String> ChromiumDataObject::types() const
+{
+ if (m_legacyData)
+ return m_legacyData->types();
+ return m_readableData->types();
+}
+
+String ChromiumDataObject::getData(const String& type, bool& success)
+{
+ if (m_legacyData)
+ return m_legacyData->getData(type, success);
+ return m_readableData->getData(type, success);
+}
+
+bool ChromiumDataObject::setData(const String& type, const String& data)
+{
+ if (m_legacyData)
+ return m_legacyData->setData(type, data);
+ return m_writableData->setData(type, data);
+}
+
+String ChromiumDataObject::urlTitle() const
+{
+ if (m_legacyData)
+ return m_legacyData->urlTitle();
+ return m_readableData->urlTitle();
+}
+
+void ChromiumDataObject::setUrlTitle(const String& urlTitle)
+{
+ if (m_legacyData)
+ m_legacyData->setUrlTitle(urlTitle);
+ else
+ m_writableData->setUrlTitle(urlTitle);
+}
+
+KURL ChromiumDataObject::htmlBaseUrl() const
+{
+ if (m_legacyData)
+ return m_legacyData->htmlBaseUrl();
+ return m_readableData->htmlBaseUrl();
+}
+
+void ChromiumDataObject::setHtmlBaseUrl(const KURL& url)
+{
+ if (m_legacyData)
+ m_legacyData->setHtmlBaseUrl(url);
+ else
+ m_writableData->setHtmlBaseUrl(url);
+}
+
+bool ChromiumDataObject::containsFilenames() const
+{
+ if (m_legacyData)
+ return m_legacyData->containsFilenames();
+ return m_readableData->containsFilenames();
+}
+
+Vector<String> ChromiumDataObject::filenames() const
+{
+ if (m_legacyData)
+ return m_legacyData->filenames();
+ return m_readableData->filenames();
+}
+
+void ChromiumDataObject::setFilenames(const Vector<String>& filenames)
+{
+ if (m_legacyData)
+ m_legacyData->setFilenames(filenames);
+ else
+ ASSERT_NOT_REACHED();
+}
+
+String ChromiumDataObject::fileExtension() const
+{
+ if (m_legacyData)
+ return m_legacyData->fileExtension();
+ return m_writableData->fileExtension();
+}
+
+void ChromiumDataObject::setFileExtension(const String& fileExtension)
+{
+ if (m_legacyData)
+ m_legacyData->setFileExtension(fileExtension);
+ else
+ m_writableData->setFileExtension(fileExtension);
+}
+
+String ChromiumDataObject::fileContentFilename() const
+{
+ if (m_legacyData)
+ return m_legacyData->fileContentFilename();
+ return m_writableData->fileContentFilename();
+}
+
+void ChromiumDataObject::setFileContentFilename(const String& fileContentFilename)
+{
+ if (m_legacyData)
+ m_legacyData->setFileContentFilename(fileContentFilename);
+ else
+ m_writableData->setFileContentFilename(fileContentFilename);
+}
+
+PassRefPtr<SharedBuffer> ChromiumDataObject::fileContent() const
+{
+ if (m_legacyData)
+ return m_legacyData->fileContent();
+ return m_writableData->fileContent();
+}
+
+void ChromiumDataObject::setFileContent(PassRefPtr<SharedBuffer> fileContent)
+{
+ if (m_legacyData)
+ m_legacyData->setFileContent(fileContent);
+ else
+ m_writableData->setFileContent(fileContent);
+}
+
}
-ChromiumDataObject::ChromiumDataObject(const ChromiumDataObject& other)
- : RefCounted<ChromiumDataObject>()
- , urlTitle(other.urlTitle)
- , downloadMetadata(other.downloadMetadata)
- , fileExtension(other.fileExtension)
- , filenames(other.filenames)
- , plainText(other.plainText)
- , textHtml(other.textHtml)
- , htmlBaseUrl(other.htmlBaseUrl)
- , fileContentFilename(other.fileContentFilename)
- , url(other.url)
- , uriList(other.uriList)
-{
- if (other.fileContent.get())
- fileContent = other.fileContent->copy();
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/chromium/ChromiumDataObject.h b/WebCore/platform/chromium/ChromiumDataObject.h
index af0a3fa..4aac5c9 100644
--- a/WebCore/platform/chromium/ChromiumDataObject.h
+++ b/WebCore/platform/chromium/ChromiumDataObject.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Google 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
@@ -31,85 +31,58 @@
#ifndef ChromiumDataObject_h
#define ChromiumDataObject_h
-#include "KURL.h"
-#include "PlatformString.h"
-#include "SharedBuffer.h"
+#include "ChromiumDataObjectLegacy.h"
+#include "ReadableDataObject.h"
+#include "WritableDataObject.h"
#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
namespace WebCore {
- // A data object for holding data that would be in a clipboard or moved
- // during a drag-n-drop operation. This is the data that WebCore is aware
- // of and is not specific to a platform.
- class ChromiumDataObject : public RefCounted<ChromiumDataObject> {
- public:
- static PassRefPtr<ChromiumDataObject> create()
- {
- return adoptRef(new ChromiumDataObject);
- }
-
- PassRefPtr<ChromiumDataObject> copy() const
- {
- return adoptRef(new ChromiumDataObject(*this));
- }
-
- void clear();
- void clearAllExceptFiles();
- bool hasData() const;
-
- void clearURL()
- {
- url = KURL();
- uriList.clear();
- urlTitle = "";
- }
-
- bool hasValidURL() const
- {
- return url.isValid();
- }
-
- KURL getURL() const
- {
- return url;
- }
-
- void setURL(const KURL& newURL)
- {
- url = newURL;
- uriList.clear();
- if (newURL.isEmpty())
- return;
- uriList.append(newURL.string());
- }
-
- String urlTitle;
-
- String downloadMetadata;
-
- String fileExtension;
- Vector<String> filenames;
-
- String plainText;
-
- String textHtml;
- KURL htmlBaseUrl;
-
- String fileContentFilename;
- RefPtr<SharedBuffer> fileContent;
-
- private:
- // URL and uri-list are linked, so they should not be accessed individually.
- KURL url;
- Vector<String> uriList;
-
- ChromiumDataObject() {}
- ChromiumDataObject(const ChromiumDataObject&);
-
- friend class ClipboardChromium;
- };
-
-} // namespace WebCore
+class ChromiumDataObject : public RefCounted<ChromiumDataObject> {
+public:
+ static PassRefPtr<ChromiumDataObject> create(PassRefPtr<ChromiumDataObjectLegacy> data);
+ static PassRefPtr<ChromiumDataObject> createReadable(Clipboard::ClipboardType);
+ static PassRefPtr<ChromiumDataObject> createWritable(Clipboard::ClipboardType);
+
+ void clearData(const String& type);
+ void clearAll();
+ void clearAllExceptFiles();
+
+ bool hasData() const;
+
+ HashSet<String> types() const;
+ String getData(const String& type, bool& success);
+ bool setData(const String& type, const String& data);
+
+ // Special handlers for URL/HTML metadata.
+ String urlTitle() const;
+ void setUrlTitle(const String& urlTitle);
+ KURL htmlBaseUrl() const;
+ void setHtmlBaseUrl(const KURL& url);
+
+ // Used to handle files being dragged in.
+ bool containsFilenames() const;
+ Vector<String> filenames() const;
+ void setFilenames(const Vector<String>& filenames);
+
+ // Used to handle files (images) being dragged out.
+ String fileExtension() const;
+ void setFileExtension(const String& fileExtension);
+ String fileContentFilename() const;
+ void setFileContentFilename(const String& fileContentFilename);
+ PassRefPtr<SharedBuffer> fileContent() const;
+ void setFileContent(PassRefPtr<SharedBuffer> fileContent);
+
+private:
+ ChromiumDataObject(PassRefPtr<ChromiumDataObjectLegacy>);
+ ChromiumDataObject(PassRefPtr<ReadableDataObject>);
+ ChromiumDataObject(PassRefPtr<WritableDataObject>);
+
+ RefPtr<ChromiumDataObjectLegacy> m_legacyData;
+ RefPtr<ReadableDataObject> m_readableData;
+ RefPtr<WritableDataObject> m_writableData;
+};
+
+}
#endif
diff --git a/WebCore/platform/chromium/ChromiumDataObjectLegacy.cpp b/WebCore/platform/chromium/ChromiumDataObjectLegacy.cpp
new file mode 100644
index 0000000..a2952c0
--- /dev/null
+++ b/WebCore/platform/chromium/ChromiumDataObjectLegacy.cpp
@@ -0,0 +1,249 @@
+/*
+ * 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 "ChromiumDataObjectLegacy.h"
+
+#include "ChromiumBridge.h"
+#include "ClipboardMimeTypes.h"
+#include "Pasteboard.h"
+
+namespace WebCore {
+
+// Per RFC 2483, the line separator for "text/..." MIME types is CR-LF.
+static char const* const textMIMETypeLineSeparator = "\r\n";
+
+void ChromiumDataObjectLegacy::clearData(const String& type)
+{
+ if (type == mimeTypeTextPlain) {
+ m_plainText = "";
+ return;
+ }
+
+ if (type == mimeTypeURL || type == mimeTypeTextURIList) {
+ m_uriList = "";
+ m_url = KURL();
+ m_urlTitle = "";
+ return;
+ }
+
+ if (type == mimeTypeTextHTML) {
+ m_textHtml = "";
+ m_htmlBaseUrl = KURL();
+ return;
+ }
+
+ if (type == mimeTypeDownloadURL) {
+ m_downloadMetadata = "";
+ return;
+ }
+}
+
+void ChromiumDataObjectLegacy::clearAll()
+{
+ clearAllExceptFiles();
+ m_filenames.clear();
+}
+
+void ChromiumDataObjectLegacy::clearAllExceptFiles()
+{
+ m_urlTitle = "";
+ m_url = KURL();
+ m_uriList = "";
+ m_downloadMetadata = "";
+ m_fileExtension = "";
+ m_plainText = "";
+ m_textHtml = "";
+ m_htmlBaseUrl = KURL();
+ m_fileContentFilename = "";
+ if (m_fileContent)
+ m_fileContent->clear();
+}
+
+bool ChromiumDataObjectLegacy::hasData() const
+{
+ return !m_url.isEmpty()
+ || !m_uriList.isEmpty()
+ || !m_downloadMetadata.isEmpty()
+ || !m_fileExtension.isEmpty()
+ || !m_filenames.isEmpty()
+ || !m_plainText.isEmpty()
+ || !m_textHtml.isEmpty()
+ || m_fileContent;
+}
+
+HashSet<String> ChromiumDataObjectLegacy::types() const
+{
+ // This is currently broken for pasteboard events, and always has been.
+ HashSet<String> results;
+
+ if (!m_plainText.isEmpty()) {
+ results.add(mimeTypeText);
+ results.add(mimeTypeTextPlain);
+ }
+
+ if (m_url.isValid())
+ results.add(mimeTypeURL);
+
+ if (!m_uriList.isEmpty())
+ results.add(mimeTypeTextURIList);
+
+ if (!m_textHtml.isEmpty())
+ results.add(mimeTypeTextHTML);
+
+ if (!m_filenames.isEmpty())
+ results.add("Files");
+
+ return results;
+}
+
+String ChromiumDataObjectLegacy::getData(const String& type, bool& success)
+{
+ if (type == mimeTypeTextPlain) {
+ if (m_clipboardType == Clipboard::CopyAndPaste) {
+ PasteboardPrivate::ClipboardBuffer buffer =
+ Pasteboard::generalPasteboard()->isSelectionMode() ?
+ PasteboardPrivate::SelectionBuffer :
+ PasteboardPrivate::StandardBuffer;
+ String text = ChromiumBridge::clipboardReadPlainText(buffer);
+ success = !text.isEmpty();
+ return text;
+ }
+ success = !m_plainText.isEmpty();
+ return m_plainText;
+ }
+
+ if (type == mimeTypeURL) {
+ success = !m_url.isEmpty();
+ return m_url.string();
+ }
+
+ if (type == mimeTypeTextURIList) {
+ success = !m_uriList.isEmpty();
+ return m_uriList;
+ }
+
+ if (type == mimeTypeTextHTML) {
+ if (m_clipboardType == Clipboard::CopyAndPaste) {
+ PasteboardPrivate::ClipboardBuffer buffer =
+ Pasteboard::generalPasteboard()->isSelectionMode() ?
+ PasteboardPrivate::SelectionBuffer :
+ PasteboardPrivate::StandardBuffer;
+ String htmlText;
+ KURL sourceURL;
+ ChromiumBridge::clipboardReadHTML(buffer, &htmlText, &sourceURL);
+ success = !htmlText.isEmpty();
+ return htmlText;
+ }
+ success = !m_textHtml.isEmpty();
+ return m_textHtml;
+ }
+
+ if (type == mimeTypeDownloadURL) {
+ success = !m_downloadMetadata.isEmpty();
+ return m_downloadMetadata;
+ }
+
+ success = false;
+ return String();
+}
+
+bool ChromiumDataObjectLegacy::setData(const String& type, const String& data)
+{
+ if (type == mimeTypeTextPlain) {
+ m_plainText = data;
+ return true;
+ }
+
+ if (type == mimeTypeURL || type == mimeTypeTextURIList) {
+ m_url = KURL();
+ Vector<String> uriList;
+ // Line separator is \r\n per RFC 2483 - however, for compatibility
+ // reasons we also allow just \n here.
+ data.split('\n', uriList);
+ // Process the input and copy the first valid URL into the url member.
+ // In case no URLs can be found, subsequent calls to getData("URL")
+ // will get an empty string. This is in line with the HTML5 spec (see
+ // "The DragEvent and DataTransfer interfaces").
+ for (size_t i = 0; i < uriList.size(); ++i) {
+ String& line = uriList[i];
+ line = line.stripWhiteSpace();
+ if (line.isEmpty())
+ continue;
+ if (line[0] == '#')
+ continue;
+ KURL url = KURL(ParsedURLString, line);
+ if (url.isValid()) {
+ m_url = url;
+ break;
+ }
+ }
+ m_uriList = data;
+ return true;
+ }
+
+ if (type == mimeTypeTextHTML) {
+ m_textHtml = data;
+ m_htmlBaseUrl = KURL();
+ return true;
+ }
+
+ if (type == mimeTypeDownloadURL) {
+ m_downloadMetadata = data;
+ return true;
+ }
+
+ return false;
+}
+
+ChromiumDataObjectLegacy::ChromiumDataObjectLegacy(Clipboard::ClipboardType clipboardType)
+ : m_clipboardType(clipboardType)
+{
+}
+
+ChromiumDataObjectLegacy::ChromiumDataObjectLegacy(const ChromiumDataObjectLegacy& other)
+ : RefCounted<ChromiumDataObjectLegacy>()
+ , m_clipboardType(other.m_clipboardType)
+ , m_urlTitle(other.m_urlTitle)
+ , m_downloadMetadata(other.m_downloadMetadata)
+ , m_fileExtension(other.m_fileExtension)
+ , m_filenames(other.m_filenames)
+ , m_plainText(other.m_plainText)
+ , m_textHtml(other.m_textHtml)
+ , m_htmlBaseUrl(other.m_htmlBaseUrl)
+ , m_fileContentFilename(other.m_fileContentFilename)
+ , m_url(other.m_url)
+ , m_uriList(other.m_uriList)
+{
+ if (other.m_fileContent.get())
+ m_fileContent = other.m_fileContent->copy();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/chromium/ChromiumDataObjectLegacy.h b/WebCore/platform/chromium/ChromiumDataObjectLegacy.h
new file mode 100644
index 0000000..55be7aa
--- /dev/null
+++ b/WebCore/platform/chromium/ChromiumDataObjectLegacy.h
@@ -0,0 +1,119 @@
+/*
+ * 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 ChromiumDataObjectLegacy_h
+#define ChromiumDataObjectLegacy_h
+
+#include "Clipboard.h"
+#include "KURL.h"
+#include "PlatformString.h"
+#include "SharedBuffer.h"
+#include <wtf/HashSet.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+// A data object for holding data that would be in a clipboard or moved
+// during a drag-n-drop operation. This is the data that WebCore is aware
+// of and is not specific to a platform.
+class ChromiumDataObjectLegacy : public RefCounted<ChromiumDataObjectLegacy> {
+public:
+ static PassRefPtr<ChromiumDataObjectLegacy> create(Clipboard::ClipboardType clipboardType)
+ {
+ return adoptRef(new ChromiumDataObjectLegacy(clipboardType));
+ }
+
+ PassRefPtr<ChromiumDataObjectLegacy> copy() const
+ {
+ return adoptRef(new ChromiumDataObjectLegacy(*this));
+ }
+
+ void clearData(const String& type);
+ void clearAll();
+ void clearAllExceptFiles();
+
+ bool hasData() const;
+
+ HashSet<String> types() const;
+ String getData(const String& type, bool& success);
+ bool setData(const String& type, const String& data);
+
+ // Special handlers for URL/HTML metadata.
+ String urlTitle() const { return m_urlTitle; }
+ void setUrlTitle(const String& urlTitle) { m_urlTitle = urlTitle; }
+ KURL htmlBaseUrl() const { return m_htmlBaseUrl; }
+ void setHtmlBaseUrl(const KURL& url) { m_htmlBaseUrl = url; }
+
+ // Used to handle files being dragged in.
+ bool containsFilenames() const { return !m_filenames.isEmpty(); }
+ Vector<String> filenames() const { return m_filenames; }
+ void setFilenames(const Vector<String>& filenames) { m_filenames = filenames; }
+
+ // Used to handle files (images) being dragged out.
+ String fileExtension() const { return m_fileExtension; }
+ void setFileExtension(const String& fileExtension) { m_fileExtension = fileExtension; }
+ String fileContentFilename() const { return m_fileContentFilename; }
+ void setFileContentFilename(const String& fileContentFilename) { m_fileContentFilename = fileContentFilename; }
+ PassRefPtr<SharedBuffer> fileContent() const { return m_fileContent; }
+ void setFileContent(PassRefPtr<SharedBuffer> fileContent) { m_fileContent = fileContent; }
+
+private:
+ ChromiumDataObjectLegacy(Clipboard::ClipboardType);
+ ChromiumDataObjectLegacy(const ChromiumDataObjectLegacy&);
+
+ Clipboard::ClipboardType m_clipboardType;
+
+ String m_urlTitle;
+
+ String m_downloadMetadata;
+
+ String m_fileExtension;
+ Vector<String> m_filenames;
+
+ String m_plainText;
+
+ String m_textHtml;
+ KURL m_htmlBaseUrl;
+
+ String m_fileContentFilename;
+ RefPtr<SharedBuffer> m_fileContent;
+
+ // These two are linked. Setting m_url will set m_uriList to the same
+ // string value; setting m_uriList will cause its contents to be parsed
+ // according to RFC 2483 and the first URL found will be set in m_url.
+ KURL m_url;
+ String m_uriList;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp
index c2ec80c..46b4339 100644
--- a/WebCore/platform/chromium/ClipboardChromium.cpp
+++ b/WebCore/platform/chromium/ClipboardChromium.cpp
@@ -28,8 +28,8 @@
#include "ClipboardChromium.h"
#include "CachedImage.h"
-#include "ChromiumBridge.h"
#include "ChromiumDataObject.h"
+#include "ClipboardMimeTypes.h"
#include "ClipboardUtilitiesChromium.h"
#include "Document.h"
#include "DragData.h"
@@ -37,17 +37,18 @@
#include "FileList.h"
#include "Frame.h"
#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
#include "Image.h"
#include "MIMETypeRegistry.h"
#include "NamedNodeMap.h"
-#include "Pasteboard.h"
-#include "PlatformString.h"
#include "Range.h"
#include "RenderImage.h"
#include "ScriptExecutionContext.h"
-#include "StringBuilder.h"
#include "markup.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+
namespace WebCore {
using namespace HTMLNames;
@@ -55,40 +56,12 @@ using namespace HTMLNames;
// We provide the IE clipboard types (URL and Text), and the clipboard types specified in the WHATWG Web Applications 1.0 draft
// see http://www.whatwg.org/specs/web-apps/current-work/ Section 6.3.5.3
-enum ClipboardDataType {
- ClipboardDataTypeNone,
-
- ClipboardDataTypeURL,
- ClipboardDataTypeURIList,
- ClipboardDataTypeDownloadURL,
- ClipboardDataTypePlainText,
- ClipboardDataTypeHTML,
-
- ClipboardDataTypeOther,
-};
-
-// Per RFC 2483, the line separator for "text/..." MIME types is CR-LF.
-static char const* const textMIMETypeLineSeparator = "\r\n";
-
-static ClipboardDataType clipboardTypeFromMIMEType(const String& type)
+static String normalizeType(const String& type)
{
String cleanType = type.stripWhiteSpace().lower();
- if (cleanType.isEmpty())
- return ClipboardDataTypeNone;
-
- // Includes two special cases for IE compatibility.
- if (cleanType == "text" || cleanType == "text/plain" || cleanType.startsWith("text/plain;"))
- return ClipboardDataTypePlainText;
- if (cleanType == "url")
- return ClipboardDataTypeURL;
- if (cleanType == "text/uri-list")
- return ClipboardDataTypeURIList;
- if (cleanType == "downloadurl")
- return ClipboardDataTypeDownloadURL;
- if (cleanType == "text/html")
- return ClipboardDataTypeHTML;
-
- return ClipboardDataTypeOther;
+ if (cleanType == mimeTypeText || cleanType.startsWith(mimeTypeTextPlainEtc))
+ return mimeTypeTextPlain;
+ return cleanType;
}
PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame)
@@ -112,41 +85,22 @@ PassRefPtr<ClipboardChromium> ClipboardChromium::create(ClipboardType clipboardT
return adoptRef(new ClipboardChromium(clipboardType, dataObject, policy, frame));
}
+PassRefPtr<ClipboardChromium> ClipboardChromium::create(ClipboardType clipboardType,
+ ClipboardAccessPolicy policy, Frame* frame)
+{
+ RefPtr<ChromiumDataObject> dataObject =
+ policy == ClipboardWritable ?
+ ChromiumDataObject::createWritable(clipboardType) :
+ ChromiumDataObject::createReadable(clipboardType);
+ return adoptRef(new ClipboardChromium(clipboardType, dataObject, policy, frame));
+}
+
void ClipboardChromium::clearData(const String& type)
{
if (policy() != ClipboardWritable || !m_dataObject)
return;
- ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
- switch (dataType) {
- case ClipboardDataTypeNone:
- // If called with no arguments, everything except the file list must be cleared.
- // (See HTML5 spec, "The DragEvent and DataTransfer interfaces")
- m_dataObject->clearAllExceptFiles();
- return;
-
- case ClipboardDataTypeURL:
- case ClipboardDataTypeURIList:
- m_dataObject->clearURL();
- return;
-
- case ClipboardDataTypeDownloadURL:
- m_dataObject->downloadMetadata = "";
- return;
-
- case ClipboardDataTypePlainText:
- m_dataObject->plainText = "";
- return;
-
- case ClipboardDataTypeHTML:
- m_dataObject->textHtml = "";
- m_dataObject->htmlBaseUrl = KURL();
- return;
-
- case ClipboardDataTypeOther:
- // Not yet implemented, see https://bugs.webkit.org/show_bug.cgi?id=34410
- return;
- }
+ m_dataObject->clearData(normalizeType(type));
ASSERT_NOT_REACHED();
}
@@ -156,7 +110,7 @@ void ClipboardChromium::clearAllData()
if (policy() != ClipboardWritable)
return;
- m_dataObject->clear();
+ m_dataObject->clearAll();
}
String ClipboardChromium::getData(const String& type, bool& success) const
@@ -165,80 +119,7 @@ String ClipboardChromium::getData(const String& type, bool& success) const
if (policy() != ClipboardReadable || !m_dataObject)
return String();
- ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
- switch (dataType) {
- case ClipboardDataTypeNone:
- return String();
-
- // Hack for URLs. file URLs are used internally for drop's default action, but we don't want
- // to expose them to the page, so we filter them out here.
- case ClipboardDataTypeURIList:
- {
- String text;
- for (size_t i = 0; i < m_dataObject->uriList.size(); ++i) {
- const String& uri = m_dataObject->uriList[i];
- if (protocolIs(uri, "file"))
- continue;
- ASSERT(!uri.isEmpty());
- if (!text.isEmpty())
- text.append(textMIMETypeLineSeparator);
- // URIs have already been canonicalized, so copy everything verbatim.
- text.append(uri);
- }
- success = !text.isEmpty();
- return text;
- }
-
- case ClipboardDataTypeURL:
- // In case of a previous setData('text/uri-list'), setData() has already
- // prepared the 'url' member, so we can just retrieve it here.
- if (!m_dataObject->url.isEmpty() && !m_dataObject->url.isLocalFile()) {
- success = true;
- return m_dataObject->url.string();
- }
- return String();
-
- case ClipboardDataTypeDownloadURL:
- success = !m_dataObject->downloadMetadata.isEmpty();
- return m_dataObject->downloadMetadata;
-
- case ClipboardDataTypePlainText:
- if (isForCopyAndPaste()) {
- PasteboardPrivate::ClipboardBuffer buffer =
- Pasteboard::generalPasteboard()->isSelectionMode() ?
- PasteboardPrivate::SelectionBuffer :
- PasteboardPrivate::StandardBuffer;
- String text = ChromiumBridge::clipboardReadPlainText(buffer);
- success = !text.isEmpty();
- return text;
- }
- // Otherwise return whatever is stored in plainText.
- success = !m_dataObject->plainText.isEmpty();
- return m_dataObject->plainText;
-
- case ClipboardDataTypeHTML:
- if (isForCopyAndPaste()) {
- PasteboardPrivate::ClipboardBuffer buffer =
- Pasteboard::generalPasteboard()->isSelectionMode() ?
- PasteboardPrivate::SelectionBuffer :
- PasteboardPrivate::StandardBuffer;
- String htmlText;
- KURL sourceURL;
- ChromiumBridge::clipboardReadHTML(buffer, &htmlText, &sourceURL);
- success = !htmlText.isEmpty();
- return htmlText;
- }
- // Otherwise return whatever is stored in textHtml.
- success = !m_dataObject->textHtml.isEmpty();
- return m_dataObject->textHtml;
-
- case ClipboardDataTypeOther:
- // not yet implemented, see https://bugs.webkit.org/show_bug.cgi?id=34410
- return String();
- }
-
- ASSERT_NOT_REACHED();
- return String();
+ return m_dataObject->getData(normalizeType(type), success);
}
bool ClipboardChromium::setData(const String& type, const String& data)
@@ -246,69 +127,7 @@ bool ClipboardChromium::setData(const String& type, const String& data)
if (policy() != ClipboardWritable)
return false;
- ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
- switch (dataType) {
- case ClipboardDataTypeNone:
- return false;
-
- case ClipboardDataTypeURL:
- // For setData(), "URL" must be treated as "text/uri-list".
- // (See HTML5 spec, "The DragEvent and DataTransfer interfaces")
- case ClipboardDataTypeURIList:
- m_dataObject->url = KURL();
- // Line separator is \r\n per RFC 2483 - however, for compatibility reasons
- // we also allow just \n here.
- data.split('\n', m_dataObject->uriList);
- // Strip white space on all lines, including trailing \r from above split.
- // If this leaves a line empty, remove it completely.
- //
- // Also, copy the first valid URL into the 'url' member as well.
- // In case no entry is a valid URL (i.e., remarks only), then we leave 'url' empty.
- // I.e., in that case subsequent calls to getData("URL") will get an empty string.
- // This is in line with the HTML5 spec (see "The DragEvent and DataTransfer interfaces").
- for (size_t i = 0; i < m_dataObject->uriList.size(); /**/) {
- String& line = m_dataObject->uriList[i];
- line = line.stripWhiteSpace();
- if (line.isEmpty()) {
- m_dataObject->uriList.remove(i);
- continue;
- }
- ++i;
- // Only copy the first valid URL.
- if (m_dataObject->url.isValid())
- continue;
- // Skip remarks.
- if (line[0] == '#')
- continue;
- KURL url = KURL(ParsedURLString, line);
- if (url.isValid())
- m_dataObject->url = url;
- }
- if (m_dataObject->uriList.isEmpty()) {
- ASSERT(m_dataObject->url.isEmpty());
- return data.isEmpty();
- }
- return true;
-
- case ClipboardDataTypeDownloadURL:
- m_dataObject->downloadMetadata = data;
- return true;
-
- case ClipboardDataTypePlainText:
- m_dataObject->plainText = data;
- return true;
-
- case ClipboardDataTypeHTML:
- m_dataObject->textHtml = data;
- return true;
-
- case ClipboardDataTypeOther:
- // Not yet implemented, see https://bugs.webkit.org/show_bug.cgi?id=34410
- return false;
- }
-
- ASSERT_NOT_REACHED();
- return false;
+ return m_dataObject->setData(normalizeType(type), data);
}
// extensions beyond IE's API
@@ -321,33 +140,7 @@ HashSet<String> ClipboardChromium::types() const
if (!m_dataObject)
return results;
- if (!m_dataObject->filenames.isEmpty())
- results.add("Files");
-
- // Hack for URLs. file URLs are used internally for drop's default action, but we don't want
- // to expose them to the page, so we filter them out here.
- if (m_dataObject->url.isValid() && !m_dataObject->url.isLocalFile()) {
- ASSERT(!m_dataObject->uriList.isEmpty());
- results.add("URL");
- }
-
- if (!m_dataObject->uriList.isEmpty()) {
- // Verify that the URI list contains at least one non-file URL.
- for (Vector<String>::const_iterator it = m_dataObject->uriList.begin();
- it != m_dataObject->uriList.end(); ++it) {
- if (!protocolIs(*it, "file")) {
- // Note that even if the URI list is not empty, it may not actually
- // contain a valid URL, so we can't return "URL" here.
- results.add("text/uri-list");
- break;
- }
- }
- }
-
- if (!m_dataObject->plainText.isEmpty()) {
- results.add("Text");
- results.add("text/plain");
- }
+ results = m_dataObject->types();
return results;
}
@@ -357,12 +150,13 @@ PassRefPtr<FileList> ClipboardChromium::files() const
if (policy() != ClipboardReadable)
return FileList::create();
- if (!m_dataObject || m_dataObject->filenames.isEmpty())
+ if (!m_dataObject)
return FileList::create();
+ const Vector<String>& filenames = m_dataObject->filenames();
RefPtr<FileList> fileList = FileList::create();
- for (size_t i = 0; i < m_dataObject->filenames.size(); ++i)
- fileList->append(File::create(m_dataObject->filenames.at(i)));
+ for (size_t i = 0; i < filenames.size(); ++i)
+ fileList->append(File::create(filenames.at(i)));
return fileList.release();
}
@@ -412,7 +206,7 @@ static String imageToMarkup(const String& url, Element* element)
StringBuilder markup;
markup.append("<img src=\"");
markup.append(url);
- markup.append("\"");
+ markup.append('"');
// Copy over attributes. If we are dragging an image, we expect things like
// the id to be copied as well.
NamedNodeMap* attrs = element->attributes();
@@ -421,13 +215,13 @@ static String imageToMarkup(const String& url, Element* element)
Attribute* attr = attrs->attributeItem(i);
if (attr->localName() == "src")
continue;
- markup.append(" ");
+ markup.append(' ');
markup.append(attr->localName());
markup.append("=\"");
String escapedAttr = attr->value();
escapedAttr.replace("\"", "&quot;");
markup.append(escapedAttr);
- markup.append("\"");
+ markup.append('"');
}
markup.append("/>");
@@ -461,7 +255,7 @@ static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* elem
if (!imageBuffer || !imageBuffer->size())
return;
- dataObject->fileContent = imageBuffer;
+ dataObject->setFileContent(imageBuffer);
// Determine the filename for the file contents of the image. We try to
// use the alt tag if one exists, otherwise we fall back on the suggested
@@ -469,13 +263,13 @@ static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* elem
// in the URL.
String extension = MIMETypeRegistry::getPreferredExtensionForMIMEType(
cachedImage->response().mimeType());
- dataObject->fileExtension = extension.isEmpty() ? "" : "." + extension;
+ dataObject->setFileExtension(extension.isEmpty() ? "" : "." + extension);
String title = element->getAttribute(altAttr);
if (title.isEmpty())
title = cachedImage->response().suggestedFilename();
title = ClipboardChromium::validateFileName(title, dataObject);
- dataObject->fileContentFilename = title + dataObject->fileExtension;
+ dataObject->setFileContentFilename(title + dataObject->fileExtension());
}
void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
@@ -483,8 +277,8 @@ void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& u
if (!m_dataObject)
return;
- m_dataObject->url = url;
- m_dataObject->urlTitle = title;
+ m_dataObject->setData(mimeTypeURL, url);
+ m_dataObject->setUrlTitle(title);
// Write the bytes in the image to the file format.
writeImageToDataObject(m_dataObject.get(), element, url);
@@ -493,12 +287,12 @@ void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& u
if (imageURL.isEmpty())
return;
- String fullURL = frame->document()->completeURL(deprecatedParseURL(imageURL));
+ String fullURL = frame->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(imageURL));
if (fullURL.isEmpty())
return;
// Put img tag on the clipboard referencing the image
- m_dataObject->textHtml = imageToMarkup(fullURL, element);
+ m_dataObject->setData(mimeTypeTextHTML, imageToMarkup(fullURL, element));
}
void ClipboardChromium::writeURL(const KURL& url, const String& title, Frame*)
@@ -506,17 +300,15 @@ void ClipboardChromium::writeURL(const KURL& url, const String& title, Frame*)
if (!m_dataObject)
return;
ASSERT(!url.isEmpty());
- m_dataObject->url = url;
- m_dataObject->urlTitle = title;
- m_dataObject->uriList.clear();
- m_dataObject->uriList.append(url);
+ m_dataObject->setData(mimeTypeURL, url);
+ m_dataObject->setUrlTitle(title);
// The URL can also be used as plain text.
- m_dataObject->plainText = url.string();
+ m_dataObject->setData(mimeTypeTextPlain, url.string());
// The URL can also be used as an HTML fragment.
- m_dataObject->textHtml = urlToMarkup(url, title);
- m_dataObject->htmlBaseUrl = url;
+ m_dataObject->setData(mimeTypeTextHTML, urlToMarkup(url, title));
+ m_dataObject->setHtmlBaseUrl(url);
}
void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame)
@@ -525,15 +317,15 @@ void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame)
if (!m_dataObject)
return;
- m_dataObject->textHtml = createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs);
- m_dataObject->htmlBaseUrl = frame->document()->url();
+ m_dataObject->setData(mimeTypeTextHTML, createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs));
+ m_dataObject->setHtmlBaseUrl(frame->document()->url());
String str = frame->editor()->selectedText();
#if OS(WINDOWS)
replaceNewlinesWithWindowsStyleNewlines(str);
#endif
replaceNBSPWithSpace(str);
- m_dataObject->plainText = str;
+ m_dataObject->setData(mimeTypeTextPlain, str);
}
void ClipboardChromium::writePlainText(const String& text)
@@ -546,7 +338,7 @@ void ClipboardChromium::writePlainText(const String& text)
replaceNewlinesWithWindowsStyleNewlines(str);
#endif
replaceNBSPWithSpace(str);
- m_dataObject->plainText = str;
+ m_dataObject->setData(mimeTypeTextPlain, str);
}
bool ClipboardChromium::hasData()
diff --git a/WebCore/platform/chromium/ClipboardChromium.h b/WebCore/platform/chromium/ClipboardChromium.h
index 14f59e9..1d69921 100644
--- a/WebCore/platform/chromium/ClipboardChromium.h
+++ b/WebCore/platform/chromium/ClipboardChromium.h
@@ -48,6 +48,9 @@ namespace WebCore {
static PassRefPtr<ClipboardChromium> create(
ClipboardType, PassRefPtr<ChromiumDataObject>, ClipboardAccessPolicy, Frame*);
+ static PassRefPtr<ClipboardChromium> create(
+ ClipboardType, ClipboardAccessPolicy, Frame*);
+
// Returns the file name (not including the extension). This removes any
// invalid file system characters as well as making sure the
// path + extension is not bigger than allowed by the file system.
diff --git a/WebCore/platform/chromium/ClipboardChromiumWin.cpp b/WebCore/platform/chromium/ClipboardChromiumWin.cpp
index b4a2c21..d9bbeb5 100644
--- a/WebCore/platform/chromium/ClipboardChromiumWin.cpp
+++ b/WebCore/platform/chromium/ClipboardChromiumWin.cpp
@@ -44,11 +44,11 @@ String ClipboardChromium::validateFileName(const String& title, ChromiumDataObje
{
// Remove any invalid file system characters.
String result = title.removeCharacters(&isInvalidFileCharacter);
- if (result.length() + dataObject->fileExtension.length() + 1 >= MAX_PATH) {
- if (dataObject->fileExtension.length() + 1 >= MAX_PATH)
- dataObject->fileExtension = "";
- if (result.length() + dataObject->fileExtension.length() + 1 >= MAX_PATH)
- result = result.substring(0, MAX_PATH - dataObject->fileExtension.length() - 1);
+ if (result.length() + dataObject->fileExtension().length() + 1 >= MAX_PATH) {
+ if (dataObject->fileExtension().length() + 1 >= MAX_PATH)
+ dataObject->setFileExtension("");
+ if (result.length() + dataObject->fileExtension().length() + 1 >= MAX_PATH)
+ result = result.substring(0, MAX_PATH - dataObject->fileExtension().length() - 1);
}
return result;
}
diff --git a/WebCore/platform/chromium/ClipboardMimeTypes.cpp b/WebCore/platform/chromium/ClipboardMimeTypes.cpp
index b95744f8..f689e0e 100644
--- a/WebCore/platform/chromium/ClipboardMimeTypes.cpp
+++ b/WebCore/platform/chromium/ClipboardMimeTypes.cpp
@@ -33,8 +33,12 @@
namespace WebCore {
-const char textPlainType[] = "text/plain";
-const char textHtmlType[] = "text/html";
-const char textUriListType[] = "text/uri-list";
+const char mimeTypeText[] = "text";
+const char mimeTypeTextPlain[] = "text/plain";
+const char mimeTypeTextPlainEtc[] = "text/plain;";
+const char mimeTypeTextHTML[] = "text/html";
+const char mimeTypeURL[] = "url";
+const char mimeTypeTextURIList[] = "text/uri-list";
+const char mimeTypeDownloadURL[] = "downloadurl";
} // namespace WebCore
diff --git a/WebCore/platform/chromium/ClipboardMimeTypes.h b/WebCore/platform/chromium/ClipboardMimeTypes.h
index d7468f2..9bdccfe 100644
--- a/WebCore/platform/chromium/ClipboardMimeTypes.h
+++ b/WebCore/platform/chromium/ClipboardMimeTypes.h
@@ -33,9 +33,13 @@
namespace WebCore {
-extern const char textPlainType[];
-extern const char textHtmlType[];
-extern const char textUriListType[];
+extern const char mimeTypeText[];
+extern const char mimeTypeTextPlain[];
+extern const char mimeTypeTextPlainEtc[];
+extern const char mimeTypeTextHTML[];
+extern const char mimeTypeURL[];
+extern const char mimeTypeTextURIList[];
+extern const char mimeTypeDownloadURL[];
} // namespace WebCore
diff --git a/WebCore/platform/chromium/DragDataChromium.cpp b/WebCore/platform/chromium/DragDataChromium.cpp
index 674d34d..2b04523 100644
--- a/WebCore/platform/chromium/DragDataChromium.cpp
+++ b/WebCore/platform/chromium/DragDataChromium.cpp
@@ -32,6 +32,7 @@
#include "ChromiumBridge.h"
#include "ChromiumDataObject.h"
+#include "ClipboardMimeTypes.h"
#include "DocumentFragment.h"
#include "FileSystem.h"
#include "KURL.h"
@@ -43,50 +44,50 @@ namespace WebCore {
static bool containsHTML(const ChromiumDataObject* dropData)
{
- return dropData->textHtml.length() > 0;
+ return dropData->types().contains(mimeTypeTextHTML);
}
bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const
{
- return !asURL(filenamePolicy).isEmpty();
+ return m_platformDragData->types().contains(mimeTypeURL)
+ || (filenamePolicy == ConvertFilenames && m_platformDragData->containsFilenames());
}
String DragData::asURL(FilenameConversionPolicy filenamePolicy, String* title) const
{
String url;
- if (m_platformDragData->hasValidURL())
- url = m_platformDragData->getURL().string();
- else if (filenamePolicy == ConvertFilenames && !m_platformDragData->filenames.isEmpty()) {
- String fileName = m_platformDragData->filenames[0];
- fileName = ChromiumBridge::getAbsolutePath(fileName);
- url = ChromiumBridge::filePathToURL(fileName).string();
+ if (m_platformDragData->types().contains(mimeTypeURL)) {
+ bool ignoredSuccess;
+ url = m_platformDragData->getData(mimeTypeURL, ignoredSuccess);
+ if (title)
+ *title = m_platformDragData->urlTitle();
+ } else if (filenamePolicy == ConvertFilenames && containsFiles()) {
+ url = ChromiumBridge::filePathToURL(ChromiumBridge::getAbsolutePath(m_platformDragData->filenames()[0]));
}
-
- // |title| can be NULL
- if (title)
- *title = m_platformDragData->urlTitle;
return url;
}
bool DragData::containsFiles() const
{
- return !m_platformDragData->filenames.isEmpty();
+ return m_platformDragData->containsFilenames();
}
void DragData::asFilenames(Vector<String>& result) const
{
- for (size_t i = 0; i < m_platformDragData->filenames.size(); ++i)
- result.append(m_platformDragData->filenames[i]);
+ const Vector<String>& filenames = m_platformDragData->filenames();
+ for (size_t i = 0; i < filenames.size(); ++i)
+ result.append(filenames[i]);
}
bool DragData::containsPlainText() const
{
- return !m_platformDragData->plainText.isEmpty();
+ return m_platformDragData->types().contains(mimeTypeTextPlain);
}
String DragData::asPlainText() const
{
- return m_platformDragData->plainText;
+ bool ignoredSuccess;
+ return m_platformDragData->getData(mimeTypeTextPlain, ignoredSuccess);
}
bool DragData::containsColor() const
@@ -101,8 +102,8 @@ bool DragData::canSmartReplace() const
// This is allowed whenever the drag data contains a 'range' (ie.,
// ClipboardWin::writeRange is called). For example, dragging a link
// should not result in a space being added.
- return !m_platformDragData->plainText.isEmpty()
- && !m_platformDragData->hasValidURL();
+ return m_platformDragData->types().contains(mimeTypeTextPlain)
+ && !m_platformDragData->types().contains(mimeTypeURL);
}
bool DragData::containsCompatibleContent() const
@@ -134,9 +135,10 @@ PassRefPtr<DocumentFragment> DragData::asFragment(Document* doc) const
// return fragment;
}
- if (!m_platformDragData->textHtml.isEmpty()) {
+ if (m_platformDragData->types().contains(mimeTypeTextHTML)) {
+ bool ignoredSuccess;
RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(doc,
- m_platformDragData->textHtml, m_platformDragData->htmlBaseUrl, FragmentScriptingNotAllowed);
+ m_platformDragData->getData(mimeTypeTextHTML, ignoredSuccess), m_platformDragData->htmlBaseUrl(), FragmentScriptingNotAllowed);
return fragment.release();
}
diff --git a/WebCore/platform/chromium/GeolocationServiceChromium.cpp b/WebCore/platform/chromium/GeolocationServiceChromium.cpp
index b64f5eb..c5e73ae 100644
--- a/WebCore/platform/chromium/GeolocationServiceChromium.cpp
+++ b/WebCore/platform/chromium/GeolocationServiceChromium.cpp
@@ -33,6 +33,10 @@
#include "ChromiumBridge.h"
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+#error "This file should not be compiled when ENABLE(CLIENT_BASED_GEOLOCATION)"
+#endif // ENABLE(CLIENT_BASED_GEOLOCATION)
+
namespace WebCore {
GeolocationServiceBridge::~GeolocationServiceBridge()
diff --git a/WebCore/platform/chromium/Language.cpp b/WebCore/platform/chromium/LanguageChromium.cpp
index 2612af4..69fe372 100644
--- a/WebCore/platform/chromium/Language.cpp
+++ b/WebCore/platform/chromium/LanguageChromium.cpp
@@ -36,7 +36,7 @@
namespace WebCore {
-String defaultLanguage()
+String platformDefaultLanguage()
{
static String computedDefaultLanguage;
if (computedDefaultLanguage.isEmpty())
diff --git a/WebCore/platform/chromium/PasteboardChromium.cpp b/WebCore/platform/chromium/PasteboardChromium.cpp
index ba69b00..907a4b9 100644
--- a/WebCore/platform/chromium/PasteboardChromium.cpp
+++ b/WebCore/platform/chromium/PasteboardChromium.cpp
@@ -38,6 +38,7 @@
#include "Element.h"
#include "Frame.h"
#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
#include "Image.h"
#include "KURL.h"
#include "markup.h"
@@ -147,7 +148,7 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String& title)
Element* element = static_cast<Element*>(node);
urlString = element->getAttribute(element->imageSourceAttributeName());
}
- KURL url = urlString.isEmpty() ? KURL() : node->document()->completeURL(deprecatedParseURL(urlString));
+ KURL url = urlString.isEmpty() ? KURL() : node->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
ChromiumBridge::clipboardWriteImage(bitmap, url, title);
}
diff --git a/WebCore/platform/chromium/PopupMenuChromium.cpp b/WebCore/platform/chromium/PopupMenuChromium.cpp
index 9c73a9c..3c807ba 100644
--- a/WebCore/platform/chromium/PopupMenuChromium.cpp
+++ b/WebCore/platform/chromium/PopupMenuChromium.cpp
@@ -513,7 +513,7 @@ void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect)
Color borderColor(127, 157, 185);
gc->setStrokeStyle(NoStroke);
- gc->setFillColor(borderColor, DeviceColorSpace);
+ gc->setFillColor(borderColor, ColorSpaceDeviceRGB);
int tx = x();
int ty = y();
@@ -857,7 +857,7 @@ void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect)
// Special case for an empty popup.
if (numItems() == 0)
- gc->fillRect(r, Color::white, DeviceColorSpace);
+ gc->fillRect(r, Color::white, ColorSpaceDeviceRGB);
gc->restore();
@@ -894,23 +894,23 @@ void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowInd
// If we have a transparent background, make sure it has a color to blend
// against.
if (backColor.hasAlpha())
- gc->fillRect(rowRect, Color::white, DeviceColorSpace);
+ gc->fillRect(rowRect, Color::white, ColorSpaceDeviceRGB);
- gc->fillRect(rowRect, backColor, DeviceColorSpace);
+ gc->fillRect(rowRect, backColor, ColorSpaceDeviceRGB);
if (m_popupClient->itemIsSeparator(rowIndex)) {
IntRect separatorRect(
rowRect.x() + separatorPadding,
rowRect.y() + (rowRect.height() - separatorHeight) / 2,
rowRect.width() - 2 * separatorPadding, separatorHeight);
- gc->fillRect(separatorRect, textColor, DeviceColorSpace);
+ gc->fillRect(separatorRect, textColor, ColorSpaceDeviceRGB);
return;
}
if (!style.isVisible())
return;
- gc->setFillColor(textColor, DeviceColorSpace);
+ gc->setFillColor(textColor, ColorSpaceDeviceRGB);
Font itemFont = getRowFont(rowIndex);
// FIXME: http://crbug.com/19872 We should get the padding of individual option
@@ -973,7 +973,7 @@ void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowInd
remainingWidth -= (imageRect.width() + kLabelToIconPadding);
imageRect.setX(rowRect.width() - rightPadding - imageRect.width());
imageRect.setY(rowRect.y() + (rowRect.height() - imageRect.height()) / 2);
- gc->drawImage(image.get(), DeviceColorSpace, imageRect);
+ gc->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect);
}
// Draw the the label if applicable.
@@ -985,7 +985,7 @@ void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowInd
else
textX = remainingWidth - itemFont.width(labelTextRun);
- gc->setFillColor(labelColor, DeviceColorSpace);
+ gc->setFillColor(labelColor, ColorSpaceDeviceRGB);
gc->drawBidiText(itemFont, labelTextRun, IntPoint(textX, textY));
}
diff --git a/WebCore/platform/chromium/ReadableDataObject.cpp b/WebCore/platform/chromium/ReadableDataObject.cpp
index 1a333bb..97c481b 100644
--- a/WebCore/platform/chromium/ReadableDataObject.cpp
+++ b/WebCore/platform/chromium/ReadableDataObject.cpp
@@ -33,21 +33,23 @@
#include "ChromiumBridge.h"
#include "ClipboardMimeTypes.h"
+#include "Pasteboard.h"
+#include "PasteboardPrivate.h"
namespace WebCore {
-static PasteboardPrivate::ClipboardBuffer clipboardBuffer(bool isForDragging)
+static PasteboardPrivate::ClipboardBuffer clipboardBuffer(Clipboard::ClipboardType clipboardType)
{
- return isForDragging ? PasteboardPrivate::DragBuffer : PasteboardPrivate::StandardBuffer;
+ return clipboardType == Clipboard::DragAndDrop ? PasteboardPrivate::DragBuffer : PasteboardPrivate::StandardBuffer;
}
-PassRefPtr<ReadableDataObject> ReadableDataObject::create(bool isForDragging)
+PassRefPtr<ReadableDataObject> ReadableDataObject::create(Clipboard::ClipboardType clipboardType)
{
- return adoptRef(new ReadableDataObject(isForDragging));
+ return adoptRef(new ReadableDataObject(clipboardType));
}
-ReadableDataObject::ReadableDataObject(bool isForDragging)
- : m_isForDragging(isForDragging)
+ReadableDataObject::ReadableDataObject(Clipboard::ClipboardType clipboardType)
+ : m_clipboardType(clipboardType)
, m_containsFilenames(false)
, m_isTypeCacheInitialized(false)
{
@@ -69,34 +71,51 @@ String ReadableDataObject::getData(const String& type, bool& succeeded) const
{
String data;
String ignoredMetadata;
+ // Since the Chromium-side bridge isn't complete yet, we special case this
+ // for copy-and-paste, since that code path no longer uses
+ // ChromiumDataObjectLegacy.
+ if (m_clipboardType == Clipboard::CopyAndPaste) {
+ if (type == mimeTypeTextPlain) {
+ PasteboardPrivate::ClipboardBuffer buffer =
+ Pasteboard::generalPasteboard()->isSelectionMode() ?
+ PasteboardPrivate::SelectionBuffer :
+ PasteboardPrivate::StandardBuffer;
+ data = ChromiumBridge::clipboardReadPlainText(buffer);
+ } else if (type == mimeTypeTextHTML) {
+ PasteboardPrivate::ClipboardBuffer buffer =
+ Pasteboard::generalPasteboard()->isSelectionMode() ?
+ PasteboardPrivate::SelectionBuffer :
+ PasteboardPrivate::StandardBuffer;
+ KURL ignoredSourceURL;
+ ChromiumBridge::clipboardReadHTML(buffer, &data, &ignoredSourceURL);
+ }
+ succeeded = !data.isEmpty();
+ return data;
+ }
succeeded = ChromiumBridge::clipboardReadData(
- clipboardBuffer(m_isForDragging), type, data, ignoredMetadata);
+ clipboardBuffer(m_clipboardType), type, data, ignoredMetadata);
return data;
}
-String ReadableDataObject::getURL(String* title) const
+String ReadableDataObject::urlTitle() const
{
- String url;
- String ignoredTitle;
- if (!title)
- title = &ignoredTitle;
+ String ignoredData;
+ String urlTitle;
ChromiumBridge::clipboardReadData(
- clipboardBuffer(m_isForDragging), textUriListType, url, *title);
- return url;
+ clipboardBuffer(m_clipboardType), mimeTypeTextURIList, ignoredData, urlTitle);
+ return urlTitle;
}
-String ReadableDataObject::getHTML(String* baseURL) const
+KURL ReadableDataObject::htmlBaseUrl() const
{
- String html;
- String ignoredBaseURL;
- if (!baseURL)
- baseURL = &ignoredBaseURL;
+ String ignoredData;
+ String htmlBaseUrl;
ChromiumBridge::clipboardReadData(
- clipboardBuffer(m_isForDragging), textHtmlType, html, *baseURL);
- return html;
+ clipboardBuffer(m_clipboardType), mimeTypeTextHTML, ignoredData, htmlBaseUrl);
+ return KURL(ParsedURLString, htmlBaseUrl);
}
-bool ReadableDataObject::hasFilenames() const
+bool ReadableDataObject::containsFilenames() const
{
ensureTypeCacheInitialized();
return m_containsFilenames;
@@ -104,7 +123,7 @@ bool ReadableDataObject::hasFilenames() const
Vector<String> ReadableDataObject::filenames() const
{
- return ChromiumBridge::clipboardReadFilenames(clipboardBuffer(m_isForDragging));
+ return ChromiumBridge::clipboardReadFilenames(clipboardBuffer(m_clipboardType));
}
void ReadableDataObject::ensureTypeCacheInitialized() const
@@ -113,7 +132,7 @@ void ReadableDataObject::ensureTypeCacheInitialized() const
return;
m_types = ChromiumBridge::clipboardReadAvailableTypes(
- clipboardBuffer(m_isForDragging), &m_containsFilenames);
+ clipboardBuffer(m_clipboardType), &m_containsFilenames);
m_isTypeCacheInitialized = true;
}
diff --git a/WebCore/platform/chromium/ReadableDataObject.h b/WebCore/platform/chromium/ReadableDataObject.h
index 60f6d45..027e0ed 100644
--- a/WebCore/platform/chromium/ReadableDataObject.h
+++ b/WebCore/platform/chromium/ReadableDataObject.h
@@ -31,6 +31,7 @@
#ifndef ReadableDataObject_h
#define ReadableDataObject_h
+#include "Clipboard.h"
#include "PlatformString.h"
#include <wtf/HashSet.h>
#include <wtf/RefCounted.h>
@@ -43,26 +44,25 @@ namespace WebCore {
// browser to the renderer.
class ReadableDataObject : public RefCounted<ReadableDataObject> {
public:
- static PassRefPtr<ReadableDataObject> create(bool isForDragging);
+ static PassRefPtr<ReadableDataObject> create(Clipboard::ClipboardType);
- virtual bool hasData() const;
- virtual HashSet<String> types() const;
- virtual String getData(const String& type, bool& succeeded) const;
+ bool hasData() const;
+ HashSet<String> types() const;
+ String getData(const String& type, bool& succeeded) const;
- virtual String getURL(String* title) const;
- virtual String getHTML(String* baseURL) const;
+ String urlTitle() const;
+ KURL htmlBaseUrl() const;
- virtual bool hasFilenames() const;
- virtual Vector<String> filenames() const;
+ bool containsFilenames() const;
+ Vector<String> filenames() const;
private:
- explicit ReadableDataObject(bool isForDragging);
+ explicit ReadableDataObject(Clipboard::ClipboardType);
// This isn't always const... but most of the time it is.
void ensureTypeCacheInitialized() const;
-
- bool m_isForDragging;
+ Clipboard::ClipboardType m_clipboardType;
// To avoid making a lot of IPC calls for each drag event, we cache some
// values in the renderer.
diff --git a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp
index cf3ca6f..234d0ee 100644
--- a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp
+++ b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp
@@ -131,7 +131,7 @@ void ScrollbarThemeChromium::paintTickmarks(GraphicsContext* context, Scrollbar*
const int yPos = rect.topLeft().y() + (rect.height() * percent);
IntPoint tick(scrollbar->x(), yPos);
- context->drawImage(dash.get(), DeviceColorSpace, tick);
+ context->drawImage(dash.get(), ColorSpaceDeviceRGB, tick);
}
context->restore();
diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp
index d8f2c79..46e6993 100644
--- a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp
+++ b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp
@@ -31,17 +31,12 @@
#include "config.h"
#include "ScrollbarThemeChromiumLinux.h"
-#include "PlatformContextSkia.h"
+#include "ChromiumBridge.h"
#include "PlatformMouseEvent.h"
-#include "PlatformThemeChromiumGtk.h"
#include "Scrollbar.h"
-#include "TransformationMatrix.h"
namespace WebCore {
-static const int scrollbarThicknessValue = 15;
-static const int buttonLength = 14;
-
ScrollbarTheme* ScrollbarTheme::nativeTheme()
{
static ScrollbarThemeChromiumLinux theme;
@@ -50,136 +45,79 @@ ScrollbarTheme* ScrollbarTheme::nativeTheme()
int ScrollbarThemeChromiumLinux::scrollbarThickness(ScrollbarControlSize controlSize)
{
- return scrollbarThicknessValue;
-}
-
-static void drawVertLine(SkCanvas* canvas, int x, int y1, int y2, const SkPaint& paint)
-{
- SkIRect skrect;
- skrect.set(x, y1, x + 1, y2 + 1);
- canvas->drawIRect(skrect, paint);
-}
-
-static void drawHorizLine(SkCanvas* canvas, int x1, int x2, int y, const SkPaint& paint)
-{
- SkIRect skrect;
- skrect.set(x1, y, x2 + 1, y + 1);
- canvas->drawIRect(skrect, paint);
-}
-
-static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint)
-{
- const int right = rect.x() + rect.width() - 1;
- const int bottom = rect.y() + rect.height() - 1;
- drawHorizLine(canvas, rect.x(), right, rect.y(), paint);
- drawVertLine(canvas, right, rect.y(), bottom, paint);
- drawHorizLine(canvas, rect.x(), right, bottom, paint);
- drawVertLine(canvas, rect.x(), rect.y(), bottom, paint);
+ // Horiz and Vert scrollbars are the same thickness.
+ IntSize scrollbarSize = ChromiumBridge::getThemePartSize(ChromiumBridge::PartScrollbarVerticalTrack);
+ return scrollbarSize.width();
}
void ScrollbarThemeChromiumLinux::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart partType)
{
- SkCanvas* const canvas = gc->platformContext()->canvas();
- SkPaint paint;
- SkIRect skrect;
-
- skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
- SkScalar trackHSV[3];
- SkColorToHSV(PlatformThemeChromiumGtk::trackColor(), trackHSV);
- paint.setColor(PlatformThemeChromiumGtk::saturateAndBrighten(trackHSV, 0, 0));
- canvas->drawIRect(skrect, paint);
-
- SkScalar thumbHSV[3];
- SkColorToHSV(PlatformThemeChromiumGtk::thumbInactiveColor(),
- thumbHSV);
-
- paint.setColor(PlatformThemeChromiumGtk::outlineColor(trackHSV, thumbHSV));
- drawBox(canvas, rect, paint);
+ ChromiumBridge::ThemePaintState state = scrollbar->hoveredPart() == partType ? ChromiumBridge::StateHover : ChromiumBridge::StateNormal;
+ IntRect alignRect = trackRect(scrollbar, false);
+ ChromiumBridge::ThemePaintExtraParams extraParams;
+ extraParams.scrollbarTrack.trackX = alignRect.x();
+ extraParams.scrollbarTrack.trackY = alignRect.y();
+ extraParams.scrollbarTrack.trackWidth = alignRect.width();
+ extraParams.scrollbarTrack.trackHeight = alignRect.height();
+ ChromiumBridge::paintThemePart(
+ gc,
+ scrollbar->orientation() == HorizontalScrollbar ? ChromiumBridge::PartScrollbarHoriztonalTrack : ChromiumBridge::PartScrollbarVerticalTrack,
+ state,
+ rect,
+ &extraParams);
}
void ScrollbarThemeChromiumLinux::paintButton(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
{
- PlatformThemeChromiumGtk::ArrowDirection direction;
+ ChromiumBridge::ThemePart paintPart;
+ ChromiumBridge::ThemePaintState state = ChromiumBridge::StateNormal;
+ bool checkMin = false;
+ bool checkMax = false;
if (scrollbar->orientation() == HorizontalScrollbar) {
- if (part == BackButtonStartPart)
- direction = PlatformThemeChromiumGtk::West;
- else
- direction = PlatformThemeChromiumGtk::East;
+ if (part == BackButtonStartPart) {
+ paintPart = ChromiumBridge::PartScrollbarLeftArrow;
+ checkMin = true;
+ } else {
+ paintPart = ChromiumBridge::PartScrollbarRightArrow;
+ checkMax = true;
+ }
} else {
- if (part == BackButtonStartPart)
- direction = PlatformThemeChromiumGtk::North;
- else
- direction = PlatformThemeChromiumGtk::South;
+ if (part == BackButtonStartPart) {
+ paintPart = ChromiumBridge::PartScrollbarUpArrow;
+ checkMin = true;
+ } else {
+ paintPart = ChromiumBridge::PartScrollbarDownArrow;
+ checkMax = true;
+ }
}
-
- ControlStates states = 0;
- // Determine if the button can be pressed.
- if (((direction == PlatformThemeChromiumGtk::West || direction == PlatformThemeChromiumGtk::North) && scrollbar->currentPos())
- || ((direction == PlatformThemeChromiumGtk::East || direction == PlatformThemeChromiumGtk::South) && scrollbar->currentPos() != scrollbar->maximum()))
- states |= EnabledState;
-
- if (states & EnabledState) {
+ if ((checkMin && (scrollbar->currentPos() <= 0))
+ || (checkMax && scrollbar->currentPos() == scrollbar->maximum())) {
+ state = ChromiumBridge::StateDisabled;
+ } else {
if (part == scrollbar->pressedPart())
- states |= PressedState;
+ state = ChromiumBridge::StatePressed;
else if (part == scrollbar->hoveredPart())
- states |= HoverState;
+ state = ChromiumBridge::StateHover;
}
-
- PlatformThemeChromiumGtk::paintArrowButton(gc, rect, direction, states);
+ ChromiumBridge::paintThemePart(gc, paintPart, state, rect, 0);
}
void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect)
{
- const bool hovered = scrollbar->hoveredPart() == ThumbPart;
- const int midx = rect.x() + rect.width() / 2;
- const int midy = rect.y() + rect.height() / 2;
- const bool vertical = scrollbar->orientation() == VerticalScrollbar;
- SkCanvas* const canvas = gc->platformContext()->canvas();
-
- SkScalar thumb[3];
- SkColorToHSV(hovered
- ? PlatformThemeChromiumGtk::thumbActiveColor()
- : PlatformThemeChromiumGtk::thumbInactiveColor(),
- thumb);
-
- SkPaint paint;
- paint.setColor(PlatformThemeChromiumGtk::saturateAndBrighten(thumb, 0, 0.02));
-
- SkIRect skrect;
- if (vertical)
- skrect.set(rect.x(), rect.y(), midx + 1, rect.y() + rect.height());
- else
- skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), midy + 1);
-
- canvas->drawIRect(skrect, paint);
-
- paint.setColor(PlatformThemeChromiumGtk::saturateAndBrighten(thumb, 0, -0.02));
+ ChromiumBridge::ThemePaintState state;
- if (vertical)
- skrect.set(midx + 1, rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
+ if (scrollbar->pressedPart() == ThumbPart)
+ state = ChromiumBridge::StatePressed;
+ else if (scrollbar->hoveredPart() == ThumbPart)
+ state = ChromiumBridge::StateHover;
else
- skrect.set(rect.x(), midy + 1, rect.x() + rect.width(), rect.y() + rect.height());
-
- canvas->drawIRect(skrect, paint);
-
- SkScalar track[3];
- SkColorToHSV(PlatformThemeChromiumGtk::trackColor(), track);
- paint.setColor(PlatformThemeChromiumGtk::outlineColor(track, thumb));
- drawBox(canvas, rect, paint);
-
- if (rect.height() > 10 && rect.width() > 10) {
- const int grippyHalfWidth = 2;
- const int interGrippyOffset = 3;
- if (vertical) {
- drawHorizLine(canvas, midx - grippyHalfWidth, midx + grippyHalfWidth, midy - interGrippyOffset, paint);
- drawHorizLine(canvas, midx - grippyHalfWidth, midx + grippyHalfWidth, midy, paint);
- drawHorizLine(canvas, midx - grippyHalfWidth, midx + grippyHalfWidth, midy + interGrippyOffset, paint);
- } else {
- drawVertLine(canvas, midx - interGrippyOffset, midy - grippyHalfWidth, midy + grippyHalfWidth, paint);
- drawVertLine(canvas, midx, midy - grippyHalfWidth, midy + grippyHalfWidth, paint);
- drawVertLine(canvas, midx + interGrippyOffset, midy - grippyHalfWidth, midy + grippyHalfWidth, paint);
- }
- }
+ state = ChromiumBridge::StateNormal;
+ ChromiumBridge::paintThemePart(
+ gc,
+ scrollbar->orientation() == HorizontalScrollbar ? ChromiumBridge::PartScrollbarHorizontalThumb : ChromiumBridge::PartScrollbarVerticalThumb,
+ state,
+ rect,
+ 0);
}
bool ScrollbarThemeChromiumLinux::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
@@ -189,17 +127,25 @@ bool ScrollbarThemeChromiumLinux::shouldCenterOnThumb(Scrollbar*, const Platform
IntSize ScrollbarThemeChromiumLinux::buttonSize(Scrollbar* scrollbar)
{
- if (scrollbar->orientation() == VerticalScrollbar)
- return IntSize(scrollbarThicknessValue, buttonLength);
+ if (scrollbar->orientation() == VerticalScrollbar) {
+ IntSize size = ChromiumBridge::getThemePartSize(ChromiumBridge::PartScrollbarUpArrow);
+ return IntSize(size.width(), scrollbar->height() < 2 * size.height() ? scrollbar->height() / 2 : size.height());
+ }
// HorizontalScrollbar
- return IntSize(buttonLength, scrollbarThicknessValue);
+ IntSize size = ChromiumBridge::getThemePartSize(ChromiumBridge::PartScrollbarLeftArrow);
+ return IntSize(scrollbar->width() < 2 * size.width() ? scrollbar->width() / 2 : size.width(), size.height());
}
int ScrollbarThemeChromiumLinux::minimumThumbLength(Scrollbar* scrollbar)
{
- // This matches Firefox on Linux.
- return 2 * scrollbarThickness(scrollbar->controlSize());
+ if (scrollbar->orientation() == VerticalScrollbar) {
+ IntSize size = ChromiumBridge::getThemePartSize(ChromiumBridge::PartScrollbarVerticalThumb);
+ return size.height();
+ }
+
+ IntSize size = ChromiumBridge::getThemePartSize(ChromiumBridge::PartScrollbarHorizontalThumb);
+ return size.width();
}
} // namespace WebCore
diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm
index bafc96e..b47e998 100644
--- a/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm
+++ b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm
@@ -417,8 +417,8 @@ bool ScrollbarThemeChromiumMac::paint(Scrollbar* scrollbar, GraphicsContext* con
if (scrollbar->orientation() == VerticalScrollbar && tickmarks.size()) {
drawingContext->save();
drawingContext->setShouldAntialias(false);
- drawingContext->setStrokeColor(Color(0xCC, 0xAA, 0x00, 0xFF), DeviceColorSpace);
- drawingContext->setFillColor(Color(0xFF, 0xDD, 0x00, 0xFF), DeviceColorSpace);
+ drawingContext->setStrokeColor(Color(0xCC, 0xAA, 0x00, 0xFF), ColorSpaceDeviceRGB);
+ drawingContext->setFillColor(Color(0xFF, 0xDD, 0x00, 0xFF), ColorSpaceDeviceRGB);
IntRect thumbArea = trackRect(scrollbar, false);
if (!canDrawDirectly) {
@@ -453,7 +453,7 @@ bool ScrollbarThemeChromiumMac::paint(Scrollbar* scrollbar, GraphicsContext* con
}
if (!canDrawDirectly)
- context->drawImageBuffer(imageBuffer.get(), DeviceColorSpace, scrollbar->frameRect().location());
+ context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, scrollbar->frameRect().location());
return true;
}
diff --git a/WebCore/platform/chromium/ThemeChromiumMac.mm b/WebCore/platform/chromium/ThemeChromiumMac.mm
index 68fd7b7..5e457f3 100644
--- a/WebCore/platform/chromium/ThemeChromiumMac.mm
+++ b/WebCore/platform/chromium/ThemeChromiumMac.mm
@@ -376,6 +376,7 @@ static void paintCheckbox(ControlStates states, GraphicsContext* context, const
// Determine the width and height needed for the control and prepare the cell for painting.
NSButtonCell *checkboxCell = checkbox(states, zoomedRect, zoomFactor);
+ LocalCurrentGraphicsContext localContext(context);
context->save();
@@ -456,6 +457,7 @@ static void paintRadio(ControlStates states, GraphicsContext* context, const Int
{
// Determine the width and height needed for the control and prepare the cell for painting.
NSButtonCell *radioCell = radio(states, zoomedRect, zoomFactor);
+ LocalCurrentGraphicsContext localContext(context);
context->save();
diff --git a/WebCore/platform/chromium/WritableDataObject.cpp b/WebCore/platform/chromium/WritableDataObject.cpp
index 6e7c283..7cbf42c 100644
--- a/WebCore/platform/chromium/WritableDataObject.cpp
+++ b/WebCore/platform/chromium/WritableDataObject.cpp
@@ -36,22 +36,22 @@
namespace WebCore {
-PassRefPtr<WritableDataObject> WritableDataObject::create(bool isForDragging)
+PassRefPtr<WritableDataObject> WritableDataObject::create(Clipboard::ClipboardType clipboardType)
{
- return adoptRef(new WritableDataObject(isForDragging));
+ return adoptRef(new WritableDataObject(clipboardType));
}
-WritableDataObject::WritableDataObject(bool isForDragging)
- : m_isForDragging(isForDragging)
+WritableDataObject::WritableDataObject(Clipboard::ClipboardType clipboardType)
+ : m_clipboardType(clipboardType)
{
}
void WritableDataObject::clearData(const String& type)
{
m_dataMap.remove(type);
- if (type == textUriListType)
+ if (type == mimeTypeTextURIList)
m_urlTitle = "";
- else if (type == textHtmlType)
+ else if (type == mimeTypeTextHTML)
m_htmlBaseURL = KURL();
}
@@ -76,77 +76,19 @@ void WritableDataObject::clearAll()
bool WritableDataObject::setData(const String& type, const String& data)
{
- if (!m_isForDragging) {
+ if (m_clipboardType == Clipboard::CopyAndPaste) {
+ // FIXME: This is currently unimplemented on the Chromium-side. This is
+ // "okay" for now since the original implementation didn't support it
+ // anyway. Going forward, this is something we'll need to fix though.
ChromiumBridge::clipboardWriteData(type, data, "");
return true;
}
m_dataMap.set(type, data);
- if (type == textUriListType)
+ if (type == mimeTypeTextURIList)
m_urlTitle = "";
- else if (type == textHtmlType)
+ else if (type == mimeTypeTextHTML)
m_htmlBaseURL = KURL();
return true;
}
-void WritableDataObject::setURL(const String& url, const String& title)
-{
- setData(textUriListType, url);
- m_urlTitle = title;
-}
-
-void WritableDataObject::setHTML(const String& html, const KURL& baseURL)
-{
- setData(textHtmlType, html);
- m_htmlBaseURL = baseURL;
-}
-
-// Accessors used when transferring drag data from the renderer to the
-// browser.
-HashMap<String, String> WritableDataObject::dataMap() const
-{
- return m_dataMap;
-}
-
-String WritableDataObject::urlTitle() const
-{
- return m_urlTitle;
-}
-
-KURL WritableDataObject::htmlBaseURL() const
-{
- return m_htmlBaseURL;
-}
-
-// Used for transferring file data from the renderer to the browser.
-String WritableDataObject::fileExtension() const
-{
- return m_fileExtension;
-}
-
-String WritableDataObject::fileContentFilename() const
-{
- return m_fileContentFilename;
-}
-
-PassRefPtr<SharedBuffer> WritableDataObject::fileContent() const
-{
- return m_fileContent;
-}
-
-void WritableDataObject::setFileExtension(const String& fileExtension)
-{
- m_fileExtension = fileExtension;
-}
-
-void WritableDataObject::setFileContentFilename(const String& fileContentFilename)
-{
- m_fileContentFilename = fileContentFilename;
-}
-
-void WritableDataObject::setFileContent(PassRefPtr<SharedBuffer> fileContent)
-{
- m_fileContent = fileContent;
-}
-
-
} // namespace WebCore
diff --git a/WebCore/platform/chromium/WritableDataObject.h b/WebCore/platform/chromium/WritableDataObject.h
index 71e2e26..c475d15 100644
--- a/WebCore/platform/chromium/WritableDataObject.h
+++ b/WebCore/platform/chromium/WritableDataObject.h
@@ -31,6 +31,7 @@
#ifndef WritableDataObject_h
#define WritableDataObject_h
+#include "Clipboard.h"
#include "KURL.h"
#include "PlatformString.h"
#include "SharedBuffer.h"
@@ -47,32 +48,32 @@ namespace WebCore {
// atomically.
class WritableDataObject : public RefCounted<WritableDataObject> {
public:
- static PassRefPtr<WritableDataObject> create(bool isForDragging);
+ static PassRefPtr<WritableDataObject> create(Clipboard::ClipboardType);
- virtual void clearData(const String& type);
- virtual void clearAllExceptFiles();
- virtual void clearAll();
- virtual bool setData(const String& type, const String& data);
+ void clearData(const String& type);
+ void clearAllExceptFiles();
+ void clearAll();
+ bool setData(const String& type, const String& data);
- virtual void setURL(const String& url, const String& title);
- virtual void setHTML(const String& html, const KURL& baseURL);
+ void setUrlTitle(const String& title) { m_urlTitle = title; }
+ void setHtmlBaseUrl(const KURL& baseURL) { m_htmlBaseURL = baseURL; }
// Used for transferring drag data from the renderer to the browser.
- virtual HashMap<String, String> dataMap() const;
- virtual String urlTitle() const;
- virtual KURL htmlBaseURL() const;
+ HashMap<String, String> dataMap() const { return m_dataMap; }
+ String urlTitle() const { return m_urlTitle; }
+ KURL htmlBaseURL() const { return m_htmlBaseURL; }
- virtual String fileExtension() const;
- virtual String fileContentFilename() const;
- virtual PassRefPtr<SharedBuffer> fileContent() const;
- virtual void setFileExtension(const String&);
- virtual void setFileContentFilename(const String&);
- virtual void setFileContent(PassRefPtr<SharedBuffer>);
+ String fileExtension() const { return m_fileExtension; }
+ String fileContentFilename() const { return m_fileContentFilename; }
+ PassRefPtr<SharedBuffer> fileContent() const { return m_fileContent; }
+ void setFileExtension(const String& fileExtension) { m_fileExtension = fileExtension; }
+ void setFileContentFilename(const String& fileContentFilename) { m_fileContentFilename = fileContentFilename; }
+ void setFileContent(PassRefPtr<SharedBuffer> fileContent) { m_fileContent = fileContent; }
private:
- explicit WritableDataObject(bool isForDragging);
+ explicit WritableDataObject(Clipboard::ClipboardType);
- bool m_isForDragging;
+ Clipboard::ClipboardType m_clipboardType;
HashMap<String, String> m_dataMap;
String m_urlTitle;
diff --git a/WebCore/platform/cocoa/KeyEventCocoa.mm b/WebCore/platform/cocoa/KeyEventCocoa.mm
index cf83d93..a2b5c9c 100644
--- a/WebCore/platform/cocoa/KeyEventCocoa.mm
+++ b/WebCore/platform/cocoa/KeyEventCocoa.mm
@@ -471,6 +471,33 @@ int windowsKeyCodeForKeyCode(uint16_t keyCode)
int windowsKeyCodeForCharCode(unichar charCode)
{
switch (charCode) {
+#if PLATFORM(IOS)
+ case 8: case 0x7F: return VK_BACK;
+ case 9: return VK_TAB;
+ case 0xD: case 3: return VK_RETURN;
+ case 0x1B: return VK_ESCAPE;
+ case ' ': return VK_SPACE;
+ case NSHomeFunctionKey: return VK_HOME;
+ case NSEndFunctionKey: return VK_END;
+ case NSPageUpFunctionKey: return VK_PRIOR;
+ case NSPageDownFunctionKey: return VK_NEXT;
+ case NSUpArrowFunctionKey: return VK_UP;
+ case NSDownArrowFunctionKey: return VK_DOWN;
+ case NSLeftArrowFunctionKey: return VK_LEFT;
+ case NSRightArrowFunctionKey: return VK_RIGHT;
+ case NSDeleteFunctionKey: return VK_DELETE;
+
+ case '0': case ')': return VK_0;
+ case '1': case '!': return VK_1;
+ case '2': case '@': return VK_2;
+ case '3': case '#': return VK_3;
+ case '4': case '$': return VK_4;
+ case '5': case '%': return VK_5;
+ case '6': case '^': return VK_6;
+ case '7': case '&': return VK_7;
+ case '8': case '*': return VK_8;
+ case '9': case '(': return VK_9;
+#endif
case 'a': case 'A': return VK_A;
case 'b': case 'B': return VK_B;
case 'c': case 'C': return VK_C;
@@ -505,6 +532,30 @@ int windowsKeyCodeForCharCode(unichar charCode)
case NSExecuteFunctionKey: return VK_EXECUTE;
case NSPrintScreenFunctionKey: return VK_SNAPSHOT;
case NSInsertFunctionKey: return VK_INSERT;
+#if PLATFORM(IOS)
+ case NSHelpFunctionKey: return VK_INSERT;
+
+ case NSF1FunctionKey: return VK_F1;
+ case NSF2FunctionKey: return VK_F2;
+ case NSF3FunctionKey: return VK_F3;
+ case NSF4FunctionKey: return VK_F4;
+ case NSF5FunctionKey: return VK_F5;
+ case NSF6FunctionKey: return VK_F6;
+ case NSF7FunctionKey: return VK_F7;
+ case NSF8FunctionKey: return VK_F8;
+ case NSF9FunctionKey: return VK_F9;
+ case NSF10FunctionKey: return VK_F10;
+ case NSF11FunctionKey: return VK_F11;
+ case NSF12FunctionKey: return VK_F12;
+ case NSF13FunctionKey: return VK_F13;
+ case NSF14FunctionKey: return VK_F14;
+ case NSF15FunctionKey: return VK_F15;
+ case NSF16FunctionKey: return VK_F16;
+ case NSF17FunctionKey: return VK_F17;
+ case NSF18FunctionKey: return VK_F18;
+ case NSF19FunctionKey: return VK_F19;
+ case NSF20FunctionKey: return VK_F20;
+#endif
case NSF21FunctionKey: return VK_F21;
case NSF22FunctionKey: return VK_F22;
case NSF23FunctionKey: return VK_F23;
diff --git a/WebCore/platform/efl/Language.cpp b/WebCore/platform/efl/LanguageEfl.cpp
index 1da7925..4b765a6 100644
--- a/WebCore/platform/efl/Language.cpp
+++ b/WebCore/platform/efl/LanguageEfl.cpp
@@ -34,7 +34,7 @@
namespace WebCore {
-String defaultLanguage()
+String platformDefaultLanguage()
{
notImplemented();
return String();
diff --git a/WebCore/platform/efl/PlatformKeyboardEventEfl.cpp b/WebCore/platform/efl/PlatformKeyboardEventEfl.cpp
index fd84b15..2888b22 100644
--- a/WebCore/platform/efl/PlatformKeyboardEventEfl.cpp
+++ b/WebCore/platform/efl/PlatformKeyboardEventEfl.cpp
@@ -39,7 +39,7 @@
#include <Evas.h>
#include <stdio.h>
#include <wtf/HashMap.h>
-#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
#include <wtf/text/StringHash.h>
namespace WebCore {
@@ -53,7 +53,7 @@ static WindowsKeyMap gWindowsKeyMap;
static void createKeyMap()
{
for (unsigned int i = 1; i < 25; i++) {
- String key = String::format("F%d", i);
+ String key = makeString('F', String::number(i));
gKeyMap.set(key, key);
}
gKeyMap.set("Alt_L", "Alt");
@@ -131,15 +131,15 @@ static void createWindowsKeyMap()
gWindowsKeyMap.set("quotedbl", VK_OEM_7);
// Alphabet
- String alphabet = "abcdefghijklmnopqrstuvwxyz";
+ const char* alphabet = "abcdefghijklmnopqrstuvwxyz";
for (unsigned int i = 0; i < 26; i++) {
- String key = String::format("%c", alphabet[i]);
+ String key(alphabet + i, 1);
gWindowsKeyMap.set(key, VK_A + i);
}
// Digits
for (unsigned int i = 0; i < 10; i++) {
- String key = String::format("%d", i);
+ String key = String::number(i);
gWindowsKeyMap.set(key, VK_0 + i);
}
@@ -161,7 +161,7 @@ static void createWindowsKeyMap()
// F_XX
for (unsigned int i = 1; i < 25; i++) {
- String key = String::format("F%d", i);
+ String key = makeString('F', String::number(i));
gWindowsKeyMap.set(key, VK_F1 + i);
}
}
diff --git a/WebCore/platform/efl/RenderThemeEfl.cpp b/WebCore/platform/efl/RenderThemeEfl.cpp
index 53997be..6076747 100644
--- a/WebCore/platform/efl/RenderThemeEfl.cpp
+++ b/WebCore/platform/efl/RenderThemeEfl.cpp
@@ -35,6 +35,7 @@
#include "Page.h"
#include "RenderBox.h"
#include "RenderObject.h"
+#include "RenderProgress.h"
#include "RenderSlider.h"
#include <wtf/text/CString.h>
@@ -296,6 +297,25 @@ bool RenderThemeEfl::paintThemePart(RenderObject* o, FormType type, const PaintI
msg->val[0] = static_cast<float>(value) / static_cast<float>(max);
msg->val[1] = 0.1;
edje_object_message_send(ce->o, EDJE_MESSAGE_FLOAT_SET, 0, msg);
+#if ENABLE(PROGRESS_TAG)
+ } else if (type == ProgressBar) {
+ RenderProgress* renderProgress = toRenderProgress(o);
+ Edje_Message_Float_Set* msg;
+ int max;
+ double value;
+
+ msg = static_cast<Edje_Message_Float_Set*>(alloca(sizeof(Edje_Message_Float_Set) + sizeof(float)));
+ max = rect.width();
+ value = renderProgress->position();
+
+ msg->count = 2;
+ if (o->style()->direction() == RTL)
+ msg->val[0] = (1.0 - value) * max;
+ else
+ msg->val[0] = 0;
+ msg->val[1] = value;
+ edje_object_message_send(ce->o, EDJE_MESSAGE_FLOAT_SET, 0, msg);
+#endif
}
edje_object_calc_force(ce->o);
@@ -562,6 +582,9 @@ const char* RenderThemeEfl::edjeGroupFromFormType(FormType type) const
W("entry"),
W("checkbox"),
W("combo"),
+#if ENABLE(PROGRESS_TAG)
+ W("progressbar"),
+#endif
W("search/field"),
W("search/decoration"),
W("search/results_button"),
@@ -1008,4 +1031,16 @@ void RenderThemeEfl::systemFont(int propId, FontDescription& fontDescription) co
fontDescription.setItalic(false);
}
+#if ENABLE(PROGRESS_TAG)
+void RenderThemeEfl::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ style->setBoxShadow(0);
+}
+
+bool RenderThemeEfl::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& rect)
+{
+ return paintThemePart(o, ProgressBar, i, rect);
+}
+#endif
+
}
diff --git a/WebCore/platform/efl/RenderThemeEfl.h b/WebCore/platform/efl/RenderThemeEfl.h
index 478dfc5..087e2aa 100644
--- a/WebCore/platform/efl/RenderThemeEfl.h
+++ b/WebCore/platform/efl/RenderThemeEfl.h
@@ -45,6 +45,9 @@ enum FormType { // KEEP IN SYNC WITH edjeGroupFromFormType()
TextField,
CheckBox,
ComboBox,
+#if ENABLE(PROGRESS_TAG)
+ ProgressBar,
+#endif
SearchField,
SearchFieldDecoration,
SearchFieldResultsButton,
@@ -145,6 +148,11 @@ public:
static void setDefaultFontSize(int size);
+#if ENABLE(PROGRESS_TAG)
+ virtual void adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&);
+#endif
+
protected:
static float defaultFontSize;
diff --git a/WebCore/platform/efl/SharedBufferEfl.cpp b/WebCore/platform/efl/SharedBufferEfl.cpp
index 1025e33..23769ab 100644
--- a/WebCore/platform/efl/SharedBufferEfl.cpp
+++ b/WebCore/platform/efl/SharedBufferEfl.cpp
@@ -56,7 +56,7 @@ PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& fi
result = SharedBuffer::create();
result->m_buffer.resize(fileStat.st_size);
- if (result->m_buffer.size() != fileStat.st_size) {
+ if (result->m_buffer.size() != static_cast<unsigned>(fileStat.st_size)) {
fclose(file);
return 0;
}
diff --git a/WebCore/platform/efl/SharedTimerEfl.cpp b/WebCore/platform/efl/SharedTimerEfl.cpp
index 437de64..990d0c8 100644
--- a/WebCore/platform/efl/SharedTimerEfl.cpp
+++ b/WebCore/platform/efl/SharedTimerEfl.cpp
@@ -30,43 +30,97 @@
#include "SharedTimer.h"
#include <Ecore.h>
+#include <pthread.h>
#include <stdio.h>
#include <wtf/Assertions.h>
#include <wtf/CurrentTime.h>
+#include <wtf/MainThread.h>
namespace WebCore {
-static Ecore_Timer *g_sharedTimer = 0;
+static pthread_mutex_t timerMutex = PTHREAD_MUTEX_INITIALIZER;
+static Ecore_Timer *_sharedTimer = 0;
+static Ecore_Pipe *_pipe = 0;
-static void (*g_timerFunction)();
+static void (*_timerFunction)();
+
+struct timerOp {
+ double time;
+ unsigned char op; // 0 - add a timer; 1 - del a timer;
+};
void setSharedTimerFiredFunction(void (*func)())
{
- g_timerFunction = func;
+ _timerFunction = func;
}
static Eina_Bool timerEvent(void*)
{
- if (g_timerFunction)
- g_timerFunction();
+ if (_timerFunction)
+ _timerFunction();
+
+ _sharedTimer = 0;
return ECORE_CALLBACK_CANCEL;
}
-void stopSharedTimer()
+void processTimers(struct timerOp *tOp)
{
- if (g_sharedTimer) {
- ecore_timer_del(g_sharedTimer);
- g_sharedTimer = 0;
+ if (_sharedTimer) {
+ ecore_timer_del(_sharedTimer);
+ _sharedTimer = 0;
}
+
+ if (tOp->op == 1)
+ return;
+
+ double interval = tOp->time - currentTime();
+
+ if (interval <= ecore_animator_frametime_get()) {
+ if (_timerFunction)
+ _timerFunction();
+ return;
+ }
+
+ _sharedTimer = ecore_timer_add(interval, timerEvent, 0);
}
-void setSharedTimerFireTime(double fireTime)
+void pipeHandlerCb(void *data, void *buffer, unsigned int nbyte)
+{
+ ASSERT(nbyte == sizeof(struct timerOp));
+
+ struct timerOp *tOp = (struct timerOp *)buffer;
+ processTimers(tOp);
+}
+
+void stopSharedTimer()
{
- double interval = fireTime - currentTime();
+ struct timerOp tOp;
+ pthread_mutex_lock(&timerMutex);
+ if (!_pipe)
+ _pipe = ecore_pipe_add(pipeHandlerCb, 0);
+ pthread_mutex_unlock(&timerMutex);
- stopSharedTimer();
- g_sharedTimer = ecore_timer_add(interval, timerEvent, 0);
+ tOp.op = 1;
+ ecore_pipe_write(_pipe, &tOp, sizeof(tOp));
+}
+
+void addNewTimer(double fireTime)
+{
+ struct timerOp tOp;
+ pthread_mutex_lock(&timerMutex);
+ if (!_pipe)
+ _pipe = ecore_pipe_add(pipeHandlerCb, 0);
+ pthread_mutex_unlock(&timerMutex);
+
+ tOp.time = fireTime;
+ tOp.op = 0;
+ ecore_pipe_write(_pipe, &tOp, sizeof(tOp));
+}
+
+void setSharedTimerFireTime(double fireTime)
+{
+ addNewTimer(fireTime);
}
}
diff --git a/WebCore/platform/efl/WidgetEfl.cpp b/WebCore/platform/efl/WidgetEfl.cpp
index d82e99e..640e6e3 100644
--- a/WebCore/platform/efl/WidgetEfl.cpp
+++ b/WebCore/platform/efl/WidgetEfl.cpp
@@ -206,7 +206,7 @@ void Widget::setFocus(bool focused)
void Widget::applyFallbackCursor()
{
-#if HAVE_ECORE_X
+#ifdef HAVE_ECORE_X
if (m_data->m_isUsingEcoreX && !m_data->m_cursorGroup.isNull()) {
int shape = cursorStringMap.cursor(m_data->m_cursorGroup.utf8().data());
diff --git a/WebCore/platform/graphics/ANGLEWebKitBridge.cpp b/WebCore/platform/graphics/ANGLEWebKitBridge.cpp
index 9a14820..64f19c4 100644
--- a/WebCore/platform/graphics/ANGLEWebKitBridge.cpp
+++ b/WebCore/platform/graphics/ANGLEWebKitBridge.cpp
@@ -44,8 +44,6 @@ ANGLEWebKitBridge::~ANGLEWebKitBridge()
ShDestruct(m_fragmentCompiler);
ShDestruct(m_vertexCompiler);
}
-
- ShFinalize();
}
bool ANGLEWebKitBridge::validateShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog)
diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp
index f28d51c..fa7346e 100644
--- a/WebCore/platform/graphics/Color.cpp
+++ b/WebCore/platform/graphics/Color.cpp
@@ -175,8 +175,7 @@ Color::Color(const char* name)
m_valid = parseHexColor(&name[1], m_color);
else {
const NamedColor* foundColor = findColor(name, strlen(name));
- m_color = foundColor ? foundColor->RGBValue : 0;
- m_color |= 0xFF000000;
+ m_color = foundColor ? foundColor->ARGBValue : 0;
m_valid = foundColor;
}
}
@@ -219,8 +218,7 @@ static inline const NamedColor* findNamedColor(const String& name)
void Color::setNamedColor(const String& name)
{
const NamedColor* foundColor = findNamedColor(name);
- m_color = foundColor ? foundColor->RGBValue : 0;
- m_color |= 0xFF000000;
+ m_color = foundColor ? foundColor->ARGBValue : 0;
m_valid = foundColor;
}
diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h
index 22a8a8f..276e69f 100644
--- a/WebCore/platform/graphics/Color.h
+++ b/WebCore/platform/graphics/Color.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-6 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -31,6 +31,7 @@
#include <wtf/unicode/Unicode.h>
#if PLATFORM(CG)
+#include "ColorSpace.h"
typedef struct CGColor* CGColorRef;
#endif
@@ -180,7 +181,7 @@ Color colorFromPremultipliedARGB(unsigned);
unsigned premultipliedARGBFromColor(const Color&);
#if PLATFORM(CG)
-CGColorRef createCGColor(const Color&);
+CGColorRef cachedCGColor(const Color&, ColorSpace);
#endif
} // namespace WebCore
diff --git a/WebCore/platform/graphics/ColorSpace.h b/WebCore/platform/graphics/ColorSpace.h
index 1bad58c..7622c47 100644
--- a/WebCore/platform/graphics/ColorSpace.h
+++ b/WebCore/platform/graphics/ColorSpace.h
@@ -28,7 +28,11 @@
namespace WebCore {
- enum ColorSpace { DeviceColorSpace, sRGBColorSpace };
+enum ColorSpace {
+ ColorSpaceDeviceRGB,
+ ColorSpaceSRGB,
+ ColorSpaceLinearRGB
+};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/ContextShadow.cpp b/WebCore/platform/graphics/ContextShadow.cpp
index 1007962..87a1c5c 100644
--- a/WebCore/platform/graphics/ContextShadow.cpp
+++ b/WebCore/platform/graphics/ContextShadow.cpp
@@ -39,18 +39,20 @@ namespace WebCore {
ContextShadow::ContextShadow()
: m_type(NoShadow)
- , m_blurRadius(0)
+ , m_blurDistance(0)
+ , m_layerContext(0)
{
}
ContextShadow::ContextShadow(const Color& color, float radius, const FloatSize& offset)
: m_color(color)
- , m_blurRadius(round(radius))
+ , m_blurDistance(round(radius))
, m_offset(offset)
+ , m_layerContext(0)
{
// See comments in http://webkit.org/b/40793, it seems sensible
// to follow Skia's limit of 128 pixels of blur radius
- m_blurRadius = min(m_blurRadius, 128);
+ 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()) {
@@ -71,7 +73,7 @@ void ContextShadow::clear()
{
m_type = NoShadow;
m_color = Color();
- m_blurRadius = 0;
+ m_blurDistance = 0;
m_offset = FloatSize();
}
@@ -85,8 +87,9 @@ static const int BlurSumShift = 15;
void ContextShadow::blurLayerImage(unsigned char* imageData, const IntSize& size, int rowStride)
{
int channels[4] = { 3, 0, 1, 3 };
- int dmax = m_blurRadius >> 1;
- int dmin = dmax - 1 + (m_blurRadius & 1);
+ 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;
@@ -153,8 +156,8 @@ void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const
destinationRect.move(m_offset);
m_layerRect = enclosingIntRect(destinationRect);
- // We expand the area by the blur radius * 2 to give extra space for the blur transition.
- m_layerRect.inflate((m_type == BlurShadow) ? ceil(m_blurRadius * 2) : 0);
+ // We expand the area by the blur radius to give extra space for the blur transition.
+ m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0);
if (!clipRect.contains(m_layerRect)) {
// No need to have the buffer larger than the clip.
@@ -167,7 +170,7 @@ void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const
// We adjust again because the pixels at the borders are still
// potentially affected by the pixels outside the buffer.
if (m_type == BlurShadow)
- m_layerRect.inflate((m_type == BlurShadow) ? ceil(m_blurRadius * 2) : 0);
+ m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0);
}
}
diff --git a/WebCore/platform/graphics/ContextShadow.h b/WebCore/platform/graphics/ContextShadow.h
index ede9336..0160f8a 100644
--- a/WebCore/platform/graphics/ContextShadow.h
+++ b/WebCore/platform/graphics/ContextShadow.h
@@ -31,6 +31,7 @@
#include "Color.h"
#include "FloatRect.h"
+#include "GraphicsContext.h"
#include "IntRect.h"
#include "RefCounted.h"
@@ -65,7 +66,7 @@ public:
} m_type;
Color m_color;
- int m_blurRadius;
+ int m_blurDistance;
FloatSize m_offset;
ContextShadow();
@@ -98,6 +99,9 @@ public:
PlatformContext beginShadowLayer(PlatformContext, const FloatRect& layerArea);
void endShadowLayer(PlatformContext);
static void purgeScratchBuffer();
+#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() { return QPointF(m_offset.width(), m_offset.height()); }
@@ -111,6 +115,9 @@ private:
void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride);
void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect);
+#if PLATFORM(CAIRO)
+ void drawRectShadowWithoutTiling(PlatformContext context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha);
+#endif
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h
index e387927..10ad838 100644
--- a/WebCore/platform/graphics/FloatRect.h
+++ b/WebCore/platform/graphics/FloatRect.h
@@ -59,6 +59,10 @@ class BRect;
struct SkRect;
#endif
+#if PLATFORM(CAIRO)
+typedef struct _cairo_rectangle cairo_rectangle_t;
+#endif
+
namespace WebCore {
#if PLATFORM(OPENVG)
@@ -172,6 +176,11 @@ public:
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;
diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp
index 3dfdb20..ec15d26 100644
--- a/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/WebCore/platform/graphics/GraphicsContext.cpp
@@ -219,7 +219,7 @@ void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
{
ASSERT(pattern);
if (!pattern) {
- setStrokeColor(Color::black, DeviceColorSpace);
+ setStrokeColor(Color::black, ColorSpaceDeviceRGB);
return;
}
m_common->state.strokeGradient.clear();
@@ -231,7 +231,7 @@ void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
{
ASSERT(pattern);
if (!pattern) {
- setFillColor(Color::black, DeviceColorSpace);
+ setFillColor(Color::black, ColorSpaceDeviceRGB);
return;
}
m_common->state.fillGradient.clear();
@@ -243,7 +243,7 @@ void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
{
ASSERT(gradient);
if (!gradient) {
- setStrokeColor(Color::black, DeviceColorSpace);
+ setStrokeColor(Color::black, ColorSpaceDeviceRGB);
return;
}
m_common->state.strokeGradient = gradient;
@@ -255,7 +255,7 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
{
ASSERT(gradient);
if (!gradient) {
- setFillColor(Color::black, DeviceColorSpace);
+ setFillColor(Color::black, ColorSpaceDeviceRGB);
return;
}
m_common->state.fillGradient = gradient;
@@ -500,7 +500,9 @@ void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& top
if (paintingDisabled())
return;
- clip(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
+ Path path;
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ clip(path);
}
void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
@@ -509,7 +511,9 @@ void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& top
if (paintingDisabled())
return;
- clipOut(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
+ Path path;
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ clipOut(path);
}
void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect)
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index fd3bf2c..b1fa48a 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -41,6 +41,9 @@
typedef struct CGContext PlatformGraphicsContext;
#elif PLATFORM(CAIRO)
#include "PlatformRefPtrCairo.h"
+namespace WebCore {
+class ContextShadow;
+}
typedef struct _cairo PlatformGraphicsContext;
#elif PLATFORM(OPENVG)
namespace WebCore {
@@ -333,11 +336,6 @@ namespace WebCore {
void setAlpha(float);
#if PLATFORM(CAIRO)
float getAlpha();
- void applyPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float radius);
- PlatformRefPtr<cairo_surface_t> createShadowMask(PassOwnPtr<ImageBuffer>, const FloatRect&, float radius);
-
- static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& radius, const FloatRect& sourceRect, const FloatSize& shadowOffset, float shadowBlur);
- void drawTiledShadow(const IntRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius, ColorSpace colorSpace);
#endif
void setCompositeOperation(CompositeOperator);
@@ -438,6 +436,9 @@ namespace WebCore {
void pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask);
QPen pen();
static QPainter::CompositionMode toQtCompositionMode(CompositeOperator op);
+#endif
+
+#if PLATFORM(QT) || PLATFORM(CAIRO)
ContextShadow* contextShadow();
#endif
diff --git a/WebCore/platform/graphics/GraphicsContext3D.cpp b/WebCore/platform/graphics/GraphicsContext3D.cpp
index 86e9569..d2e9057 100644
--- a/WebCore/platform/graphics/GraphicsContext3D.cpp
+++ b/WebCore/platform/graphics/GraphicsContext3D.cpp
@@ -31,11 +31,27 @@
#include "GraphicsContext3D.h"
#include "ArrayBufferView.h"
+#include "DrawingBuffer.h"
#include "Image.h"
#include "ImageData.h"
namespace WebCore {
+static uint8_t convertColor16LittleTo8(uint16_t value)
+{
+ return value >> 8;
+}
+
+static uint8_t convertColor16BigTo8(uint16_t value)
+{
+ return static_cast<uint8_t>(value & 0x00FF);
+}
+
+PassRefPtr<DrawingBuffer> GraphicsContext3D::createDrawingBuffer(const IntSize& size)
+{
+ return DrawingBuffer::create(this, size);
+}
+
bool GraphicsContext3D::computeFormatAndTypeParameters(unsigned int format,
unsigned int type,
unsigned long* componentsPerPixel,
@@ -247,6 +263,22 @@ void unpackRGBA8ToRGBA8(const uint8_t* source, uint8_t* destination)
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];
@@ -255,6 +287,22 @@ void unpackRGB8ToRGBA8(const uint8_t* source, uint8_t* destination)
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 unpackARGB8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[1];
@@ -263,6 +311,22 @@ void unpackARGB8ToRGBA8(const uint8_t* source, uint8_t* destination)
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 unpackBGRA8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[2];
@@ -271,6 +335,22 @@ void unpackBGRA8ToRGBA8(const uint8_t* source, uint8_t* destination)
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];
@@ -316,6 +396,22 @@ void unpackR8ToRGBA8(const uint8_t* source, uint8_t* destination)
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];
@@ -324,6 +420,22 @@ void unpackRA8ToRGBA8(const uint8_t* source, uint8_t* destination)
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];
@@ -332,6 +444,22 @@ void unpackAR8ToRGBA8(const uint8_t* source, uint8_t* destination)
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;
@@ -340,6 +468,22 @@ void unpackA8ToRGBA8(const uint8_t* source, uint8_t* destination)
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]);
+}
+
//----------------------------------------------------------------------
// Pixel packing routines.
//
@@ -602,6 +746,7 @@ static void computeIncrementParameters(unsigned int width,
{
unsigned int elementSizeInBytes = sizeof(SourceType);
ASSERT(elementSizeInBytes <= bytesPerPixel);
+ ASSERT(!(bytesPerPixel % elementSizeInBytes));
unsigned int validRowBytes = width * bytesPerPixel;
unsigned int totalRowBytes = validRowBytes;
if (unpackAlignment) {
@@ -644,24 +789,72 @@ static void doPacking(const void* sourceData,
}
break;
}
+ case GraphicsContext3D::kSourceFormatRGBA16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackRGBA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::kSourceFormatRGBA16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackRGBA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
case GraphicsContext3D::kSourceFormatRGB8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, DestType, unpackRGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
+ case GraphicsContext3D::kSourceFormatRGB16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackRGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::kSourceFormatRGB16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackRGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
case GraphicsContext3D::kSourceFormatARGB8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, DestType, unpackARGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
+ case GraphicsContext3D::kSourceFormatARGB16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackARGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::kSourceFormatARGB16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackARGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
case GraphicsContext3D::kSourceFormatBGRA8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, DestType, unpackBGRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
+ case GraphicsContext3D::kSourceFormatBGRA16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackBGRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::kSourceFormatBGRA16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackBGRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
case GraphicsContext3D::kSourceFormatRGBA5551: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
@@ -686,24 +879,72 @@ static void doPacking(const void* sourceData,
doUnpackingAndPacking<uint8_t, DestType, unpackR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
+ case GraphicsContext3D::kSourceFormatR16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::kSourceFormatR16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
case GraphicsContext3D::kSourceFormatRA8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, DestType, unpackRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
+ case GraphicsContext3D::kSourceFormatRA16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::kSourceFormatRA16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
case GraphicsContext3D::kSourceFormatAR8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, DestType, unpackAR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
+ case GraphicsContext3D::kSourceFormatAR16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackAR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::kSourceFormatAR16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackAR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
case GraphicsContext3D::kSourceFormatA8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, DestType, unpackA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
+ case GraphicsContext3D::kSourceFormatA16Little: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
+ case GraphicsContext3D::kSourceFormatA16Big: {
+ unsigned int sourceElementsPerPixel, sourceElementsPerRow;
+ computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
+ doUnpackingAndPacking<uint16_t, DestType, unpackA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
+ break;
+ }
}
}
diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h
index a12b1c4..d74c97c 100644
--- a/WebCore/platform/graphics/GraphicsContext3D.h
+++ b/WebCore/platform/graphics/GraphicsContext3D.h
@@ -26,16 +26,12 @@
#ifndef GraphicsContext3D_h
#define GraphicsContext3D_h
-#if PLATFORM(MAC)
-#include "ANGLEWebKitBridge.h"
-#endif
#include "GraphicsLayer.h"
#include "PlatformString.h"
#include <wtf/HashMap.h>
#include <wtf/ListHashSet.h>
#include <wtf/Noncopyable.h>
-#include <wtf/PassOwnPtr.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)))
@@ -43,6 +39,7 @@
#endif
#if PLATFORM(MAC)
+#include "ANGLEWebKitBridge.h"
#include <OpenGL/OpenGL.h>
#include <wtf/RetainPtr.h>
@@ -78,6 +75,7 @@ const Platform3DObject NullPlatform3DObject = 0;
namespace WebCore {
class CanvasRenderingContext;
+class DrawingBuffer;
class HostWindow;
class Image;
class ImageData;
@@ -94,7 +92,7 @@ struct ActiveInfo {
class GraphicsContext3DInternal;
#endif
-class GraphicsContext3D : public Noncopyable {
+class GraphicsContext3D : public RefCounted<GraphicsContext3D> {
public:
enum WebGLEnumType {
DEPTH_BUFFER_BIT = 0x00000100,
@@ -409,7 +407,13 @@ public:
// GL_CHROMIUM_map_sub (enums inherited from GL_ARB_vertex_buffer_object)
READ_ONLY = 0x88B8,
- WRITE_ONLY = 0x88B9
+ WRITE_ONLY = 0x88B9,
+
+ // GL_ARB_robustness enums
+ GUILTY_CONTEXT_RESET_ARB = 0x8253,
+ INNOCENT_CONTEXT_RESET_ARB = 0x8254,
+ UNKNOWN_CONTEXT_RESET_ARB = 0x8255
+
};
// Context creation attributes.
@@ -435,8 +439,8 @@ public:
RenderDirectlyToHostWindow
};
- static PassOwnPtr<GraphicsContext3D> create(Attributes attrs, HostWindow* hostWindow, RenderStyle renderStyle = RenderOffscreen);
- virtual ~GraphicsContext3D();
+ static PassRefPtr<GraphicsContext3D> create(Attributes, HostWindow*, RenderStyle = RenderOffscreen);
+ ~GraphicsContext3D();
#if PLATFORM(MAC)
PlatformGraphicsContext3D platformGraphicsContext3D() const { return m_contextObj; }
@@ -463,6 +467,8 @@ public:
#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();
@@ -535,16 +541,32 @@ public:
// by non-member functions.
enum SourceDataFormat {
kSourceFormatRGBA8,
+ kSourceFormatRGBA16Little,
+ kSourceFormatRGBA16Big,
kSourceFormatRGB8,
+ kSourceFormatRGB16Little,
+ kSourceFormatRGB16Big,
kSourceFormatBGRA8,
+ kSourceFormatBGRA16Little,
+ kSourceFormatBGRA16Big,
kSourceFormatARGB8,
+ kSourceFormatARGB16Little,
+ kSourceFormatARGB16Big,
kSourceFormatRGBA5551,
kSourceFormatRGBA4444,
kSourceFormatRGB565,
kSourceFormatR8,
+ kSourceFormatR16Little,
+ kSourceFormatR16Big,
kSourceFormatRA8,
+ kSourceFormatRA16Little,
+ kSourceFormatRA16Big,
kSourceFormatAR8,
- kSourceFormatA8
+ kSourceFormatAR16Little,
+ kSourceFormatAR16Big,
+ kSourceFormatA8,
+ kSourceFormatA16Little,
+ kSourceFormatA16Big
};
//----------------------------------------------------------------------
@@ -777,6 +799,9 @@ public:
bool supportsCopyTextureToParentTextureCHROMIUM();
void copyTextureToParentTextureCHROMIUM(unsigned texture, unsigned parentTexture);
+ // GL_ARB_robustness
+ int getGraphicsResetStatusARB();
+
private:
GraphicsContext3D(Attributes attrs, HostWindow* hostWindow, bool renderDirectlyToHostWindow);
diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h
index 903c7e3..985cad9 100644
--- a/WebCore/platform/graphics/GraphicsContextPrivate.h
+++ b/WebCore/platform/graphics/GraphicsContextPrivate.h
@@ -39,10 +39,10 @@ namespace WebCore {
, strokeStyle(SolidStroke)
, strokeThickness(0)
, strokeColor(Color::black)
- , strokeColorSpace(DeviceColorSpace)
+ , strokeColorSpace(ColorSpaceDeviceRGB)
, fillRule(RULE_NONZERO)
, fillColor(Color::black)
- , fillColorSpace(DeviceColorSpace)
+ , fillColorSpace(ColorSpaceDeviceRGB)
, shouldAntialias(true)
, paintingDisabled(false)
, shadowBlur(0)
diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp
index 412f06d..08b79ab 100644
--- a/WebCore/platform/graphics/GraphicsLayer.cpp
+++ b/WebCore/platform/graphics/GraphicsLayer.cpp
@@ -33,6 +33,7 @@
#include "RotateTransformOperation.h"
#include "TextStream.h"
#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
#ifndef NDEBUG
#include <stdio.h>
@@ -249,7 +250,7 @@ void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const I
String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property)
{
// | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier.
- return String::format("-|transition%c-", property);
+ return makeString("-|transition", static_cast<char>(property), '-');
}
void GraphicsLayer::suspendAnimations(double)
diff --git a/WebCore/platform/graphics/ImageBuffer.cpp b/WebCore/platform/graphics/ImageBuffer.cpp
index 71b8189..4a76be4 100644
--- a/WebCore/platform/graphics/ImageBuffer.cpp
+++ b/WebCore/platform/graphics/ImageBuffer.cpp
@@ -32,17 +32,17 @@
namespace WebCore {
-void ImageBuffer::transformColorSpace(ImageColorSpace srcColorSpace, ImageColorSpace dstColorSpace)
+void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace)
{
if (srcColorSpace == dstColorSpace)
return;
// only sRGB <-> linearRGB are supported at the moment
- if ((srcColorSpace != LinearRGB && srcColorSpace != DeviceRGB) ||
- (dstColorSpace != LinearRGB && dstColorSpace != DeviceRGB))
+ if ((srcColorSpace != ColorSpaceLinearRGB && srcColorSpace != ColorSpaceDeviceRGB)
+ || (dstColorSpace != ColorSpaceLinearRGB && dstColorSpace != ColorSpaceDeviceRGB))
return;
- if (dstColorSpace == LinearRGB) {
+ if (dstColorSpace == ColorSpaceLinearRGB) {
if (m_linearRgbLUT.isEmpty()) {
for (unsigned i = 0; i < 256; i++) {
float color = i / 255.0f;
@@ -53,7 +53,7 @@ void ImageBuffer::transformColorSpace(ImageColorSpace srcColorSpace, ImageColorS
}
}
platformTransformColorSpace(m_linearRgbLUT);
- } else if (dstColorSpace == DeviceRGB) {
+ } else if (dstColorSpace == ColorSpaceDeviceRGB) {
if (m_deviceRgbLUT.isEmpty()) {
for (unsigned i = 0; i < 256; i++) {
float color = i / 255.0f;
diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h
index 3c0508e..822a0ff 100644
--- a/WebCore/platform/graphics/ImageBuffer.h
+++ b/WebCore/platform/graphics/ImageBuffer.h
@@ -29,6 +29,7 @@
#define ImageBuffer_h
#include "AffineTransform.h"
+#include "ColorSpace.h"
#include "FloatRect.h"
#include "Image.h"
#include "IntSize.h"
@@ -44,13 +45,6 @@ namespace WebCore {
class ImageData;
class IntPoint;
class IntRect;
-
- enum ImageColorSpace {
- Unknown,
- DeviceRGB, // like sRGB
- GrayScale,
- LinearRGB
- };
enum Multiply {
Premultiplied,
@@ -60,7 +54,7 @@ namespace WebCore {
class ImageBuffer : public Noncopyable {
public:
// Will return a null pointer on allocation failure.
- static PassOwnPtr<ImageBuffer> create(const IntSize& size, ImageColorSpace colorSpace = DeviceRGB)
+ static PassOwnPtr<ImageBuffer> create(const IntSize& size, ColorSpace colorSpace = ColorSpaceDeviceRGB)
{
bool success = false;
OwnPtr<ImageBuffer> buf(new ImageBuffer(size, colorSpace, success));
@@ -89,7 +83,7 @@ namespace WebCore {
String toDataURL(const String& mimeType, const double* quality = 0) const;
#if !PLATFORM(CG)
AffineTransform baseTransform() const { return AffineTransform(); }
- void transformColorSpace(ImageColorSpace srcColorSpace, ImageColorSpace dstColorSpace);
+ 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()); }
@@ -119,7 +113,7 @@ namespace WebCore {
// This constructor will place its success into the given out-variable
// so that create() knows when it should return failure.
- ImageBuffer(const IntSize&, ImageColorSpace colorSpace, bool& success);
+ ImageBuffer(const IntSize&, ColorSpace colorSpace, bool& success);
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h
index c5990ef..c8d7c71 100644
--- a/WebCore/platform/graphics/IntRect.h
+++ b/WebCore/platform/graphics/IntRect.h
@@ -56,6 +56,8 @@ 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)
@@ -158,6 +160,9 @@ public:
#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)
diff --git a/WebCore/platform/graphics/Path.cpp b/WebCore/platform/graphics/Path.cpp
index 4e2de53..55760b1 100644
--- a/WebCore/platform/graphics/Path.cpp
+++ b/WebCore/platform/graphics/Path.cpp
@@ -35,8 +35,9 @@
#include <math.h>
#include <wtf/MathExtras.h>
-static const float QUARTER = 0.552f; // approximation of control point positions on a bezier
- // to simulate a quarter of a circle.
+// 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)
@@ -47,7 +48,7 @@ static void pathLengthApplierFunction(void* info, const PathElement* element)
return;
traversalState.m_previous = traversalState.m_current;
FloatPoint* points = element->points;
- float segmentLength = 0.0f;
+ float segmentLength = 0;
switch (element->type) {
case PathElementMoveToPoint:
segmentLength = traversalState.moveTo(points[0]);
@@ -75,10 +76,8 @@ static void pathLengthApplierFunction(void* info, const PathElement* element)
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 {
- static const float rad2deg = 180.0f / piFloat;
- traversalState.m_normalAngle = slope * rad2deg;
- }
+ } else
+ traversalState.m_normalAngle = rad2deg(slope);
traversalState.m_success = true;
}
@@ -110,167 +109,83 @@ float Path::normalAngleAtLength(float length, bool& ok)
}
#endif
-Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& roundingRadii)
+void Path::addRoundedRect(const FloatRect& rect, const FloatSize& roundingRadii)
{
- Path path;
- float x = rectangle.x();
- float y = rectangle.y();
- float width = rectangle.width();
- float height = rectangle.height();
- float rx = roundingRadii.width();
- float ry = roundingRadii.height();
- if (width <= 0.0f || height <= 0.0f)
- return path;
+ if (rect.isEmpty())
+ return;
+
+ FloatSize radius(roundingRadii);
+ FloatSize halfSize(rect.width() / 2, rect.height() / 2);
- float dx = rx, dy = ry;
// 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 (dx > width * 0.5f)
- dx = width * 0.5f;
+ 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 (dy > height * 0.5f)
- dy = height * 0.5f;
+ if (radius.height() > halfSize.height())
+ radius.setHeight(halfSize.height());
- path.moveTo(FloatPoint(x + dx, y));
+ moveTo(FloatPoint(rect.x() + radius.width(), rect.y()));
- if (dx < width * 0.5f)
- path.addLineTo(FloatPoint(x + width - rx, y));
+ if (radius.width() < halfSize.width())
+ addLineTo(FloatPoint(rect.x() + rect.width() - roundingRadii.width(), rect.y()));
- path.addBezierCurveTo(FloatPoint(x + width - dx * (1 - QUARTER), y), FloatPoint(x + width, y + dy * (1 - QUARTER)), FloatPoint(x + width, y + dy));
+ 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 (dy < height * 0.5)
- path.addLineTo(FloatPoint(x + width, y + height - dy));
+ if (radius.height() < halfSize.height())
+ addLineTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - radius.height()));
- path.addBezierCurveTo(FloatPoint(x + width, y + height - dy * (1 - QUARTER)), FloatPoint(x + width - dx * (1 - QUARTER), y + height), FloatPoint(x + width - dx, y + 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 (dx < width * 0.5)
- path.addLineTo(FloatPoint(x + dx, y + height));
+ if (radius.width() < halfSize.width())
+ addLineTo(FloatPoint(rect.x() + radius.width(), rect.y() + rect.height()));
- path.addBezierCurveTo(FloatPoint(x + dx * (1 - QUARTER), y + height), FloatPoint(x, y + height - dy * (1 - QUARTER)), FloatPoint(x, y + height - dy));
+ 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 (dy < height * 0.5)
- path.addLineTo(FloatPoint(x, y + dy));
+ if (radius.height() < halfSize.height())
+ addLineTo(FloatPoint(rect.x(), rect.y() + radius.height()));
- path.addBezierCurveTo(FloatPoint(x, y + dy * (1 - QUARTER)), FloatPoint(x + dx * (1 - QUARTER), y), FloatPoint(x + dx, y));
+ addBezierCurveTo(FloatPoint(rect.x(), rect.y() + radius.height() * gCircleControlPoint), FloatPoint(rect.x() + radius.width() * gCircleControlPoint, rect.y()), FloatPoint(rect.x() + radius.width(), rect.y()));
- path.closeSubpath();
-
- return path;
+ closeSubpath();
}
-Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius)
+void Path::addRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius)
{
- Path path;
-
- float width = rectangle.width();
- float height = rectangle.height();
- if (width <= 0.0 || height <= 0.0)
- return path;
+ if (rect.isEmpty())
+ return;
- if (width < topLeftRadius.width() + topRightRadius.width()
- || width < bottomLeftRadius.width() + bottomRightRadius.width()
- || height < topLeftRadius.height() + bottomLeftRadius.height()
- || height < topRightRadius.height() + bottomRightRadius.height())
+ 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.
- return createRectangle(rectangle);
-
- float x = rectangle.x();
- float y = rectangle.y();
-
- path.moveTo(FloatPoint(x + topLeftRadius.width(), y));
-
- path.addLineTo(FloatPoint(x + width - topRightRadius.width(), y));
-
- path.addBezierCurveTo(FloatPoint(x + width - topRightRadius.width() * (1 - QUARTER), y), FloatPoint(x + width, y + topRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width, y + topRightRadius.height()));
-
- path.addLineTo(FloatPoint(x + width, y + height - bottomRightRadius.height()));
-
- path.addBezierCurveTo(FloatPoint(x + width, y + height - bottomRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width - bottomRightRadius.width() * (1 - QUARTER), y + height), FloatPoint(x + width - bottomRightRadius.width(), y + height));
-
- path.addLineTo(FloatPoint(x + bottomLeftRadius.width(), y + height));
-
- path.addBezierCurveTo(FloatPoint(x + bottomLeftRadius.width() * (1 - QUARTER), y + height), FloatPoint(x, y + height - bottomLeftRadius.height() * (1 - QUARTER)), FloatPoint(x, y + height - bottomLeftRadius.height()));
-
- path.addLineTo(FloatPoint(x, y + topLeftRadius.height()));
-
- path.addBezierCurveTo(FloatPoint(x, y + topLeftRadius.height() * (1 - QUARTER)), FloatPoint(x + topLeftRadius.width() * (1 - QUARTER), y), FloatPoint(x + topLeftRadius.width(), y));
-
- path.closeSubpath();
-
- return path;
-}
-
-Path Path::createRectangle(const FloatRect& rectangle)
-{
- Path path;
- float x = rectangle.x();
- float y = rectangle.y();
- float width = rectangle.width();
- float height = rectangle.height();
- if (width <= 0.0f || height <= 0.0f)
- return path;
-
- path.moveTo(FloatPoint(x, y));
- path.addLineTo(FloatPoint(x + width, y));
- path.addLineTo(FloatPoint(x + width, y + height));
- path.addLineTo(FloatPoint(x, y + height));
- path.closeSubpath();
-
- return path;
-}
-
-Path Path::createEllipse(const FloatPoint& center, float rx, float ry)
-{
- float cx = center.x();
- float cy = center.y();
- Path path;
- if (rx <= 0.0f || ry <= 0.0f)
- return path;
-
- float x = cx;
- float y = cy;
-
- unsigned step = 0, num = 100;
- bool running = true;
- while (running)
- {
- if (step == num)
- {
- running = false;
- break;
- }
-
- float angle = static_cast<float>(step) / static_cast<float>(num) * 2.0f * piFloat;
- x = cx + cosf(angle) * rx;
- y = cy + sinf(angle) * ry;
-
- step++;
- if (step == 1)
- path.moveTo(FloatPoint(x, y));
- else
- path.addLineTo(FloatPoint(x, y));
+ addRect(rect);
+ return;
}
- path.closeSubpath();
-
- return path;
-}
-
-Path Path::createCircle(const FloatPoint& center, float r)
-{
- return createEllipse(center, r, r);
-}
-
-Path Path::createLine(const FloatPoint& start, const FloatPoint& end)
-{
- Path path;
-
- path.moveTo(start);
- path.addLineTo(end);
-
- return path;
+ 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/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h
index 43ba889..86ba831 100644
--- a/WebCore/platform/graphics/Path.h
+++ b/WebCore/platform/graphics/Path.h
@@ -137,20 +137,13 @@ namespace WebCore {
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&);
- String debugString() const;
-
PlatformPathPtr platformPath() const { return m_path; }
- static Path createRoundedRectangle(const FloatRect&, const FloatSize& roundingRadii);
- static Path createRoundedRectangle(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius);
- static Path createRectangle(const FloatRect&);
- static Path createEllipse(const FloatPoint& center, float rx, float ry);
- static Path createCircle(const FloatPoint& center, float r);
- static Path createLine(const FloatPoint&, const FloatPoint&);
-
void apply(void* info, PathApplierFunction) const;
void transform(const AffineTransform&);
diff --git a/WebCore/platform/graphics/brew/ImageBrew.cpp b/WebCore/platform/graphics/brew/ImageBrew.cpp
index f5c855d..b574b0a 100644
--- a/WebCore/platform/graphics/brew/ImageBrew.cpp
+++ b/WebCore/platform/graphics/brew/ImageBrew.cpp
@@ -36,13 +36,13 @@
#include "SharedBuffer.h"
#include <wtf/text/CString.h>
-#include <wtf/text/WTFString.h>
+#include <wtf/text/StringConcatenate.h>
namespace WebCore {
PassRefPtr<Image> Image::loadPlatformResource(const char *name)
{
- String resourcePath = homeDirectoryPath() + String::format("res/%s.png", name);
+ String resourcePath = makeString(homeDirectoryPath(), "res/", name, ".png");
RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(resourcePath.utf8().data());
if (!buffer)
diff --git a/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/WebCore/platform/graphics/cairo/CairoUtilities.cpp
index 8c2049f..7af5577 100644
--- a/WebCore/platform/graphics/cairo/CairoUtilities.cpp
+++ b/WebCore/platform/graphics/cairo/CairoUtilities.cpp
@@ -26,8 +26,15 @@
#include "config.h"
#include "CairoUtilities.h"
+#include "AffineTransform.h"
+#include "CairoPath.h"
#include "Color.h"
-#include <cairo.h>
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "OwnPtrCairo.h"
+#include "Path.h"
+#include "PlatformRefPtrCairo.h"
#include <wtf/Vector.h>
namespace WebCore {
@@ -56,4 +63,96 @@ void setSourceRGBAFromColor(cairo_t* context, const Color& color)
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);
+
+ PlatformRefPtr<cairo_surface_t> clippedImageSurface = 0;
+ if (tileRect.size() != imageSize) {
+ IntRect imageRect = enclosingIntRect(tileRect);
+ clippedImageSurface = adoptPlatformRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageRect.width(), imageRect.height()));
+ PlatformRefPtr<cairo_t> clippedImageContext(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/WebCore/platform/graphics/cairo/CairoUtilities.h b/WebCore/platform/graphics/cairo/CairoUtilities.h
index 0675b90..d8fff8d 100644
--- a/WebCore/platform/graphics/cairo/CairoUtilities.h
+++ b/WebCore/platform/graphics/cairo/CairoUtilities.h
@@ -26,13 +26,25 @@
#ifndef CairoUtilities_h
#define CairoUtilities_h
-typedef struct _cairo cairo_t;
+#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
diff --git a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
index 4b94cb3..8299b6a 100644
--- a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
@@ -29,10 +29,15 @@
#include "config.h"
#include "ContextShadow.h"
+#include "AffineTransform.h"
#include "CairoUtilities.h"
+#include "OwnPtrCairo.h"
+#include "Path.h"
#include "Timer.h"
#include <cairo.h>
+using WTF::max;
+
namespace WebCore {
static cairo_surface_t* scratchBuffer = 0;
@@ -105,10 +110,13 @@ void ContextShadow::endShadowLayer(cairo_t* cr)
cairo_destroy(m_layerContext);
m_layerContext = 0;
- if (m_type == BlurShadow)
+ 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_save(cr);
setSourceRGBAFromColor(cr, m_color);
@@ -119,4 +127,223 @@ void ContextShadow::endShadowLayer(cairo_t* cr)
scheduleScratchBufferPurge();
}
+void ContextShadow::drawRectShadowWithoutTiling(PlatformContext 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)
+{
+
+ // drawShadowedRect still does not work with rotations.
+ // https://bugs.webkit.org/show_bug.cgi?id=45042
+ float radiusTwice = m_blurDistance * 2;
+ cairo_t* cr = context->platformContext();
+ if ((!context->getCTM().isIdentityOrTranslationOrFlipped()) || (radiusTwice > rect.width())
+ || (radiusTwice > rect.height()) || (m_type != BlurShadow)) {
+ drawRectShadowWithoutTiling(cr, 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;
+
+ // Find the extra space needed from the curve of the corners.
+ int extraWidthFromCornerRadii = radiusTwice + max(topLeftRadius.width(), bottomLeftRadius.width()) +
+ radiusTwice + max(topRightRadius.width(), bottomRightRadius.width());
+ int extraHeightFromCornerRadii = radiusTwice + max(topLeftRadius.height(), topRightRadius.height()) +
+ radiusTwice + max(bottomLeftRadius.height(), bottomRightRadius.height());
+
+ // 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 + extraWidthFromCornerRadii,
+ sideTileWidth + extraHeightFromCornerRadii);
+
+ // 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(shadowRect, IntRect(x1, y1, x2 - x1, y2 - y1));
+
+ if ((shadowTemplateSize.width() * shadowTemplateSize.height() > m_layerRect.width() * m_layerRect.height())) {
+ drawRectShadowWithoutTiling(cr, 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/WebCore/platform/graphics/cairo/FloatRectCairo.cpp b/WebCore/platform/graphics/cairo/FloatRectCairo.cpp
new file mode 100644
index 0000000..9f86f74
--- /dev/null
+++ b/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/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp b/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp
index febad12..5dca010 100644
--- a/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp
+++ b/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp
@@ -87,12 +87,12 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne
{
}
-static CString getFamilyNameStringFromFontDescriptionAndFamily(const FontDescription& fontDescription, const AtomicString& family)
+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().utf8();
+ return family.string();
switch (fontDescription.genericFamily()) {
case FontDescription::StandardFamily:
@@ -112,23 +112,14 @@ static CString getFamilyNameStringFromFontDescriptionAndFamily(const FontDescrip
}
}
-
-static bool isFallbackFontAllowed(const CString& familyName)
-{
- return !strcasecmp(familyName.data(), "sans")
- || !strcasecmp(familyName.data(), "sans-serif")
- || !strcasecmp(familyName.data(), "serif")
- || !strcasecmp(familyName.data(), "monospace");
-}
-
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).
PlatformRefPtr<FcPattern> pattern = adoptPlatformRef(FcPatternCreate());
- CString familyNameString = getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family);
- if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.data())))
+ String familyNameString(getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family));
+ if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.utf8().data())))
return 0;
bool italic = fontDescription.italic();
@@ -140,53 +131,39 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize()))
return 0;
- // The following comment and strategy are originally from Skia (src/ports/SkFontHost_fontconfig.cpp):
- // Font matching:
- // CSS often specifies a fallback list of families:
- // font-family: a, b, c, serif;
- // However, fontconfig will always do its best to find *a* font when asked
- // for something so we need a way to tell if the match which it has found is
- // "good enough" for us. Otherwise, we can return null which gets piped up
- // and lets WebKit know to try the next CSS family name. However, fontconfig
- // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
- // wish to support that.
- //
- // Thus, if a specific family is requested we set @family_requested. Then we
- // record two strings: the family name after config processing and the
- // family name after resolving. If the two are equal, it's a good match.
- //
- // So consider the case where a user has mapped Arial to Helvetica in their
- // config.
- // requested family: "Arial"
- // post_config_family: "Helvetica"
- // post_match_family: "Helvetica"
- // -> good match
- //
- // and for a missing font:
- // requested family: "Monaco"
- // post_config_family: "Monaco"
- // post_match_family: "Times New Roman"
- // -> BAD match
- //
+ // 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* familyNameAfterConfiguration;
- FcPatternGetString(pattern.get(), FC_FAMILY, 0, &familyNameAfterConfiguration);
+ FcChar8* fontConfigFamilyNameAfterConfiguration;
+ FcPatternGetString(pattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration);
+ String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration));
FcResult fontConfigResult;
PlatformRefPtr<FcPattern> resultPattern = adoptPlatformRef(FcFontMatch(0, pattern.get(), &fontConfigResult));
if (!resultPattern) // No match.
return 0;
- // Properly handle the situation where Fontconfig gives us a font that has a different family than we requested.
- FcChar8* familyNameAfterMatching;
- FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &familyNameAfterMatching);
- if (strcasecmp(reinterpret_cast<char*>(familyNameAfterConfiguration),
- reinterpret_cast<char*>(familyNameAfterMatching)) && !isFallbackFontAllowed(familyNameString))
- return 0;
-
- return new FontPlatformData(resultPattern.get(), fontDescription);
+ FcChar8* fontConfigFamilyNameAfterMatching;
+ FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching);
+ String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching));
+ if (equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching))
+ return new FontPlatformData(resultPattern.get(), fontDescription);
+
+ // 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(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif")
+ || equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace")
+ || equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive"))
+ return new FontPlatformData(resultPattern.get(), fontDescription);
+
+ // Fontconfig did not return a good match.
+ return 0;
}
}
diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp
index cd5d362..3d55c70 100644
--- a/WebCore/platform/graphics/cairo/FontCairo.cpp
+++ b/WebCore/platform/graphics/cairo/FontCairo.cpp
@@ -31,6 +31,8 @@
#include "Font.h"
#include "AffineTransform.h"
+#include "CairoUtilities.h"
+#include "ContextShadow.h"
#include "GlyphBuffer.h"
#include "Gradient.h"
#include "GraphicsContext.h"
@@ -38,18 +40,63 @@
#include "Pattern.h"
#include "SimpleFontData.h"
-#define SYNTHETIC_OBLIQUE_ANGLE 14
-
namespace WebCore {
-void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
- int from, int numGlyphs, const FloatPoint& point) const
+static void prepareContextForGlyphDrawing(cairo_t* context, const SimpleFontData* font, const FloatPoint& point)
{
- cairo_t* cr = context->platformContext();
- cairo_save(cr);
+ 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());
+}
- cairo_set_scaled_font(cr, font->platformData().scaledFont());
+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() & cTextFill) || shadow->m_type == ContextShadow::NoShadow)
+ return;
+
+ if (shadow->m_type == ContextShadow::SolidShadow) {
+ // 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(context, fontExtentsRect);
+ if (shadowContext) {
+ prepareContextForGlyphDrawing(shadowContext, font, point);
+ drawGlyphsToContext(shadowContext, font, glyphs, numGlyphs);
+ shadow->endShadowLayer(context);
+ }
+}
+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;
@@ -59,75 +106,11 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
offset += glyphBuffer.advanceAt(from + i);
}
- Color fillColor = context->fillColor();
-
- // Synthetic Oblique
- if(font->platformData().syntheticOblique()) {
- cairo_matrix_t mat = {1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, point.x(), point.y()};
- cairo_transform(cr, &mat);
- } else {
- cairo_translate(cr, point.x(), point.y());
- }
-
- // Text shadow, inspired by FontMac
- FloatSize shadowOffset;
- float shadowBlur = 0;
- Color shadowColor;
- bool hasShadow = context->textDrawingMode() & cTextFill
- && context->getShadow(shadowOffset, shadowBlur, shadowColor);
-
- // TODO: Blur support
- if (hasShadow) {
- // Disable graphics context shadows (not yet implemented) and paint them manually
- context->clearShadow();
- Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
- cairo_save(cr);
-
- float red, green, blue, alpha;
- shadowFillColor.getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(cr, red, green, blue, alpha);
-
-#if ENABLE(FILTERS)
- cairo_text_extents_t extents;
- cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents);
-
- FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height));
- IntSize shadowBufferSize;
- FloatRect shadowRect;
- float radius = 0;
- context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowOffset, shadowBlur);
-
- // Draw shadow into a new ImageBuffer
- OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
- GraphicsContext* shadowContext = shadowBuffer->context();
- cairo_t* shadowCr = shadowContext->platformContext();
-
- cairo_translate(shadowCr, radius, extents.height + radius);
-
- cairo_set_scaled_font(shadowCr, font->platformData().scaledFont());
- cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
- if (font->syntheticBoldOffset()) {
- cairo_save(shadowCr);
- cairo_translate(shadowCr, font->syntheticBoldOffset(), 0);
- cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
- cairo_restore(shadowCr);
- }
- cairo_translate(cr, 0.0, -extents.height);
- context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
-#else
- cairo_translate(cr, shadowOffset.width(), shadowOffset.height());
- cairo_show_glyphs(cr, glyphs, numGlyphs);
- if (font->syntheticBoldOffset()) {
- cairo_save(cr);
- cairo_translate(cr, font->syntheticBoldOffset(), 0);
- cairo_show_glyphs(cr, glyphs, numGlyphs);
- cairo_restore(cr);
- }
-#endif
-
- cairo_restore(cr);
- }
+ cairo_t* cr = context->platformContext();
+ drawGlyphsShadow(context, cr, point, font, glyphs, numGlyphs);
+ cairo_save(cr);
+ prepareContextForGlyphDrawing(cr, font, point);
if (context->textDrawingMode() & cTextFill) {
if (context->fillGradient()) {
cairo_set_source(cr, context->fillGradient()->platformGradient());
@@ -148,16 +131,10 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
cairo_pattern_destroy(pattern);
} else {
float red, green, blue, alpha;
- fillColor.getRGBA(red, green, blue, alpha);
+ context->fillColor().getRGBA(red, green, blue, alpha);
cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
}
- cairo_show_glyphs(cr, glyphs, numGlyphs);
- if (font->syntheticBoldOffset()) {
- cairo_save(cr);
- cairo_translate(cr, font->syntheticBoldOffset(), 0);
- cairo_show_glyphs(cr, glyphs, numGlyphs);
- cairo_restore(cr);
- }
+ drawGlyphsToContext(cr, font, glyphs, numGlyphs);
}
// Prevent running into a long computation within cairo. If the stroke width is
@@ -183,20 +160,15 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
}
cairo_pattern_destroy(pattern);
} else {
- Color strokeColor = context->strokeColor();
float red, green, blue, alpha;
- strokeColor.getRGBA(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);
}
- // Re-enable the platform shadow we disabled earlier
- if (hasShadow)
- context->setShadow(shadowOffset, shadowBlur, shadowColor, DeviceColorSpace);
-
cairo_restore(cr);
}
diff --git a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp
index 0617e6c..ba307fa 100644
--- a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp
+++ b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp
@@ -75,40 +75,65 @@ void setCairoFontOptionsFromFontConfigPattern(cairo_font_options_t* options, FcP
FcBool booleanResult;
int integerResult;
- // We will determine if subpixel anti-aliasing is enabled via the FC_RGBA setting.
- if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &booleanResult) == FcResultMatch && booleanResult)
- cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
-
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);
- cairo_font_options_set_subpixel_order(options, convertFontConfigSubpixelOrder(integerResult));
+ }
+
+ 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)
{
- cairo_font_options_t* options = cairo_font_options_create();
- setCairoFontOptionsFromFontConfigPattern(options, pattern);
+ PlatformRefPtr<cairo_font_face_t> fontFace = adoptPlatformRef(cairo_ft_font_face_create_for_pattern(m_pattern.get()));
+ initializeWithFontFace(fontFace.get());
- cairo_matrix_t fontMatrix;
- cairo_matrix_init_scale(&fontMatrix, m_size, m_size);
- cairo_matrix_t ctm;
- cairo_matrix_init_identity(&ctm);
+ int spacing;
+ if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing) == FcResultMatch && spacing == FC_MONO)
+ m_fixedWidth = true;
- PlatformRefPtr<cairo_font_face_t> fontFace = adoptPlatformRef(cairo_ft_font_face_create_for_pattern(m_pattern.get()));
- m_scaledFont = adoptPlatformRef(cairo_scaled_font_create(fontFace.get(), &fontMatrix, &ctm, options));
+ 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)
@@ -116,7 +141,9 @@ FontPlatformData::FontPlatformData(float size, bool bold, bool italic)
, m_size(size)
, m_syntheticBold(bold)
, m_syntheticOblique(italic)
+ , m_fixedWidth(false)
{
+ // We cannot create a scaled font here.
}
FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic)
@@ -125,24 +152,13 @@ FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool
, m_syntheticBold(bold)
, m_syntheticOblique(italic)
{
- cairo_matrix_t fontMatrix;
- cairo_matrix_init_scale(&fontMatrix, size, size);
- cairo_matrix_t ctm;
- cairo_matrix_init_identity(&ctm);
- static const cairo_font_options_t* defaultOptions = cairo_font_options_create();
- const cairo_font_options_t* options = NULL;
-
-#if !PLATFORM(EFL) || ENABLE(GLIB_SUPPORT)
- if (GdkScreen* screen = gdk_screen_get_default())
- options = gdk_screen_get_font_options(screen);
-#endif
-
- // gdk_screen_get_font_options() returns NULL if no default options are
- // set, so we always have to check.
- if (!options)
- options = defaultOptions;
+ initializeWithFontFace(fontFace);
- m_scaledFont = adoptPlatformRef(cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options));
+ FT_Face fontConfigFace = cairo_ft_scaled_font_lock_face(m_scaledFont.get());
+ if (fontConfigFace) {
+ m_fixedWidth = fontConfigFace->face_flags & FT_FACE_FLAG_FIXED_WIDTH;
+ cairo_ft_scaled_font_unlock_face(m_scaledFont.get());
+ }
}
FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
@@ -154,6 +170,7 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
m_size = other.m_size;
m_syntheticBold = other.m_syntheticBold;
m_syntheticOblique = other.m_syntheticOblique;
+ m_fixedWidth = other.m_fixedWidth;
m_scaledFont = other.m_scaledFont;
m_pattern = other.m_pattern;
@@ -172,6 +189,16 @@ FontPlatformData::FontPlatformData(const FontPlatformData& other)
*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.get()));
+}
+
FontPlatformData::~FontPlatformData()
{
if (m_fallbacks) {
@@ -182,14 +209,7 @@ FontPlatformData::~FontPlatformData()
bool FontPlatformData::isFixedPitch()
{
- // TODO: Support isFixedPitch() for custom fonts.
- if (!m_pattern)
- return false;
-
- int spacing;
- if (FcPatternGetInteger(m_pattern.get(), FC_SPACING, 0, &spacing) == FcResultMatch)
- return spacing == FC_MONO;
- return false;
+ return m_fixedWidth;
}
bool FontPlatformData::operator==(const FontPlatformData& other) const
@@ -208,4 +228,37 @@ String FontPlatformData::description() const
}
#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 = adoptPlatformRef(cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options));
+ cairo_font_options_destroy(options);
+}
+
+
}
diff --git a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h
index f3488ef..7d3ff99 100644
--- a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h
+++ b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h
@@ -57,6 +57,7 @@ public:
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();
@@ -89,7 +90,11 @@ public:
float m_size;
bool m_syntheticBold;
bool m_syntheticOblique;
+ bool m_fixedWidth;
PlatformRefPtr<cairo_scaled_font_t> m_scaledFont;
+
+private:
+ void initializeWithFontFace(cairo_font_face_t*);
};
}
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index 05096a9..0847da1 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -36,20 +36,18 @@
#include "AffineTransform.h"
#include "CairoPath.h"
#include "CairoUtilities.h"
-#include "FEGaussianBlur.h"
+#include "ContextShadow.h"
#include "FloatRect.h"
#include "Font.h"
+#include "GraphicsContextPlatformPrivateCairo.h"
+#include "GraphicsContextPrivate.h"
#include "OwnPtrCairo.h"
-#include "ImageBuffer.h"
-#include "ImageBufferFilter.h"
#include "IntRect.h"
#include "NotImplemented.h"
#include "Path.h"
#include "Pattern.h"
#include "PlatformRefPtrCairo.h"
#include "SimpleFontData.h"
-#include "SourceGraphic.h"
-
#include <cairo.h>
#include <math.h>
#include <stdio.h>
@@ -61,8 +59,6 @@
#elif PLATFORM(WIN)
#include <cairo-win32.h>
#endif
-#include "GraphicsContextPlatformPrivateCairo.h"
-#include "GraphicsContextPrivate.h"
using namespace std;
@@ -132,26 +128,6 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const
cairo_fill(cr);
}
-static void appendPathToCairoContext(cairo_t* to, cairo_t* from)
-{
- OwnPtr<cairo_path_t> cairoPath(cairo_copy_path(from));
- cairo_append_path(to, cairoPath.get());
-}
-
-// We apply the pending path built via addPath to the Cairo context
-// lazily. This prevents interaction between the path and other routines
-// such as fillRect.
-static void setPathOnCairoContext(cairo_t* to, cairo_t* from)
-{
- cairo_new_path(to);
- appendPathToCairoContext(to, from);
-}
-
-static void appendWebCorePathToCairoContext(cairo_t* context, const Path& path)
-{
- appendPathToCairoContext(context, path.platformPath()->context());
-}
-
static void addConvexPolygonToContext(cairo_t* context, size_t numPoints, const FloatPoint* points)
{
cairo_move_to(context, points[0].x(), points[0].y());
@@ -160,83 +136,59 @@ static void addConvexPolygonToContext(cairo_t* context, size_t numPoints, const
cairo_close_path(context);
}
-void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& radius, const FloatRect& sourceRect, const FloatSize& shadowOffset, float shadowBlur)
-{
-#if ENABLE(FILTERS)
- // limit radius to 128
- radius = min(128.f, max(shadowBlur, 0.f));
-
- shadowBufferSize = IntSize(sourceRect.width() + radius * 2, sourceRect.height() + radius * 2);
+enum PathDrawingStyle {
+ Fill = 1,
+ Stroke = 2,
+ FillAndStroke = Fill + Stroke
+};
- // determine dimensions of shadow rect
- shadowRect = FloatRect(sourceRect.location(), shadowBufferSize);
- shadowRect.move(shadowOffset.width() - radius, shadowOffset.height() - radius);
-#endif
-}
-
-static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPrivate* gcp, bool fillShadow, bool strokeShadow)
+static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPrivate* contextPrivate, PathDrawingStyle drawingStyle)
{
-#if ENABLE(FILTERS)
- FloatSize shadowOffset;
- float shadowBlur;
- Color shadowColor;
- if (!context->getShadow(shadowOffset, shadowBlur, shadowColor))
+ ContextShadow* shadow = context->contextShadow();
+ ASSERT(shadow);
+ if (shadow->m_type == ContextShadow::NoShadow)
return;
-
- // Calculate filter values to create appropriate shadow.
- cairo_t* cr = context->platformContext();
- double x0, x1, y0, y1;
- if (strokeShadow)
- cairo_stroke_extents(cr, &x0, &y0, &x1, &y1);
- else
- cairo_fill_extents(cr, &x0, &y0, &x1, &y1);
- FloatRect rect(x0, y0, x1 - x0, y1 - y0);
-
- IntSize shadowBufferSize;
- FloatRect shadowRect;
- float radius = 0;
- GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowOffset, shadowBlur);
-
- cairo_clip_extents(cr, &x0, &y0, &x1, &y1);
- FloatRect clipRect(x0, y0, x1 - x0, y1 - y0);
-
- FloatPoint rectLocation = shadowRect.location();
-
- // Reduce the shadow rect using the clip area.
- if (!clipRect.contains(shadowRect)) {
- shadowRect.intersect(clipRect);
- if (shadowRect.isEmpty())
- return;
- shadowRect.inflate(radius);
- shadowBufferSize = IntSize(shadowRect.width(), shadowRect.height());
- }
- shadowOffset = rectLocation - shadowRect.location();
+ // Calculate the extents of the rendered solid paths.
+ cairo_t* cairoContext = context->platformContext();
+ 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);
+ }
- // Create suitably-sized ImageBuffer to hold the shadow.
- OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
+ cairo_t* shadowContext = shadow->beginShadowLayer(cairoContext, solidFigureExtents);
+ if (!shadowContext)
+ return;
- // Draw shadow into a new ImageBuffer.
- cairo_t* shadowContext = shadowBuffer->context()->platformContext();
- copyContextProperties(cr, shadowContext);
- cairo_translate(shadowContext, -rect.x() + radius + shadowOffset.width(), -rect.y() + radius + shadowOffset.height());
- cairo_new_path(shadowContext);
- OwnPtr<cairo_path_t> path(cairo_copy_path(cr));
- cairo_append_path(shadowContext, path.get());
+ // 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);
- if (fillShadow)
- setPlatformFill(context, shadowContext, gcp);
- if (strokeShadow)
- setPlatformStroke(context, shadowContext, gcp);
+ if (drawingStyle & Fill)
+ setPlatformFill(context, shadowContext, contextPrivate);
+ if (drawingStyle & Stroke)
+ setPlatformStroke(context, shadowContext, contextPrivate);
- context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
-#endif
+ shadow->endShadowLayer(cairoContext);
}
static void fillCurrentCairoPath(GraphicsContext* context, GraphicsContextPrivate* gcp, cairo_t* cairoContext)
{
cairo_set_fill_rule(cairoContext, context->fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
- drawPathShadow(context, gcp, true, false);
+ drawPathShadow(context, gcp, Fill);
setPlatformFill(context, cairoContext, gcp);
cairo_new_path(cairoContext);
@@ -244,7 +196,7 @@ static void fillCurrentCairoPath(GraphicsContext* context, GraphicsContextPrivat
static void strokeCurrentCairoPath(GraphicsContext* context, GraphicsContextPrivate* gcp, cairo_t* cairoContext)
{
- drawPathShadow(context, gcp, false, true);
+ drawPathShadow(context, gcp, Stroke);
setPlatformStroke(context, cairoContext, gcp);
cairo_new_path(cairoContext);
}
@@ -281,12 +233,20 @@ 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.
@@ -602,7 +562,7 @@ void GraphicsContext::drawPath()
setPathOnCairoContext(cr, m_data->m_pendingPath.context());
cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
- drawPathShadow(this, m_common, true, true);
+ drawPathShadow(this, m_common, FillAndStroke);
setPlatformFill(this, cr, m_common);
setPlatformStroke(this, cr, m_common);
@@ -621,49 +581,14 @@ void GraphicsContext::fillRect(const FloatRect& rect)
cairo_restore(cr);
}
-static void drawBorderlessRectShadow(GraphicsContext* context, const FloatRect& rect, const Color& rectColor)
-{
-#if ENABLE(FILTERS)
- FloatSize shadowOffset;
- float shadowBlur;
- Color shadowColor;
- if (!context->getShadow(shadowOffset, shadowBlur, shadowColor))
- return;
-
- AffineTransform transform = context->getCTM();
- // drawTiledShadow still does not work with rotations.
- if ((transform.isIdentityOrTranslationOrFlipped())) {
- cairo_t* cr = context->platformContext();
- cairo_save(cr);
- appendWebCorePathToCairoContext(cr, Path::createRectangle(rect));
- FloatSize corner;
- IntRect shadowRect(rect);
- context->drawTiledShadow(shadowRect, corner, corner, corner, corner, DeviceColorSpace);
- cairo_restore(cr);
-
- return;
- }
-
- IntSize shadowBufferSize;
- FloatRect shadowRect;
- float radius = 0;
- GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowOffset, shadowBlur);
-
- // Draw shadow into a new ImageBuffer
- OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
- GraphicsContext* shadowContext = shadowBuffer->context();
- shadowContext->fillRect(FloatRect(FloatPoint(radius, radius), rect.size()), rectColor, DeviceColorSpace);
-
- context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
-#endif
-}
-
-void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace)
{
if (paintingDisabled())
return;
- drawBorderlessRectShadow(this, rect, color);
+ if (m_data->hasShadow())
+ m_data->shadow.drawRectShadow(this, enclosingIntRect(rect));
+
if (color.alpha())
fillRectSourceOver(m_data->cr, rect, color);
}
@@ -737,8 +662,13 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int
setPlatformStrokeStyle(DottedStroke);
#else
int radius = (width - 1) / 2;
- for (unsigned i = 0; i < rectCount; i++)
- appendWebCorePathToCairoContext(cr, Path::createRoundedRectangle(rects[i], FloatSize(radius, radius)));
+ Path path;
+ for (unsigned i = 0; i < rectCount; ++i) {
+ if (i > 0)
+ path.clear();
+ path.addRoundedRect(rects[i], FloatSize(radius, radius));
+ appendWebCorePathToCairoContext(cr, path);
+ }
// Force the alpha to 50%. This matches what the Mac does with outline rings.
Color ringColor(color.red(), color.green(), color.blue(), 127);
@@ -928,57 +858,26 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness
cairo_set_fill_rule(cr, savedFillRule);
}
-void GraphicsContext::setPlatformShadow(FloatSize const& size, float, Color const&, ColorSpace)
+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
-
+ // Cairo doesn't support shadows natively, they are drawn manually in the draw* functions
if (m_common->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_common->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()));
}
-void GraphicsContext::applyPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float radius)
+ContextShadow* GraphicsContext::contextShadow()
{
-#if ENABLE(FILTERS)
- setColor(m_data->cr, shadowColor);
- PlatformRefPtr<cairo_surface_t> shadowMask(createShadowMask(buffer, shadowRect, radius));
- cairo_mask_surface(m_data->cr, shadowMask.get(), shadowRect.x(), shadowRect.y());
-#endif
-}
-
-PlatformRefPtr<cairo_surface_t> GraphicsContext::createShadowMask(PassOwnPtr<ImageBuffer> buffer, const FloatRect& shadowRect, float radius)
-{
-#if ENABLE(FILTERS)
- if (!radius)
- return buffer->m_data.m_surface;
-
- FloatPoint blurRadius = FloatPoint(radius, radius);
- float stdDeviation = FEGaussianBlur::calculateStdDeviation(radius);
- if (!stdDeviation)
- return buffer->m_data.m_surface;
-
- // create filter
- RefPtr<Filter> filter = ImageBufferFilter::create();
- filter->setSourceImage(buffer);
- RefPtr<FilterEffect> source = SourceGraphic::create();
- source->setRepaintRectInLocalCoordinates(FloatRect(FloatPoint(), shadowRect.size()));
- source->setIsAlphaImage(true);
- RefPtr<FilterEffect> blur = FEGaussianBlur::create(stdDeviation, stdDeviation);
- FilterEffectVector& inputEffects = blur->inputEffects();
- inputEffects.append(source.get());
- blur->setRepaintRectInLocalCoordinates(FloatRect(FloatPoint(), shadowRect.size()));
- blur->apply(filter.get());
- return blur->resultImage()->m_data.m_surface;
-#endif
+ return &m_data->shadow;
}
-
void GraphicsContext::clearPlatformShadow()
{
- notImplemented();
+ m_data->shadow.clear();
}
void GraphicsContext::beginTransparencyLayer(float opacity)
@@ -1095,43 +994,6 @@ float GraphicsContext::getAlpha()
return m_common->state.globalAlpha;
}
-static inline 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 GraphicsContext::setCompositeOperation(CompositeOperator op)
{
if (paintingDisabled())
@@ -1248,206 +1110,20 @@ static inline FloatPoint getPhase(const FloatRect& dest, const FloatRect& tile)
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 minimum rectangle size required to create the
- tiles
-
- 2. If that size is smaller than the real rectangle render the new
- small 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 small 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 GraphicsContext::drawTiledShadow(const IntRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius, ColorSpace colorSpace)
-{
-#if ENABLE(FILTERS)
- FloatSize shadowSize;
- float shadowBlur;
- Color shadowColor;
- if (!getShadow(shadowSize, shadowBlur, shadowColor))
- return;
-
- // Calculate filter values to create appropriate shadow.
- cairo_t* cr = m_data->cr;
-
- IntSize shadowBufferSize;
- FloatRect shadowRect;
- float blurRadius = 0;
- GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, blurRadius, rect, shadowSize, shadowBlur);
-
- // Size of the tiling side.
- int sideTileWidth = 1;
- float radiusTwice = blurRadius * 2;
-
- // Find the extra space needed from the curve of the corners.
- int extraWidthFromCornerRadii = radiusTwice + max(topLeftRadius.width(), bottomLeftRadius.width()) +
- radiusTwice + max(topRightRadius.width(), bottomRightRadius.width());
- int extraHeightFromCornerRadii = radiusTwice + max(topLeftRadius.height(), topRightRadius.height()) +
- radiusTwice + max(bottomLeftRadius.height(), bottomRightRadius.height());
-
- // 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 smallBufferSize = IntSize(sideTileWidth + extraWidthFromCornerRadii,
- sideTileWidth + extraHeightFromCornerRadii);
-
- if ((smallBufferSize.width() > shadowBufferSize.width()) || (smallBufferSize.height() > shadowBufferSize.height()) || (blurRadius <= 0)) {
- // Create suitably-sized ImageBuffer to hold the shadow.
- OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
- if (!shadowBuffer)
- return;
-
- // Draw shadow into a new ImageBuffer.
- cairo_t* shadowContext = shadowBuffer->context()->platformContext();
- copyContextProperties(cr, shadowContext);
- cairo_translate(shadowContext, -rect.x() + blurRadius, -rect.y() + blurRadius);
- cairo_new_path(shadowContext);
- OwnPtr<cairo_path_t> path(cairo_copy_path(cr));
- cairo_append_path(shadowContext, path.get());
-
- setPlatformFill(this, shadowContext, m_common);
-
- applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, blurRadius);
-
- return;
- }
-
- OwnPtr<ImageBuffer> smallBuffer = ImageBuffer::create(smallBufferSize);
- if (!smallBuffer)
- return;
-
- IntRect smallRect = IntRect(blurRadius, blurRadius, smallBufferSize.width() - radiusTwice, smallBufferSize.height() - radiusTwice);
-
- // Draw shadow into a new ImageBuffer.
- cairo_t* smallBufferContext = smallBuffer->context()->platformContext();
- copyContextProperties(cr, smallBufferContext);
- appendWebCorePathToCairoContext(smallBuffer->context()->platformContext(), Path::createRoundedRectangle(smallRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius));
- setPlatformFill(this, smallBufferContext, m_common);
-
- OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(smallBufferSize);
- if (!shadowBuffer)
- return;
-
- smallRect.setSize(smallBufferSize);
-
- PlatformRefPtr<cairo_surface_t> shadowMask(createShadowMask(smallBuffer.release(), smallRect, blurRadius));
-
- cairo_t* shadowContext = shadowBuffer->context()->platformContext();
- setColor(shadowContext, shadowColor);
- cairo_mask_surface(shadowContext, shadowMask.get(), 0, 0);
-
- // Fill the internal part of the shadow.
- shadowRect.inflate(-radiusTwice);
- if (!shadowRect.isEmpty()) {
- cairo_save(cr);
- appendWebCorePathToCairoContext(cr, Path::createRoundedRectangle(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius));
- setColor(cr, shadowColor);
- 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() - blurRadius * 4);
- FloatPoint phase = getPhase(destRect, tileRect);
- AffineTransform patternTransform;
- patternTransform.makeIdentity();
- shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect);
-
- // Draw the bottom side.
- tileRect = FloatRect(radiusTwice + bottomLeftRadius.width(), smallBufferSize.height() - radiusTwice, sideTileWidth, radiusTwice);
- destRect = tileRect;
- destRect.move(shadowRect.x(), shadowRect.y() + radiusTwice + rect.height() - smallBufferSize.height());
- destRect.setWidth(shadowRect.width() - bottomLeftRadius.width() - bottomRightRadius.width() - blurRadius * 4);
- phase = getPhase(destRect, tileRect);
- shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect);
-
- // Draw the right side.
- tileRect = FloatRect(smallBufferSize.width() - radiusTwice, radiusTwice + topRightRadius.height(), radiusTwice, sideTileWidth);
- destRect = tileRect;
- destRect.move(shadowRect.x() + radiusTwice + rect.width() - smallBufferSize.width(), shadowRect.y());
- destRect.setHeight(shadowRect.height() - topRightRadius.height() - bottomRightRadius.height() - blurRadius * 4);
- phase = getPhase(destRect, tileRect);
- shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, 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() - blurRadius * 4);
- phase = FloatPoint(destRect.x() - tileRect.x(), destRect.y() - tileRect.y());
- shadowBuffer->drawPattern(this, tileRect, patternTransform,
- phase, colorSpace, CompositeSourceOver, 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);
- shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect);
-
- // Draw the top right corner.
- tileRect = FloatRect(smallBufferSize.width() - radiusTwice - topRightRadius.width(), 0, radiusTwice + topRightRadius.width(), radiusTwice + topRightRadius.height());
- destRect = tileRect;
- destRect.move(shadowRect.x() + rect.width() - smallBufferSize.width() + radiusTwice, shadowRect.y());
- phase = getPhase(destRect, tileRect);
- shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect);
-
- // Draw the bottom right corner.
- tileRect = FloatRect(smallBufferSize.width() - radiusTwice - bottomRightRadius.width(), smallBufferSize.height() - radiusTwice - bottomRightRadius.height(), radiusTwice + bottomRightRadius.width(), radiusTwice + bottomRightRadius.height());
- destRect = tileRect;
- destRect.move(shadowRect.x() + rect.width() - smallBufferSize.width() + radiusTwice, shadowRect.y() + rect.height() - smallBufferSize.height() + radiusTwice);
- phase = getPhase(destRect, tileRect);
- shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect);
-
- // Draw the bottom left corner.
- tileRect = FloatRect(0, smallBufferSize.height() - radiusTwice - bottomLeftRadius.height(), radiusTwice + bottomLeftRadius.width(), radiusTwice + bottomLeftRadius.height());
- destRect = tileRect;
- destRect.move(shadowRect.x(), shadowRect.y() + rect.height() - smallBufferSize.height() + radiusTwice);
- phase = getPhase(destRect, tileRect);
- shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect);
-#endif
-}
-
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 (m_data->hasShadow())
+ m_data->shadow.drawRectShadow(this, r, topLeft, topRight, bottomLeft, bottomRight);
+
cairo_t* cr = m_data->cr;
cairo_save(cr);
- appendWebCorePathToCairoContext(cr, Path::createRoundedRectangle(r, topLeft, topRight, bottomLeft, bottomRight));
+ Path path;
+ path.addRoundedRect(r, topLeft, topRight, bottomLeft, bottomRight);
+ appendWebCorePathToCairoContext(cr, path);
setColor(cr, color);
- AffineTransform transform = this->getCTM();
- // drawTiledShadow still does not work with rotations.
- if (transform.isIdentityOrTranslationOrFlipped())
- drawTiledShadow(r, topLeft, topRight, bottomLeft, bottomRight, colorSpace);
- else
- drawPathShadow(this, m_common, true, false);
cairo_fill(cr);
cairo_restore(cr);
}
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
index 81987ef..527cb72 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
+++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -28,6 +28,7 @@
#include "GraphicsContext.h"
#include "CairoPath.h"
+#include "ContextShadow.h"
#include <cairo.h>
#include <math.h>
#include <stdio.h>
@@ -98,6 +99,10 @@ public:
Vector<float> layers;
CairoPath m_pendingPath;
+ ContextShadow shadow;
+ Vector<ContextShadow> shadowStack;
+ bool hasShadow() const { return shadow.m_type != ContextShadow::NoShadow; }
+
#if PLATFORM(GTK)
GdkEventExpose* expose;
#elif PLATFORM(WIN)
diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index 976dcb4..d452c3a 100644
--- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -69,7 +69,7 @@ ImageBufferData::ImageBufferData(const IntSize& size)
{
}
-ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, bool& success)
: m_data(size)
, m_size(size)
{
diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp
index 904e819..8f7a194 100644
--- a/WebCore/platform/graphics/cairo/ImageCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp
@@ -31,7 +31,9 @@
#if PLATFORM(CAIRO)
#include "AffineTransform.h"
+#include "CairoUtilities.h"
#include "Color.h"
+#include "ContextShadow.h"
#include "FloatRect.h"
#include "PlatformRefPtrCairo.h"
#include "GraphicsContext.h"
@@ -133,29 +135,18 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo
cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() };
cairo_pattern_set_matrix(pattern, &matrix);
- // Draw the shadow
-#if ENABLE(FILTERS)
- FloatSize shadowOffset;
- float shadowBlur;
- Color shadowColor;
- if (context->getShadow(shadowOffset, shadowBlur, shadowColor)) {
- IntSize shadowBufferSize;
- FloatRect shadowRect;
- float radius = 0;
- context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, dstRect, shadowOffset, shadowBlur);
- shadowColor = colorWithOverrideAlpha(shadowColor.rgb(), (shadowColor.alpha() * context->getAlpha()) / 255.f);
-
- //draw shadow into a new ImageBuffer
- OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
- cairo_t* shadowContext = shadowBuffer->context()->platformContext();
- cairo_set_source(shadowContext, pattern);
- cairo_translate(shadowContext, -dstRect.x(), -dstRect.y());
- cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height());
- cairo_fill(shadowContext);
-
- context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
+ ContextShadow* shadow = context->contextShadow();
+ ASSERT(shadow);
+ if (shadow->m_type != ContextShadow::NoShadow) {
+ cairo_t* shadowContext = shadow->beginShadowLayer(cr, 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(cr);
+ }
}
-#endif
// Draw the image.
cairo_translate(cr, dstRect.x(), dstRect.y());
@@ -172,46 +163,15 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo
}
void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform,
- const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect)
+ 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;
- // Avoid NaN
- if (!isfinite(phase.x()) || !isfinite(phase.y()))
- return;
-
cairo_t* cr = context->platformContext();
- context->save();
-
- PlatformRefPtr<cairo_surface_t> clippedImageSurface = 0;
- if (tileRect.size() != size()) {
- IntRect imageSize = enclosingIntRect(tileRect);
- clippedImageSurface = adoptPlatformRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageSize.width(), imageSize.height()));
- PlatformRefPtr<cairo_t> clippedImageContext(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 pattern_matrix = cairo_matrix_t(patternTransform);
- cairo_matrix_t phase_matrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()};
- cairo_matrix_t combined;
- cairo_matrix_multiply(&combined, &pattern_matrix, &phase_matrix);
- cairo_matrix_invert(&combined);
- cairo_pattern_set_matrix(pattern, &combined);
-
- context->setCompositeOperation(op);
- cairo_set_source(cr, pattern);
- cairo_pattern_destroy(pattern);
- cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height());
- cairo_fill(cr);
-
- context->restore();
+ drawPatternToCairoContext(cr, image, size(), tileRect, patternTransform, phase, toCairoOperator(op), destRect);
if (imageObserver())
imageObserver()->didDraw(this);
diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp
index 776bceb..d5045be 100644
--- a/WebCore/platform/graphics/cairo/PathCairo.cpp
+++ b/WebCore/platform/graphics/cairo/PathCairo.cpp
@@ -337,40 +337,4 @@ void Path::transform(const AffineTransform& trans)
cairo_transform(cr, &c_matrix);
}
-String Path::debugString() const
-{
- if (isEmpty())
- return String();
-
- String pathString;
- OwnPtr<cairo_path_t> path(cairo_copy_path(platformPath()->context()));
- cairo_path_data_t* data;
-
- 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:
- if (i < (path->num_data - path->data[i].header.length))
- pathString += String::format("M%.2f,%.2f ",
- data[1].point.x, data[1].point.y);
- break;
- case CAIRO_PATH_LINE_TO:
- pathString += String::format("L%.2f,%.2f ",
- data[1].point.x, data[1].point.y);
- break;
- case CAIRO_PATH_CURVE_TO:
- pathString += String::format("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f ",
- data[1].point.x, data[1].point.y,
- data[2].point.x, data[2].point.y,
- data[3].point.x, data[3].point.y);
- break;
- case CAIRO_PATH_CLOSE_PATH:
- pathString += "Z ";
- break;
- }
- }
-
- return pathString.simplifyWhiteSpace();
-}
-
} // namespace WebCore
diff --git a/WebCore/platform/graphics/cg/ColorCG.cpp b/WebCore/platform/graphics/cg/ColorCG.cpp
index 6f05c38..c9b05da 100644
--- a/WebCore/platform/graphics/cg/ColorCG.cpp
+++ b/WebCore/platform/graphics/cg/ColorCG.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * 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
@@ -28,6 +28,7 @@
#if PLATFORM(CG)
+#include "GraphicsContextCG.h"
#include <wtf/Assertions.h>
#include <wtf/RetainPtr.h>
#include <ApplicationServices/ApplicationServices.h>
@@ -69,37 +70,79 @@ Color::Color(CGColorRef color)
m_valid = true;
}
-#if OS(WINDOWS)
+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();
+}
-CGColorRef createCGColor(const Color& c)
+static CGColorRef leakCGColor(const Color& color, ColorSpace colorSpace)
{
- CGColorRef color = NULL;
-#ifdef OBSOLETE_COLORSYNC_API
- CMProfileRef prof = NULL;
- CMGetSystemProfile(&prof);
- RetainPtr<CGColorSpaceRef> rgbSpace(AdoptCF, CGColorSpaceCreateWithPlatformColorSpace(prof));
-#else
- ColorSyncProfileRef prof = ColorSyncProfileCreateWithDisplayID(0);
- RetainPtr<CGColorSpaceRef> rgbSpace(AdoptCF, CGColorSpaceCreateWithPlatformColorSpace(const_cast<void*>(reinterpret_cast<const void*>(prof))));
-#endif
-
- if (rgbSpace) {
- CGFloat components[4] = { static_cast<CGFloat>(c.red()) / 255, static_cast<CGFloat>(c.green()) / 255,
- static_cast<CGFloat>(c.blue()) / 255, static_cast<CGFloat>(c.alpha()) / 255 };
- color = CGColorCreate(rgbSpace.get(), components);
+ 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;
+ }
}
-#ifdef OBSOLETE_COLORSYNC_API
- CMCloseProfile(prof);
-#else
- if (prof)
- CFRelease(prof);
-#endif
+ ASSERT(color.rgb());
- return color;
+ 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;
}
-#endif // OS(WINDOWS)
+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);
+}
}
diff --git a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
index 2a81fd2..fe4fc7f 100644
--- a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
@@ -64,9 +64,35 @@ bool GraphicsContext3D::getImageData(Image* image,
return false;
size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
- if (!width || !height || CGImageGetBitsPerComponent(cgImage) != 8)
+ if (!width || !height)
return false;
- size_t componentsPerPixel = CGImageGetBitsPerPixel(cgImage) / 8;
+ 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;
+ bool srcByteOrder16Big = false;
+ if (bitsPerComponent == 16) {
+ CGBitmapInfo bitInfo = CGImageGetBitmapInfo(cgImage);
+ switch (bitInfo & kCGBitmapByteOrderMask) {
+ case kCGBitmapByteOrder16Big:
+ srcByteOrder16Big = true;
+ break;
+ case kCGBitmapByteOrder16Little:
+ srcByteOrder16Big = 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.
+ srcByteOrder16Big = true;
+ break;
+ default:
+ return false;
+ }
+ }
SourceDataFormat srcDataFormat = kSourceFormatRGBA8;
AlphaOp neededAlphaOp = kAlphaDoNothing;
switch (CGImageGetAlphaInfo(cgImage)) {
@@ -79,10 +105,16 @@ bool GraphicsContext3D::getImageData(Image* image,
neededAlphaOp = kAlphaDoUnmultiply;
switch (componentsPerPixel) {
case 2:
- srcDataFormat = kSourceFormatAR8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatAR8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatAR16Big : kSourceFormatAR16Little;
break;
case 4:
- srcDataFormat = kSourceFormatARGB8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatARGB8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatARGB16Big : kSourceFormatARGB16Little;
break;
default:
return false;
@@ -94,13 +126,22 @@ bool GraphicsContext3D::getImageData(Image* image,
neededAlphaOp = kAlphaDoPremultiply;
switch (componentsPerPixel) {
case 1:
- srcDataFormat = kSourceFormatA8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatA8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatA16Big : kSourceFormatA16Little;
break;
case 2:
- srcDataFormat = kSourceFormatAR8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatAR8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatAR16Big : kSourceFormatAR16Little;
break;
case 4:
- srcDataFormat = kSourceFormatARGB8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatARGB8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatARGB16Big : kSourceFormatARGB16Little;
break;
default:
return false;
@@ -110,10 +151,16 @@ bool GraphicsContext3D::getImageData(Image* image,
// This path is only accessible for MacOS earlier than 10.6.4.
switch (componentsPerPixel) {
case 2:
- srcDataFormat = kSourceFormatAR8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatAR8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatAR16Big : kSourceFormatAR16Little;
break;
case 4:
- srcDataFormat = kSourceFormatARGB8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatARGB8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatARGB16Big : kSourceFormatARGB16Little;
break;
default:
return false;
@@ -127,10 +174,16 @@ bool GraphicsContext3D::getImageData(Image* image,
neededAlphaOp = kAlphaDoUnmultiply;
switch (componentsPerPixel) {
case 2:
- srcDataFormat = kSourceFormatRA8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatRA8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatRA16Big : kSourceFormatRA16Little;
break;
case 4:
- srcDataFormat = kSourceFormatRGBA8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatRGBA8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatRGBA16Big : kSourceFormatRGBA16Little;
break;
default:
return false;
@@ -141,13 +194,22 @@ bool GraphicsContext3D::getImageData(Image* image,
neededAlphaOp = kAlphaDoPremultiply;
switch (componentsPerPixel) {
case 1:
- srcDataFormat = kSourceFormatA8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatA8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatA16Big : kSourceFormatA16Little;
break;
case 2:
- srcDataFormat = kSourceFormatRA8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatRA8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatRA16Big : kSourceFormatRA16Little;
break;
case 4:
- srcDataFormat = kSourceFormatRGBA8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatRGBA8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatRGBA16Big : kSourceFormatRGBA16Little;
break;
default:
return false;
@@ -156,10 +218,16 @@ bool GraphicsContext3D::getImageData(Image* image,
case kCGImageAlphaNoneSkipLast:
switch (componentsPerPixel) {
case 2:
- srcDataFormat = kSourceFormatRA8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatRA8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatRA16Big : kSourceFormatRA16Little;
break;
case 4:
- srcDataFormat = kSourceFormatRGBA8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatRGBA8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatRGBA16Big : kSourceFormatRGBA16Little;
break;
default:
return false;
@@ -168,10 +236,16 @@ bool GraphicsContext3D::getImageData(Image* image,
case kCGImageAlphaNone:
switch (componentsPerPixel) {
case 1:
- srcDataFormat = kSourceFormatR8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatR8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatR16Big : kSourceFormatR16Little;
break;
case 3:
- srcDataFormat = kSourceFormatRGB8;
+ if (bitsPerComponent == 8)
+ srcDataFormat = kSourceFormatRGB8;
+ else
+ srcDataFormat = srcByteOrder16Big ? kSourceFormatRGB16Big : kSourceFormatRGB16Little;
break;
default:
return false;
@@ -188,7 +262,7 @@ bool GraphicsContext3D::getImageData(Image* image,
outputVector.resize(width * height * 4);
unsigned int srcUnpackAlignment = 0;
size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
- unsigned int padding = bytesPerRow - componentsPerPixel * width;
+ unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width;
if (padding) {
srcUnpackAlignment = padding + 1;
while (bytesPerRow % srcUnpackAlignment)
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
index e5079dc..9e0a2f5 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -26,7 +26,7 @@
#define _USE_MATH_DEFINES 1
#include "config.h"
-#include "GraphicsContext.h"
+#include "GraphicsContextCG.h"
#include "AffineTransform.h"
#include "FloatConversion.h"
@@ -69,60 +69,14 @@ using namespace std;
namespace WebCore {
-static CGColorRef createCGColorWithColorSpace(const Color& color, ColorSpace colorSpace)
-{
- CGFloat components[4];
- color.getRGBA(components[0], components[1], components[2], components[3]);
-
- CGColorRef cgColor = 0;
- if (colorSpace == sRGBColorSpace)
- cgColor = CGColorCreate(sRGBColorSpaceRef(), components);
- else
- cgColor = CGColorCreate(deviceRGBColorSpaceRef(), components);
-
- return cgColor;
-}
-
static void setCGFillColor(CGContextRef context, const Color& color, ColorSpace colorSpace)
{
- CGColorRef cgColor = createCGColorWithColorSpace(color, colorSpace);
- CGContextSetFillColorWithColor(context, cgColor);
- CFRelease(cgColor);
+ CGContextSetFillColorWithColor(context, cachedCGColor(color, colorSpace));
}
static void setCGStrokeColor(CGContextRef context, const Color& color, ColorSpace colorSpace)
{
- CGColorRef cgColor = createCGColorWithColorSpace(color, colorSpace);
- CGContextSetStrokeColorWithColor(context, cgColor);
- CFRelease(cgColor);
-}
-
-static void setCGFillColorSpace(CGContextRef context, ColorSpace colorSpace)
-{
- switch (colorSpace) {
- case DeviceColorSpace:
- break;
- case sRGBColorSpace:
- CGContextSetFillColorSpace(context, sRGBColorSpaceRef());
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
- }
-}
-
-static void setCGStrokeColorSpace(CGContextRef context, ColorSpace colorSpace)
-{
- switch (colorSpace) {
- case DeviceColorSpace:
- break;
- case sRGBColorSpace:
- CGContextSetStrokeColorSpace(context, sRGBColorSpaceRef());
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
- }
+ CGContextSetStrokeColorWithColor(context, cachedCGColor(color, colorSpace));
}
CGColorSpaceRef deviceRGBColorSpaceRef()
@@ -142,6 +96,17 @@ CGColorSpaceRef sRGBColorSpaceRef()
#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
+}
+
GraphicsContext::GraphicsContext(CGContextRef cgContext)
: m_common(createGraphicsContextPrivate())
, m_data(new GraphicsContextPlatformPrivate(cgContext))
@@ -586,9 +551,6 @@ void GraphicsContext::fillPath()
CGContextRef context = platformContext();
- // FIXME: Is this helpful and correct in the fillPattern and fillGradient cases?
- setCGFillColorSpace(context, m_common->state.fillColorSpace);
-
if (m_common->state.fillGradient) {
CGContextSaveGState(context);
if (fillRule() == RULE_EVENODD)
@@ -613,9 +575,6 @@ void GraphicsContext::strokePath()
CGContextRef context = platformContext();
- // FIXME: Is this helpful and correct in the strokePattern and strokeGradient cases?
- setCGStrokeColorSpace(context, m_common->state.strokeColorSpace);
-
if (m_common->state.strokeGradient) {
CGContextSaveGState(context);
CGContextReplacePathWithStrokedPath(context);
@@ -638,9 +597,6 @@ void GraphicsContext::fillRect(const FloatRect& rect)
CGContextRef context = platformContext();
- // FIXME: Is this helpful and correct in the fillPattern and fillGradient cases?
- setCGFillColorSpace(context, m_common->state.fillColorSpace);
-
if (m_common->state.fillGradient) {
CGContextSaveGState(context);
CGContextClipToRect(context, rect);
@@ -659,17 +615,18 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS
{
if (paintingDisabled())
return;
+
CGContextRef context = platformContext();
Color oldFillColor = fillColor();
ColorSpace oldColorSpace = fillColorSpace();
if (oldFillColor != color || oldColorSpace != colorSpace)
- setCGFillColor(context, color, colorSpace);
+ setCGFillColor(context, color, colorSpace);
CGContextFillRect(context, rect);
if (oldFillColor != color || oldColorSpace != colorSpace)
- setCGFillColor(context, oldFillColor, oldColorSpace);
+ 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)
@@ -684,7 +641,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
if (oldFillColor != color || oldColorSpace != colorSpace)
setCGFillColor(context, color, colorSpace);
- addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
+ Path path;
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ addPath(path);
fillPath();
if (oldFillColor != color || oldColorSpace != colorSpace)
@@ -821,13 +780,8 @@ void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, con
// and we should therefore just use the default shadow color.
if (!color.isValid())
CGContextSetShadow(context, CGSizeMake(xOffset, yOffset), blurRadius);
- else {
- RetainPtr<CGColorRef> colorCG(AdoptCF, createCGColorWithColorSpace(color, colorSpace));
- CGContextSetShadowWithColor(context,
- CGSizeMake(xOffset, yOffset),
- blurRadius,
- colorCG.get());
- }
+ else
+ CGContextSetShadowWithColor(context, CGSizeMake(xOffset, yOffset), blurRadius, cachedCGColor(color, colorSpace));
}
void GraphicsContext::clearPlatformShadow()
@@ -865,9 +819,6 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth)
CGContextRef context = platformContext();
- // FIXME: Is this helpful and correct in the strokePattern and strokeGradient cases?
- setCGStrokeColorSpace(context, m_common->state.strokeColorSpace);
-
if (m_common->state.strokeGradient) {
CGContextSaveGState(context);
setStrokeThickness(lineWidth);
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.h b/WebCore/platform/graphics/cg/GraphicsContextCG.h
new file mode 100644
index 0000000..5de95ef
--- /dev/null
+++ b/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/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
index aac4f45..1d0a99f 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
+++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
@@ -28,12 +28,6 @@
namespace WebCore {
-// FIXME: This would be in GraphicsContextCG.h if that existed.
-CGColorSpaceRef deviceRGBColorSpaceRef();
-
-// FIXME: This would be in GraphicsContextCG.h if that existed.
-CGColorSpaceRef sRGBColorSpaceRef();
-
class GraphicsContextPlatformPrivate {
public:
GraphicsContextPlatformPrivate(CGContextRef cgContext)
diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
index ecbcf60..640692a 100644
--- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
@@ -31,12 +31,12 @@
#include "Base64.h"
#include "BitmapImage.h"
#include "GraphicsContext.h"
+#include "GraphicsContextCG.h"
#include "ImageData.h"
#include "MIMETypeRegistry.h"
-#include "PlatformString.h"
#include <ApplicationServices/ApplicationServices.h>
#include <wtf/Assertions.h>
-#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
#include <wtf/OwnArrayPtr.h>
#include <wtf/RetainPtr.h>
#include <wtf/Threading.h>
@@ -56,7 +56,7 @@ ImageBufferData::ImageBufferData(const IntSize&)
{
}
-ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, bool& success)
: m_data(size)
, m_size(size)
{
@@ -65,12 +65,11 @@ ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, b
return;
unsigned bytesPerRow = size.width();
- if (imageColorSpace != GrayScale) {
- // Protect against overflow
- if (bytesPerRow > 0x3FFFFFFF)
- return;
- bytesPerRow *= 4;
- }
+
+ // Protect against overflow
+ if (bytesPerRow > 0x3FFFFFFF)
+ return;
+ bytesPerRow *= 4;
m_data.m_bytesPerRow = bytesPerRow;
size_t dataSize = size.height() * bytesPerRow;
@@ -80,27 +79,20 @@ ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, b
ASSERT((reinterpret_cast<size_t>(m_data.m_data) & 2) == 0);
switch(imageColorSpace) {
- case DeviceRGB:
- m_data.m_colorSpace.adoptCF(CGColorSpaceCreateDeviceRGB());
- break;
- case GrayScale:
- m_data.m_colorSpace.adoptCF(CGColorSpaceCreateDeviceGray());
- break;
-#if ((PLATFORM(MAC) || PLATFORM(CHROMIUM)) && !defined(BUILDING_ON_TIGER))
- case LinearRGB:
- m_data.m_colorSpace.adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear));
- break;
-
-#endif
- default:
- m_data.m_colorSpace.adoptCF(CGColorSpaceCreateDeviceRGB());
- break;
+ case ColorSpaceDeviceRGB:
+ m_data.m_colorSpace = deviceRGBColorSpaceRef();
+ break;
+ case ColorSpaceSRGB:
+ m_data.m_colorSpace = sRGBColorSpaceRef();
+ break;
+ case ColorSpaceLinearRGB:
+ m_data.m_colorSpace = linearRGBColorSpaceRef();
+ break;
}
- m_data.m_grayScale = imageColorSpace == GrayScale;
- m_data.m_bitmapInfo = m_data.m_grayScale ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast;
+ m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast;
RetainPtr<CGContextRef> cgContext(AdoptCF, CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow,
- m_data.m_colorSpace.get(), m_data.m_bitmapInfo));
+ m_data.m_colorSpace, m_data.m_bitmapInfo));
if (!cgContext)
return;
@@ -135,8 +127,8 @@ PassRefPtr<Image> ImageBuffer::copyImage() const
static CGImageRef cgImage(const IntSize& size, const ImageBufferData& data)
{
- return CGImageCreate(size.width(), size.height(), 8, data.m_grayScale ? 8 : 32, data.m_bytesPerRow,
- data.m_colorSpace.get(), data.m_bitmapInfo, data.m_dataProvider.get(), 0, true, kCGRenderingIntentDefault);
+ 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,
@@ -145,7 +137,7 @@ void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace,
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(), DeviceColorSpace, destRect, srcRect, op, useLowQualityScale);
+ 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);
@@ -371,7 +363,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con
base64Encode(reinterpret_cast<const char*>(CFDataGetBytePtr(data.get())), CFDataGetLength(data.get()), out);
out.append('\0');
- return String::format("data:%s;base64,%s", mimeType.utf8().data(), out.data());
+ return makeString("data:", mimeType, ";base64,", out.data());
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/cg/ImageBufferData.h b/WebCore/platform/graphics/cg/ImageBufferData.h
index 2f9d854..456c934 100644
--- a/WebCore/platform/graphics/cg/ImageBufferData.h
+++ b/WebCore/platform/graphics/cg/ImageBufferData.h
@@ -46,9 +46,8 @@ public:
RetainPtr<CGDataProviderRef> m_dataProvider;
CGBitmapInfo m_bitmapInfo;
- bool m_grayScale;
unsigned m_bytesPerRow;
- RetainPtr<CGColorSpaceRef> m_colorSpace;
+ CGColorSpaceRef m_colorSpace;
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp
index 70a80a0..c7ed0c8 100644
--- a/WebCore/platform/graphics/cg/ImageCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageCG.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -31,12 +31,12 @@
#include "AffineTransform.h"
#include "FloatConversion.h"
#include "FloatRect.h"
-#include "GraphicsContext.h"
-#include "GraphicsContextPlatformPrivateCG.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"
@@ -138,11 +138,12 @@ static RetainPtr<CGImageRef> imageWithColorSpace(CGImageRef originalImage, Color
return originalImage;
switch (colorSpace) {
- case DeviceColorSpace:
+ case ColorSpaceDeviceRGB:
return originalImage;
- case sRGBColorSpace:
- return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage,
- sRGBColorSpaceRef()));
+ case ColorSpaceSRGB:
+ return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, sRGBColorSpaceRef()));
+ case ColorSpaceLinearRGB:
+ return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, linearRGBColorSpaceRef()));
}
ASSERT_NOT_REACHED();
@@ -186,7 +187,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F
// 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();
+ 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) {
diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp
index 90d4b8a..b47ed02 100644
--- a/WebCore/platform/graphics/cg/PathCG.cpp
+++ b/WebCore/platform/graphics/cg/PathCG.cpp
@@ -254,61 +254,9 @@ FloatPoint Path::currentPoint() const
return CGPathGetCurrentPoint(m_path);
}
-static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *element)
-{
- CFMutableStringRef string = static_cast<CFMutableStringRef>(info);
-
- CGPoint* points = element->points;
- switch (element->type) {
- case kCGPathElementMoveToPoint:
- CFStringAppendFormat(string, 0, CFSTR("M%.2f,%.2f "), points[0].x, points[0].y);
- break;
- case kCGPathElementAddLineToPoint:
- CFStringAppendFormat(string, 0, CFSTR("L%.2f,%.2f "), points[0].x, points[0].y);
- break;
- case kCGPathElementAddQuadCurveToPoint:
- CFStringAppendFormat(string, 0, CFSTR("Q%.2f,%.2f,%.2f,%.2f "),
- points[0].x, points[0].y, points[1].x, points[1].y);
- break;
- case kCGPathElementAddCurveToPoint:
- CFStringAppendFormat(string, 0, CFSTR("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f "),
- points[0].x, points[0].y, points[1].x, points[1].y,
- points[2].x, points[2].y);
- break;
- case kCGPathElementCloseSubpath:
- CFStringAppendFormat(string, 0, CFSTR("Z "));
- break;
- }
-}
-
-static CFStringRef CFStringFromCGPath(CGPathRef path)
-{
- if (!path)
- return 0;
-
- CFMutableStringRef string = CFStringCreateMutable(NULL, 0);
- CGPathApply(path, string, CGPathToCFStringApplierFunction);
- CFStringTrimWhitespace(string);
-
-
- return string;
-}
-
-
#pragma mark -
#pragma mark Path Management
-String Path::debugString() const
-{
- String result;
- if (!isEmpty()) {
- CFStringRef pathString = CFStringFromCGPath(m_path);
- result = String(pathString);
- CFRelease(pathString);
- }
- return result;
-}
-
struct PathApplierInfo {
void* info;
PathApplierFunction function;
diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
index 8dda4d6..eba5349 100644
--- a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
+++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
@@ -43,8 +43,6 @@
#include "PlatformContextSkia.h"
#include "skia/ext/platform_canvas.h"
#elif PLATFORM(CG)
-#include "LocalCurrentGraphicsContext.h"
-
#include <CoreGraphics/CGBitmapContext.h>
#endif
@@ -121,6 +119,7 @@ PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChrom
ContentLayerChromium::ContentLayerChromium(GraphicsLayerChromium* owner)
: LayerChromium(owner)
, m_contentsTexture(0)
+ , m_skipsDraw(false)
{
}
@@ -129,16 +128,6 @@ ContentLayerChromium::~ContentLayerChromium()
cleanupResources();
}
-void ContentLayerChromium::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();
-
- LayerChromium::setLayerRenderer(renderer);
-}
-
void ContentLayerChromium::cleanupResources()
{
if (layerRenderer()) {
@@ -149,6 +138,42 @@ void ContentLayerChromium::cleanupResources()
}
}
+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 current size
+ // of the visible rect. This is a temporary measure until layer tiling is implemented.
+ static const int maxLayerSize = 2000;
+ return (m_bounds.width() > max(maxLayerSize, layerRenderer()->rootLayerContentRect().width())
+ || m_bounds.height() > max(maxLayerSize, layerRenderer()->rootLayerContentRect().height())
+ || !layerRenderer()->checkTextureSize(m_bounds));
+}
+
+void ContentLayerChromium::calculateClippedUpdateRect(IntRect& dirtyRect, IntRect& drawRect) const
+{
+ // For the given layer size and content rect, calculate:
+ // 1) The minimal texture space rectangle to be uploaded, returned in dirtyRect.
+ // 2) The content rect-relative rectangle to draw this texture in, returned in drawRect.
+
+ const IntRect clipRect = layerRenderer()->currentScissorRect();
+ const TransformationMatrix& transform = drawTransform();
+ // The layer's draw transform points to the center of the layer, relative to
+ // the content rect. layerPos is the distance from the top left of the
+ // layer to the top left of the content rect.
+ const IntPoint layerPos(m_bounds.width() / 2 - transform.m41(),
+ m_bounds.height() / 2 - transform.m42());
+ // Transform the contentRect into the space of the layer.
+ IntRect contentRectInLayerSpace(layerPos, clipRect.size());
+
+ // Clip the entire layer against the visible region in the content rect
+ // and use that as the drawable texture, instead of the entire layer.
+ dirtyRect = IntRect(IntPoint(0, 0), m_bounds);
+ dirtyRect.intersect(contentRectInLayerSpace);
+
+ // The draw position is relative to the content rect.
+ drawRect = IntRect(toPoint(dirtyRect.location() - layerPos), dirtyRect.size());
+}
+
void ContentLayerChromium::updateContents()
{
RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client());
@@ -159,29 +184,47 @@ void ContentLayerChromium::updateContents()
ASSERT(layerRenderer());
- // FIXME: Remove this test when tiled layers are implemented.
- m_skipsDraw = false;
- if (!layerRenderer()->checkTextureSize(m_bounds)) {
- m_skipsDraw = true;
- return;
- }
-
void* pixels = 0;
- IntRect dirtyRect(m_dirtyRect);
+ IntRect dirtyRect;
+ IntRect updateRect;
IntSize requiredTextureSize;
IntSize bitmapSize;
- requiredTextureSize = m_bounds;
- IntRect boundsRect(IntPoint(0, 0), m_bounds);
-
- // If the texture needs to be reallocated then we must redraw the entire
- // contents of the layer.
- if (requiredTextureSize != m_allocatedTextureSize)
- 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);
+ // 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;
+ }
+
+ calculateClippedUpdateRect(dirtyRect, m_largeLayerDrawRect);
+ if (!layerRenderer()->checkTextureSize(m_largeLayerDrawRect.size())) {
+ m_skipsDraw = true;
+ return;
+ }
+ if (m_largeLayerDirtyRect == dirtyRect)
+ return;
+
+ m_largeLayerDirtyRect = dirtyRect;
+ requiredTextureSize = dirtyRect.size();
+ updateRect = IntRect(IntPoint(0, 0), dirtyRect.size());
+ } else {
+ dirtyRect = IntRect(m_dirtyRect);
+ IntRect boundsRect(IntPoint(0, 0), m_bounds);
+ requiredTextureSize = m_bounds;
+ // If the texture needs to be reallocated then we must redraw the entire
+ // contents of the layer.
+ if (requiredTextureSize != m_allocatedTextureSize)
+ 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 PLATFORM(SKIA)
@@ -228,7 +271,6 @@ void ContentLayerChromium::updateContents()
CGContextScaleCTM(contextCG.get(), 1, -1);
GraphicsContext graphicsContext(contextCG.get());
- LocalCurrentGraphicsContext scopedNSGraphicsContext(&graphicsContext);
// Translate the graphics context into the coordinate system of the dirty rect.
graphicsContext.translate(-dirtyRect.x(), -dirtyRect.y());
@@ -246,7 +288,7 @@ void ContentLayerChromium::updateContents()
textureId = layerRenderer()->createLayerTexture();
if (pixels)
- updateTextureRect(pixels, bitmapSize, requiredTextureSize, dirtyRect, textureId);
+ updateTextureRect(pixels, bitmapSize, requiredTextureSize, updateRect, textureId);
}
void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId)
@@ -272,7 +314,8 @@ void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmap
}
m_dirtyRect.setSize(FloatSize());
- m_contentsDirty = false;
+ // Large layers always stay dirty, because they need to update when the content rect changes.
+ m_contentsDirty = requiresClippedUpdateRect();
}
void ContentLayerChromium::draw()
@@ -288,9 +331,21 @@ void ContentLayerChromium::draw()
GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_contentsTexture));
layerRenderer()->useShader(sv->contentShaderProgram());
GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0));
- drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(),
- bounds().width(), bounds().height(), drawOpacity(),
- sv->shaderMatrixLocation(), sv->shaderAlphaLocation());
+
+ if (requiresClippedUpdateRect()) {
+ float m43 = drawTransform().m43();
+ TransformationMatrix transform;
+ transform.translate3d(m_largeLayerDrawRect.center().x(), m_largeLayerDrawRect.center().y(), m43);
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(),
+ transform, m_largeLayerDrawRect.width(),
+ m_largeLayerDrawRect.height(), drawOpacity(),
+ sv->shaderMatrixLocation(), sv->shaderAlphaLocation());
+ } else {
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(),
+ drawTransform(), m_bounds.width(), m_bounds.height(),
+ drawOpacity(), sv->shaderMatrixLocation(),
+ sv->shaderAlphaLocation());
+ }
}
}
diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/WebCore/platform/graphics/chromium/ContentLayerChromium.h
index 412ba06..32c2c49 100644
--- a/WebCore/platform/graphics/chromium/ContentLayerChromium.h
+++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.h
@@ -49,7 +49,6 @@ public:
virtual void updateContents();
virtual void draw();
virtual bool drawsContent() { return m_owner && m_owner->drawsContent(); }
- virtual void setLayerRenderer(LayerRendererChromium*);
// Stores values that are shared between instances of this class that are
// associated with the same LayerRendererChromium (and hence the same GL
@@ -80,12 +79,17 @@ protected:
void updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize,
const IntRect& updateRect, unsigned textureId);
- void cleanupResources();
+ virtual void cleanupResources();
+ bool requiresClippedUpdateRect() const;
unsigned m_contentsTexture;
IntSize m_allocatedTextureSize;
bool m_skipsDraw;
+private:
+ void calculateClippedUpdateRect(IntRect& dirtyRect, IntRect& drawRect) const;
+ IntRect m_largeLayerDrawRect;
+ IntRect m_largeLayerDirtyRect;
};
}
diff --git a/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp
index 9ce0efe..b54a427 100644
--- a/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp
+++ b/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp
@@ -48,7 +48,7 @@ struct DrawingBufferInternal {
#endif
};
-static unsigned generateColorTexture(SharedGraphicsContext3D* context, const IntSize& size)
+static unsigned generateColorTexture(GraphicsContext3D* context, const IntSize& size)
{
unsigned offscreenColorTexture = context->createTexture();
if (!offscreenColorTexture)
@@ -66,13 +66,13 @@ static unsigned generateColorTexture(SharedGraphicsContext3D* context, const Int
}
-DrawingBuffer::DrawingBuffer(SharedGraphicsContext3D* context, const IntSize& size, unsigned framebuffer)
+DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, const IntSize& size)
: m_context(context)
, m_size(size)
- , m_framebuffer(framebuffer)
+ , m_fbo(context->createFramebuffer())
, m_internal(new DrawingBufferInternal)
{
- context->bindFramebuffer(framebuffer);
+ context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
m_internal->offscreenColorTexture = generateColorTexture(context, size);
}
@@ -82,14 +82,22 @@ DrawingBuffer::~DrawingBuffer()
if (m_internal->platformLayer)
m_internal->platformLayer->setDrawingBuffer(0);
#endif
- m_context->bindFramebuffer(m_framebuffer);
+
+ if (!m_context)
+ return;
+
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
m_context->deleteTexture(m_internal->offscreenColorTexture);
- m_context->deleteFramebuffer(m_framebuffer);
+
+ clear();
}
#if USE(ACCELERATED_COMPOSITING)
void DrawingBuffer::publishToPlatformLayer()
{
+ if (!m_context)
+ return;
+
if (m_callback)
m_callback->willPublish();
unsigned parentTexture = m_internal->platformLayer->textureId();
@@ -106,6 +114,9 @@ void DrawingBuffer::publishToPlatformLayer()
void DrawingBuffer::reset(const IntSize& newSize)
{
+ if (!m_context)
+ return;
+
if (m_size == newSize)
return;
m_size = newSize;
diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp
index a242523..f38273c 100644
--- a/WebCore/platform/graphics/chromium/FontLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -161,62 +161,23 @@ static int truncateFixedPointToInteger(HB_Fixed value)
// can call |reset| to start over again.
class TextRunWalker {
public:
- TextRunWalker(const TextRun& run, unsigned startingX, const Font* font)
- : m_font(font)
- , m_startingX(startingX)
- , m_offsetX(m_startingX)
- , m_run(getTextRun(run))
- , m_iterateBackwards(m_run.rtl())
- , m_wordSpacingAdjustment(0)
- , m_padding(0)
- , m_padError(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();
-
- int length = m_run.length();
- m_item.stringLength = length;
-
- if (!m_item.item.bidiLevel)
- m_item.string = m_run.characters();
- else {
- // Assume mirrored character is in the same Unicode multilingual plane as the original one.
- UChar* string = new UChar[length];
- mirrorCharacters(string, m_run.characters(), length);
- m_item.string = string;
- }
-
- reset();
- }
+ TextRunWalker(const TextRun&, unsigned, const Font*);
+ ~TextRunWalker();
- ~TextRunWalker()
- {
- fastFree(m_item.font);
- deleteGlyphArrays();
- delete[] m_item.log_clusters;
- if (m_item.item.bidiLevel)
- delete[] m_item.string;
- }
+ bool isWordBreak(unsigned, bool);
+ // 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;
- }
+ 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
@@ -224,393 +185,431 @@ public:
//
// (NOTE: currently does nothing because I don't know how to get the
// cluster information from Harfbuzz.)
- void setLetterSpacingAdjustment(int letterSpacingAdjustment)
- {
- m_letterSpacing = letterSpacingAdjustment;
- }
-
- bool isWordBreak(unsigned i, bool isRTL)
- {
- if (!isRTL)
- return i && isCodepointSpace(m_item.string[i]) && !isCodepointSpace(m_item.string[i - 1]);
- return i != m_item.stringLength - 1 && isCodepointSpace(m_item.string[i]) && !isCodepointSpace(m_item.string[i + 1]);
- }
-
- // setPadding sets a number of pixels to be distributed across the TextRun.
- // WebKit uses this to justify text.
- void 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;
- bool isRTL = m_iterateBackwards;
-
- for (unsigned i = 0; i < m_item.stringLength; i++) {
- if (isWordBreak(i, isRTL))
- numWordBreaks++;
- }
-
- if (numWordBreaks)
- m_padPerWordBreak = m_padding / numWordBreaks;
- else
- m_padPerWordBreak = 0;
- }
-
- void reset()
- {
- if (m_iterateBackwards)
- m_indexOfNextScriptRun = m_run.length() - 1;
- else
- m_indexOfNextScriptRun = 0;
- m_offsetX = m_startingX;
- }
+ void setLetterSpacingAdjustment(int letterSpacingAdjustment) { m_letterSpacing = letterSpacingAdjustment; }
// 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();
- }
-
- void 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 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;
- } 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.
- const FontData* glyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData;
- unsigned endOfRun;
- for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) {
- const FontData* nextGlyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false, false).fontData;
- if (nextGlyphData != glyphData)
- break;
- }
- m_item.item.length = endOfRun;
- m_indexOfNextScriptRun = m_item.item.pos + endOfRun;
- }
-
- setupFontForScriptRun();
- shapeGlyphs();
- setGlyphXPositions(rtl());
-
- return true;
- }
-
- const uint16_t* glyphs() const
- {
- return m_glyphs16;
- }
+ 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;
- }
+ 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;
- }
+ const SkScalar* xPositions() const { return m_xPositions; }
// Get the advances (widths) for each glyph.
- const HB_Fixed* advances() const
- {
- return m_item.advances;
- }
+ 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;
- }
+ 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;
- }
+ 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 unsigned numCodePoints() const { return m_numCodePoints; }
- const FontPlatformData* fontPlatformDataForScriptRun()
- {
- return reinterpret_cast<FontPlatformData*>(m_item.font->userData);
- }
+ const FontPlatformData* fontPlatformDataForScriptRun() { return reinterpret_cast<FontPlatformData*>(m_item.font->userData); }
- float widthOfFullRun()
- {
- float widthSum = 0;
- while (nextScriptRun())
- widthSum += width();
+private:
+ const TextRun& getTextRun(const TextRun&);
+ const TextRun& getNormalizedTextRun(const TextRun&);
+ void setupFontForScriptRun();
+ HB_FontRec* allocHarfbuzzFont();
+ void deleteGlyphArrays();
+ void createGlyphArrays(int);
+ void resetGlyphArrays();
+ void shapeGlyphs();
+ void setGlyphXPositions(bool);
+ void mirrorCharacters(UChar*, const UChar*, int) const;
+
+ // This matches the logic in RenderBlock::findNextLineBreak
+ static bool isCodepointSpace(HB_UChar16 c) { return c == ' ' || c == '\t'; }
- return widthSum;
- }
+ const Font* const m_font;
+ 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.
-private:
- const TextRun& getTextRun(const TextRun& originalRun)
- {
- // Normalize the text run in two 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.
- for (int i = 0; i < originalRun.length(); ++i) {
- UChar ch = originalRun[i];
- UBlockCode block = ::ublock_getCode(ch);
- if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS || (Font::treatAsSpace(ch) && ch != ' ')) {
- return getNormalizedTextRun(originalRun);
- }
- }
- return originalRun;
- }
+ 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.
+ unsigned m_letterSpacing; // pixels to be added after each glyph.
+};
- const TextRun& getNormalizedTextRun(const TextRun& originalRun)
- {
- icu::UnicodeString normalizedString;
- UErrorCode error = U_ZERO_ERROR;
- icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), originalRun.length()), UNORM_NFC, 0 /* no options */, normalizedString, error);
- if (U_FAILURE(error))
- return originalRun;
-
- m_normalizedBuffer.set(new UChar[normalizedString.length() + 1]);
- normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error);
- ASSERT(U_SUCCESS(error));
-
- for (int i = 0; i < normalizedString.length(); ++i) {
- if (Font::treatAsSpace(m_normalizedBuffer[i]))
- m_normalizedBuffer[i] = ' ';
- }
- m_normalizedRun.set(new TextRun(originalRun));
- m_normalizedRun->setText(m_normalizedBuffer.get(), normalizedString.length());
- return *m_normalizedRun;
- }
+TextRunWalker::TextRunWalker(const TextRun& run, unsigned startingX, const Font* font)
+ : m_font(font)
+ , m_startingX(startingX)
+ , m_offsetX(m_startingX)
+ , m_run(getTextRun(run))
+ , m_iterateBackwards(m_run.rtl())
+ , m_wordSpacingAdjustment(0)
+ , m_padding(0)
+ , m_padError(0)
+{
+ // Do not use |run| inside this constructor. Use |m_run| instead.
- void setupFontForScriptRun()
- {
- const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData;
- const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData();
- m_item.face = platformData.harfbuzzFace();
- void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData);
- m_item.font->userData = opaquePlatformData;
- }
+ 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);
- HB_FontRec* 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;
- }
+ 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();
- void deleteGlyphArrays()
- {
- delete[] m_item.glyphs;
- delete[] m_item.attributes;
- delete[] m_item.advances;
- delete[] m_item.offsets;
- delete[] m_glyphs16;
- delete[] m_xPositions;
+ int length = m_run.length();
+ m_item.stringLength = length;
+
+ if (!m_item.item.bidiLevel)
+ m_item.string = m_run.characters();
+ else {
+ // Assume mirrored character is in the same Unicode multilingual plane as the original one.
+ UChar* string = new UChar[length];
+ mirrorCharacters(string, m_run.characters(), length);
+ m_item.string = string;
}
- void createGlyphArrays(int size)
- {
- m_item.glyphs = new HB_Glyph[size];
- memset(m_item.glyphs, 0, size * sizeof(HB_Glyph));
- m_item.attributes = new HB_GlyphAttributes[size];
- memset(m_item.attributes, 0, size * sizeof(HB_GlyphAttributes));
- m_item.advances = new HB_Fixed[size];
- memset(m_item.advances, 0, size * sizeof(HB_Fixed));
- m_item.offsets = new HB_FixedPoint[size];
- memset(m_item.offsets, 0, size * sizeof(HB_FixedPoint));
-
- m_glyphs16 = new uint16_t[size];
- m_xPositions = new SkScalar[size];
-
- m_item.num_glyphs = size;
+ reset();
+}
+
+TextRunWalker::~TextRunWalker()
+{
+ fastFree(m_item.font);
+ deleteGlyphArrays();
+ delete[] m_item.log_clusters;
+ if (m_item.item.bidiLevel)
+ delete[] m_item.string;
+}
+
+bool TextRunWalker::isWordBreak(unsigned index, bool isRTL)
+{
+ if (!isRTL)
+ return index && isCodepointSpace(m_item.string[index]) && !isCodepointSpace(m_item.string[index - 1]);
+ return index != m_item.stringLength - 1 && isCodepointSpace(m_item.string[index]) && !isCodepointSpace(m_item.string[index + 1]);
+}
+
+// setPadding sets a number of pixels to be distributed across the TextRun.
+// WebKit uses this to justify text.
+void TextRunWalker::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;
+ bool isRTL = m_iterateBackwards;
+
+ for (unsigned i = 0; i < m_item.stringLength; i++) {
+ if (isWordBreak(i, isRTL))
+ numWordBreaks++;
}
- void shapeGlyphs()
- {
- for (;;) {
- if (HB_ShapeItem(&m_item))
- break;
+ if (numWordBreaks)
+ m_padPerWordBreak = m_padding / numWordBreaks;
+ else
+ m_padPerWordBreak = 0;
+}
+
+void TextRunWalker::reset()
+{
+ if (m_iterateBackwards)
+ m_indexOfNextScriptRun = m_run.length() - 1;
+ else
+ m_indexOfNextScriptRun = 0;
+ m_offsetX = m_startingX;
+}
- // 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 TextRunWalker::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 TextRunWalker::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;
+ } 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.
+ const FontData* glyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData;
+ unsigned endOfRun;
+ for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) {
+ const FontData* nextGlyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false, false).fontData;
+ if (nextGlyphData != glyphData)
+ break;
}
+ m_item.item.length = endOfRun;
+ m_indexOfNextScriptRun = m_item.item.pos + endOfRun;
}
- void 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.
- unsigned logClustersIndex = isRTL ? m_item.num_glyphs - 1 : 0;
-
- for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) {
- // Glyphs are stored in logical order, but for layout purposes we
- // always go left to right.
- int i = isRTL ? m_item.num_glyphs - iter - 1 : iter;
-
- m_glyphs16[i] = m_item.glyphs[i];
- double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
- m_xPositions[i] = m_offsetX + position + offsetX;
-
- double advance = truncateFixedPointToInteger(m_item.advances[i]);
- // The first half of the conjuction 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, isRTL)) {
- advance += m_wordSpacingAdjustment;
-
- if (m_padding > 0) {
- unsigned toPad = roundf(m_padPerWordBreak + m_padError);
- m_padError += m_padPerWordBreak - toPad;
-
- if (m_padding < toPad)
- toPad = m_padding;
- m_padding -= toPad;
- advance += toPad;
- }
- }
+ setupFontForScriptRun();
+ shapeGlyphs();
+ setGlyphXPositions(rtl());
- // We would like to add m_letterSpacing after each cluster, but I
- // don't know where the cluster information is. This is typically
- // fine for Roman languages, but breaks more complex languages
- // terribly.
- // advance += m_letterSpacing;
-
- if (isRTL) {
- while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i)
- logClustersIndex--;
- } else {
- while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i)
- logClustersIndex++;
- }
+ return true;
+}
- position += advance;
- }
+float TextRunWalker::widthOfFullRun()
+{
+ float widthSum = 0;
+ while (nextScriptRun())
+ widthSum += width();
- m_pixelWidth = position;
- m_offsetX += m_pixelWidth;
+ return widthSum;
+}
+
+const TextRun& TextRunWalker::getTextRun(const TextRun& originalRun)
+{
+ // Normalize the text run in two 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.
+ for (int i = 0; i < originalRun.length(); ++i) {
+ UChar ch = originalRun[i];
+ UBlockCode block = ::ublock_getCode(ch);
+ if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS || (Font::treatAsSpace(ch) && ch != ' '))
+ return getNormalizedTextRun(originalRun);
+ }
+ return originalRun;
+}
+
+const TextRun& TextRunWalker::getNormalizedTextRun(const TextRun& originalRun)
+{
+ icu::UnicodeString normalizedString;
+ UErrorCode error = U_ZERO_ERROR;
+ icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), originalRun.length()), UNORM_NFC, 0 /* no options */, normalizedString, error);
+ if (U_FAILURE(error))
+ return originalRun;
+
+ m_normalizedBuffer.set(new UChar[normalizedString.length() + 1]);
+ normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error);
+ ASSERT(U_SUCCESS(error));
+
+ for (int i = 0; i < normalizedString.length(); ++i) {
+ if (Font::treatAsSpace(m_normalizedBuffer[i]))
+ m_normalizedBuffer[i] = ' ';
}
- static bool isCodepointSpace(HB_UChar16 c)
- {
- // This matches the logic in RenderBlock::findNextLineBreak
- return c == ' ' || c == '\t';
+ m_normalizedRun.set(new TextRun(originalRun));
+ m_normalizedRun->setText(m_normalizedBuffer.get(), normalizedString.length());
+ return *m_normalizedRun;
+}
+
+void TextRunWalker::setupFontForScriptRun()
+{
+ const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, 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* TextRunWalker::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 TextRunWalker::deleteGlyphArrays()
+{
+ delete[] m_item.glyphs;
+ delete[] m_item.attributes;
+ delete[] m_item.advances;
+ delete[] m_item.offsets;
+ delete[] m_glyphs16;
+ delete[] m_xPositions;
+}
+
+void TextRunWalker::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 TextRunWalker::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 TextRunWalker::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 TextRunWalker::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.
+ unsigned logClustersIndex = isRTL ? m_item.num_glyphs - 1 : 0;
+
+ for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) {
+ // Glyphs are stored in logical order, but for layout purposes we
+ // always go left to right.
+ int i = isRTL ? m_item.num_glyphs - iter - 1 : iter;
+
+ m_glyphs16[i] = m_item.glyphs[i];
+ double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
+ m_xPositions[i] = m_offsetX + position + offsetX;
+
+ double advance = truncateFixedPointToInteger(m_item.advances[i]);
+ // The first half of the conjuction 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, isRTL)) {
+ advance += m_wordSpacingAdjustment;
+
+ if (m_padding > 0) {
+ unsigned toPad = roundf(m_padPerWordBreak + m_padError);
+ m_padError += m_padPerWordBreak - toPad;
+
+ if (m_padding < toPad)
+ toPad = m_padding;
+ m_padding -= toPad;
+ advance += toPad;
+ }
+ }
- void mirrorCharacters(UChar* destination, const UChar* source, int length) const
- {
- 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);
- character = u_charMirror(character);
- U16_APPEND(destination, position, length, character, error);
- ASSERT(!error);
- position = nextPosition;
+ // We would like to add m_letterSpacing after each cluster, but I
+ // don't know where the cluster information is. This is typically
+ // fine for Roman languages, but breaks more complex languages
+ // terribly.
+ // advance += m_letterSpacing;
+
+ if (isRTL) {
+ while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i)
+ logClustersIndex--;
+ } else {
+ while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i)
+ logClustersIndex++;
}
+
+ position += advance;
}
- const Font* const m_font;
- 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.
+ m_pixelWidth = position;
+ m_offsetX += m_pixelWidth;
+}
- 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.
- unsigned m_letterSpacing; // pixels to be added after each glyph.
-};
+void TextRunWalker::mirrorCharacters(UChar* destination, const UChar* source, int length) const
+{
+ 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);
+ character = u_charMirror(character);
+ U16_APPEND(destination, position, length, character, error);
+ ASSERT(!error);
+ position = nextPosition;
+ }
+}
static void setupForTextPainting(SkPaint* paint, SkColor color)
{
diff --git a/WebCore/platform/graphics/chromium/GLES2Canvas.cpp b/WebCore/platform/graphics/chromium/GLES2Canvas.cpp
index 46aecf4..697cf5e 100644
--- a/WebCore/platform/graphics/chromium/GLES2Canvas.cpp
+++ b/WebCore/platform/graphics/chromium/GLES2Canvas.cpp
@@ -97,7 +97,7 @@ void GLES2Canvas::clearRect(const FloatRect& rect)
} else {
save();
setCompositeOperation(CompositeClear);
- fillRect(rect, Color(RGBA32(0)), DeviceColorSpace);
+ fillRect(rect, Color(RGBA32(0)), ColorSpaceDeviceRGB);
restore();
}
}
@@ -120,7 +120,7 @@ void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace
void GLES2Canvas::fillRect(const FloatRect& rect)
{
- fillRect(rect, m_state->m_fillColor, DeviceColorSpace);
+ fillRect(rect, m_state->m_fillColor, ColorSpaceDeviceRGB);
}
void GLES2Canvas::setFillColor(const Color& color, ColorSpace colorSpace)
diff --git a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp
index c97be82..afcc98c 100644
--- a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp
+++ b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp
@@ -75,6 +75,14 @@ void ImageLayerChromium::updateContents()
{
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::updateContents();
+ return;
+ }
+
void* pixels = 0;
IntSize requiredTextureSize;
IntSize bitmapSize;
@@ -136,12 +144,6 @@ void ImageLayerChromium::updateContents()
#else
#error "Need to implement for your platform."
#endif
- // FIXME: Remove this test when tiled layers are implemented.
- m_skipsDraw = false;
- if (!layerRenderer()->checkTextureSize(requiredTextureSize)) {
- m_skipsDraw = true;
- return;
- }
unsigned textureId = m_contentsTexture;
if (!textureId)
diff --git a/WebCore/platform/graphics/chromium/LayerChromium.cpp b/WebCore/platform/graphics/chromium/LayerChromium.cpp
index 5dba58d..79f18f0 100644
--- a/WebCore/platform/graphics/chromium/LayerChromium.cpp
+++ b/WebCore/platform/graphics/chromium/LayerChromium.cpp
@@ -174,6 +174,11 @@ LayerChromium::~LayerChromium()
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();
+
m_layerRenderer = renderer;
}
@@ -446,15 +451,12 @@ void LayerChromium::drawDebugBorder()
GLC(context, context->drawElements(GraphicsContext3D::LINE_LOOP, 4, GraphicsContext3D::UNSIGNED_SHORT, 6 * sizeof(unsigned short)));
}
-const FloatRect LayerChromium::getDrawRect() const
+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.
- TransformationMatrix renderMatrix = drawTransform();
- renderMatrix.scale3d(bounds().width(), bounds().height(), 1);
-
- FloatRect layerRect(-0.5, -0.5, 1, 1);
- FloatRect mappedRect = renderMatrix.mapRect(layerRect);
+ FloatRect layerRect(-0.5 * bounds().width(), -0.5 * bounds().height(), bounds().width(), bounds().height());
+ IntRect mappedRect = enclosingIntRect(drawTransform().mapRect(layerRect));
return mappedRect;
}
diff --git a/WebCore/platform/graphics/chromium/LayerChromium.h b/WebCore/platform/graphics/chromium/LayerChromium.h
index 0a66318..3956e28 100644
--- a/WebCore/platform/graphics/chromium/LayerChromium.h
+++ b/WebCore/platform/graphics/chromium/LayerChromium.h
@@ -156,7 +156,7 @@ public:
bool contentsDirty() { return m_contentsDirty; }
// Returns the rect containtaining this layer in the current view's coordinate system.
- const FloatRect getDrawRect() const;
+ const IntRect getDrawRect() const;
// These methods typically need to be overwritten by derived classes.
virtual bool drawsContent() { return false; }
@@ -202,6 +202,11 @@ 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() { }
+
LayerRendererChromium* layerRenderer() const { return m_layerRenderer.get(); }
GraphicsContext3D* layerRendererContext() const;
diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
index c4031e5..e93e296 100644
--- a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
+++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
@@ -73,7 +73,7 @@ static inline bool compareLayerZ(const LayerChromium* a, const LayerChromium* b)
return transformA.m43() < transformB.m43();
}
-PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassOwnPtr<GraphicsContext3D> context)
+PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context)
{
if (!context)
return 0;
@@ -85,7 +85,7 @@ PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassOwnPtr<Graph
return layerRenderer.release();
}
-LayerRendererChromium::LayerRendererChromium(PassOwnPtr<GraphicsContext3D> context)
+LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context)
: m_rootLayerTextureId(0)
, m_rootLayerTextureWidth(0)
, m_rootLayerTextureHeight(0)
@@ -127,7 +127,6 @@ void LayerRendererChromium::setRootLayerCanvasSize(const IntSize& size)
// the old ones.
m_rootLayerCanvas = new skia::PlatformCanvas(size.width(), size.height(), false);
m_rootLayerSkiaContext = new PlatformContextSkia(m_rootLayerCanvas.get());
- m_rootLayerSkiaContext->setDrawingToImageBuffer(true);
m_rootLayerGraphicsContext = new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(m_rootLayerSkiaContext.get()));
#elif PLATFORM(CG)
// Release the previous CGBitmapContext before reallocating the backing store as a precaution.
@@ -204,6 +203,8 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons
GLC(m_context, m_context->disable(GraphicsContext3D::CULL_FACE));
GLC(m_context, m_context->depthFunc(GraphicsContext3D::LEQUAL));
GLC(m_context, m_context->clearStencil(0));
+ // Blending disabled by default. Root layer alpha channel on Windows is incorrect when Skia uses ClearType.
+ GLC(m_context, m_context->disable(GraphicsContext3D::BLEND));
if (m_scrollPosition == IntPoint(-1, -1)) {
m_scrollPosition = scrollPosition;
@@ -284,11 +285,15 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect
const ContentLayerChromium::SharedValues* contentLayerValues = contentLayerSharedValues();
useShader(contentLayerValues->contentShaderProgram());
GLC(m_context, m_context->uniform1i(contentLayerValues->shaderSamplerLocation(), 0));
+ // Mask out writes to alpha channel: ClearType via Skia results in invalid
+ // zero alpha values on text glyphs. The root layer is always opaque.
+ GLC(m_context, m_context->colorMask(true, true, true, false));
TransformationMatrix layerMatrix;
layerMatrix.translate3d(visibleRect.width() * 0.5f, visibleRect.height() * 0.5f, 0);
LayerChromium::drawTexturedQuad(m_context.get(), m_projectionMatrix, layerMatrix,
visibleRect.width(), visibleRect.height(), 1,
contentLayerValues->shaderMatrixLocation(), contentLayerValues->shaderAlphaLocation());
+ GLC(m_context, m_context->colorMask(true, true, true, true));
// If culling is enabled then we will cull the backface.
GLC(m_context, m_context->cullFace(GraphicsContext3D::BACK));
@@ -302,8 +307,9 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect
GLC(m_context, m_context->enable(GraphicsContext3D::BLEND));
GLC(m_context, m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
- // Set the rootVisibleRect --- used by subsequent drawLayers calls
+ // Set the root visible/content rects --- used by subsequent drawLayers calls.
m_rootVisibleRect = visibleRect;
+ m_rootContentRect = contentRect;
// Traverse the layer tree and update the layer transforms.
float opacity = 1;
@@ -315,7 +321,7 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect
// Enable scissoring to avoid rendering composited layers over the scrollbars.
GLC(m_context, m_context->enable(GraphicsContext3D::SCISSOR_TEST));
- FloatRect scissorRect(contentRect);
+ IntRect scissorRect(contentRect);
// The scissorRect should not include the scroll offset.
scissorRect.move(-m_scrollPosition.x(), -m_scrollPosition.y());
@@ -328,9 +334,10 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect
// Traverse the layer tree one more time to draw the layers.
for (size_t i = 0; i < sublayers.size(); i++)
- drawLayersRecursive(sublayers[i].get(), scissorRect);
+ drawLayersRecursive(sublayers[i].get());
GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST));
+ GLC(m_context, m_context->disable(GraphicsContext3D::BLEND));
}
void LayerRendererChromium::finish()
@@ -494,14 +501,14 @@ void LayerRendererChromium::drawLayerIntoStencilBuffer(LayerChromium* layer, boo
}
// Recursively walk the layer tree and draw the layers.
-void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer, const FloatRect& scissorRect)
+void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer)
{
static bool depthTestEnabledForSubtree = false;
static int currentStencilValue = 0;
// Check if the layer falls within the visible bounds of the page.
- FloatRect layerRect = layer->getDrawRect();
- bool isLayerVisible = scissorRect.intersects(layerRect);
+ IntRect layerRect = layer->getDrawRect();
+ bool isLayerVisible = m_currentScissorRect.intersects(layerRect);
// Enable depth testing for this layer and all its descendants if preserves3D is set.
bool mustClearDepth = false;
@@ -520,15 +527,16 @@ void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer, const Floa
// FIXME: We should check here if the layer has descendants that draw content
// before we setup for clipping.
- FloatRect currentScissorRect = scissorRect;
+ IntRect previousScissorRect = m_currentScissorRect;
bool mustResetScissorRect = false;
bool didStencilDraw = false;
if (layer->masksToBounds()) {
// If the layer isn't rotated then we can use scissoring otherwise we need
// to clip using the stencil buffer.
if (layer->drawTransform().isIdentityOrTranslation()) {
+ IntRect currentScissorRect = previousScissorRect;
currentScissorRect.intersect(layerRect);
- if (currentScissorRect != scissorRect) {
+ if (currentScissorRect != previousScissorRect) {
scissorToRect(currentScissorRect);
mustResetScissorRect = true;
}
@@ -573,11 +581,11 @@ void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer, const Floa
std::stable_sort(sublayerList.begin(), sublayerList.end(), compareLayerZ);
for (i = 0; i < sublayerList.size(); i++)
- drawLayersRecursive(sublayerList[i], currentScissorRect);
+ drawLayersRecursive(sublayerList[i]);
} else {
const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers();
for (size_t i = 0; i < sublayers.size(); i++)
- drawLayersRecursive(sublayers[i].get(), currentScissorRect);
+ drawLayersRecursive(sublayers[i].get());
}
if (didStencilDraw) {
@@ -593,7 +601,7 @@ void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer, const Floa
}
if (mustResetScissorRect) {
- scissorToRect(scissorRect);
+ scissorToRect(previousScissorRect);
}
if (mustClearDepth) {
@@ -629,11 +637,12 @@ void LayerRendererChromium::drawLayer(LayerChromium* layer)
// 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::scissorToRect(const FloatRect& scissorRect)
+void LayerRendererChromium::scissorToRect(const IntRect& scissorRect)
{
// Compute the lower left corner of the scissor rect.
- float bottom = std::max((float)m_rootVisibleRect.height() - scissorRect.bottom(), 0.f);
+ int bottom = std::max(m_rootVisibleRect.height() - scissorRect.bottom(), 0);
GLC(m_context, m_context->scissor(scissorRect.x(), bottom, scissorRect.width(), scissorRect.height()));
+ m_currentScissorRect = scissorRect;
}
bool LayerRendererChromium::makeContextCurrent()
diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/WebCore/platform/graphics/chromium/LayerRendererChromium.h
index b714584..6a06105 100644
--- a/WebCore/platform/graphics/chromium/LayerRendererChromium.h
+++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.h
@@ -59,9 +59,8 @@ class GraphicsContext3D;
// Class that handles drawing of composited render layers using GL.
class LayerRendererChromium : public RefCounted<LayerRendererChromium> {
public:
- static PassRefPtr<LayerRendererChromium> create(PassOwnPtr<GraphicsContext3D> graphicsContext3D);
+ static PassRefPtr<LayerRendererChromium> create(PassRefPtr<GraphicsContext3D> graphicsContext3D);
- LayerRendererChromium(PassOwnPtr<GraphicsContext3D> graphicsContext3D);
~LayerRendererChromium();
GraphicsContext3D* context();
@@ -93,6 +92,8 @@ public:
unsigned createLayerTexture();
void deleteLayerTexture(unsigned);
+ IntRect currentScissorRect() const { return m_currentScissorRect; }
+
static void debugGLCall(GraphicsContext3D*, const char* command, const char* file, int line);
const TransformationMatrix& projectionMatrix() const { return m_projectionMatrix; }
@@ -109,12 +110,15 @@ public:
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);
private:
+ explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D> graphicsContext3D);
+
void updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity);
- void drawLayersRecursive(LayerChromium*, const FloatRect& scissorRect);
+ void drawLayersRecursive(LayerChromium*);
void drawLayer(LayerChromium*);
@@ -122,7 +126,7 @@ private:
void drawLayerIntoStencilBuffer(LayerChromium*, bool decrement);
- void scissorToRect(const FloatRect&);
+ void scissorToRect(const IntRect&);
bool makeContextCurrent();
@@ -160,6 +164,8 @@ private:
IntSize m_rootLayerCanvasSize;
IntRect m_rootVisibleRect;
+ IntRect m_rootContentRect;
+ IntRect m_currentScissorRect;
int m_maxTextureSize;
@@ -174,7 +180,7 @@ private:
OwnPtr<CanvasLayerChromium::SharedValues> m_canvasLayerSharedValues;
OwnPtr<VideoLayerChromium::SharedValues> m_videoLayerSharedValues;
- OwnPtr<GraphicsContext3D> m_context;
+ RefPtr<GraphicsContext3D> m_context;
};
// Setting DEBUG_GL_CALLS to 1 will call glGetError() after almost every GL
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
index 47cc894..4dc2157 100644
--- a/WebCore/platform/graphics/chromium/TransparencyWin.cpp
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
@@ -275,7 +275,7 @@ void TransparencyWin::setupLayerForWhiteLayer()
if (!m_validLayer)
return;
- m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white, DeviceColorSpace);
+ m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white, ColorSpaceDeviceRGB);
// Layer rect represents the part of the original layer.
}
diff --git a/WebCore/platform/graphics/chromium/VideoFrameChromium.h b/WebCore/platform/graphics/chromium/VideoFrameChromium.h
index 34e922b..e176b0c 100644
--- a/WebCore/platform/graphics/chromium/VideoFrameChromium.h
+++ b/WebCore/platform/graphics/chromium/VideoFrameChromium.h
@@ -63,10 +63,7 @@ public:
enum SurfaceType {
TypeSystemMemory,
- TypeOMXBufferHead,
- TypeEGLImage,
- TypeMFBuffer,
- TypeDirect3DSurface
+ TypeTexture,
};
virtual SurfaceType surfaceType() const = 0;
@@ -76,6 +73,7 @@ public:
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;
};
diff --git a/WebCore/platform/graphics/chromium/VideoFrameProvider.h b/WebCore/platform/graphics/chromium/VideoFrameProvider.h
index f0bad08..c596f87 100644
--- a/WebCore/platform/graphics/chromium/VideoFrameProvider.h
+++ b/WebCore/platform/graphics/chromium/VideoFrameProvider.h
@@ -37,6 +37,8 @@ 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
diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp
index 26641a9..46c73a1 100644
--- a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp
+++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp
@@ -175,16 +175,22 @@ VideoLayerChromium::VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameP
, m_skipsDraw(true)
, m_frameFormat(VideoFrameChromium::Invalid)
, m_provider(provider)
+ , m_currentFrame(0)
{
- for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) {
- m_textures[plane] = 0;
- m_textureSizes[plane] = IntSize();
- m_frameSizes[plane] = IntSize();
- }
+ resetFrameParameters();
}
VideoLayerChromium::~VideoLayerChromium()
{
+ cleanupResources();
+}
+
+void VideoLayerChromium::cleanupResources()
+{
+ releaseCurrentFrame();
+ if (!layerRenderer())
+ return;
+
GraphicsContext3D* context = layerRendererContext();
for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) {
if (m_textures[plane])
@@ -218,6 +224,14 @@ void VideoLayerChromium::updateContents()
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();
@@ -236,6 +250,7 @@ void VideoLayerChromium::updateContents()
m_dirtyRect.setSize(FloatSize());
m_contentsDirty = false;
+
m_provider->putCurrentFrame(frame);
}
@@ -319,6 +334,17 @@ void VideoLayerChromium::draw()
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)
@@ -370,6 +396,26 @@ void VideoLayerChromium::drawRGBA(const SharedValues* sv)
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/WebCore/platform/graphics/chromium/VideoLayerChromium.h b/WebCore/platform/graphics/chromium/VideoLayerChromium.h
index 620d1a7..05b6578 100644
--- a/WebCore/platform/graphics/chromium/VideoLayerChromium.h
+++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.h
@@ -49,6 +49,10 @@ public:
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*);
@@ -66,7 +70,7 @@ public:
int rgbaAlphaLocation() const { return m_rgbaAlphaLocation; }
int rgbaTextureLocation() const { return m_rgbaTextureLocation; }
int ccMatrixLocation() const { return m_ccMatrixLocation; }
- bool initialized() const { return m_initialized; };
+ bool initialized() const { return m_initialized; }
private:
GraphicsContext3D* m_context;
unsigned m_yuvShaderProgram;
@@ -85,8 +89,12 @@ public:
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*);
@@ -95,12 +103,16 @@ private:
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;
- OwnPtr<VideoFrameProvider> m_provider;
+ VideoFrameProvider* m_provider;
+ VideoFrameChromium* m_currentFrame;
+
unsigned m_textures[3];
IntSize m_textureSizes[3];
IntSize m_frameSizes[3];
diff --git a/WebCore/platform/graphics/efl/ImageEfl.cpp b/WebCore/platform/graphics/efl/ImageEfl.cpp
index 112770f..a86ba4e 100644
--- a/WebCore/platform/graphics/efl/ImageEfl.cpp
+++ b/WebCore/platform/graphics/efl/ImageEfl.cpp
@@ -32,6 +32,7 @@
#include "BitmapImage.h"
#include "SharedBuffer.h"
+#include <wtf/text/StringConcatenate.h>
#include <cairo.h>
namespace WebCore {
@@ -51,7 +52,7 @@ static PassRefPtr<SharedBuffer> loadResourceSharedBufferFallback()
static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(const char* name)
{
- RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(String::format(DATA_DIR "/webkit-1.0/images/%s.png", name));
+ RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(makeString(DATA_DIR "/webkit-1.0/images/", name, ".png"));
if (buffer)
return buffer.release();
return loadResourceSharedBufferFallback();
diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp b/WebCore/platform/graphics/efl/IntRectEfl.cpp
index 12407f8..0c92f63 100644
--- a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp
+++ b/WebCore/platform/graphics/efl/IntRectEfl.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
- * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org>
+ * 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
@@ -19,25 +19,22 @@
*/
#include "config.h"
+#include "IntRect.h"
-#if ENABLE(FILTERS)
-#include "ImageBufferFilter.h"
-
-#include "FloatSize.h"
+#include <Eina.h>
namespace WebCore {
-ImageBufferFilter::ImageBufferFilter()
- : Filter()
+IntRect::IntRect(const Eina_Rectangle& r)
+ : m_location(IntPoint(r.x, r.y))
+ , m_size(r.w, r.h)
{
- setFilterResolution(FloatSize(1.f, 1.f));
}
-PassRefPtr<ImageBufferFilter> ImageBufferFilter::create()
+IntRect::operator Eina_Rectangle() const
{
- return adoptRef(new ImageBufferFilter());
+ Eina_Rectangle r = {x(), y(), width(), height()};
+ return r;
}
-} // namespace WebCore
-
-#endif // ENABLE(FILTERS)
+}
diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp
index 4185f61..1a40027 100644
--- a/WebCore/platform/graphics/filters/FEBlend.cpp
+++ b/WebCore/platform/graphics/filters/FEBlend.cpp
@@ -98,13 +98,13 @@ void FEBlend::apply(Filter* filter)
if (m_mode == FEBLEND_MODE_UNKNOWN)
return;
- if (!effectContext())
+ if (!effectContext(filter))
return;
- IntRect effectADrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates());
+ IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data());
- IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->repaintRectInLocalCoordinates());
+ IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
RefPtr<CanvasPixelArray> srcPixelArrayB(in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)->data());
IntRect imageRect(IntPoint(), resultImage()->size());
diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
index 86c37c2..b41d5ad 100644
--- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp
+++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
@@ -160,11 +160,11 @@ void FEColorMatrix::apply(Filter* filter)
if (!in->resultImage())
return;
- GraphicsContext* filterContext = effectContext();
+ GraphicsContext* filterContext = effectContext(filter);
if (!filterContext)
return;
- filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()));
+ filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
IntRect imageRect(IntPoint(), resultImage()->size());
PassRefPtr<ImageData> imageData(resultImage()->getUnmultipliedImageData(imageRect));
diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
index 6fe38e4..08d0b1f 100644
--- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
+++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
@@ -154,7 +154,7 @@ void FEComponentTransfer::apply(Filter* filter)
if (!in->resultImage())
return;
- if (!effectContext())
+ if (!effectContext(filter))
return;
unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
@@ -167,7 +167,7 @@ void FEComponentTransfer::apply(Filter* filter)
for (unsigned channel = 0; channel < 4; channel++)
(*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]);
- IntRect drawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates());
+ IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
RefPtr<ImageData> imageData(in->resultImage()->getUnmultipliedImageData(drawingRect));
CanvasPixelArray* srcPixelArray(imageData->data());
diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp
index 94e2524..2326966 100644
--- a/WebCore/platform/graphics/filters/FEComposite.cpp
+++ b/WebCore/platform/graphics/filters/FEComposite.cpp
@@ -3,6 +3,7 @@
* 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
@@ -112,6 +113,27 @@ inline void arithmetic(const RefPtr<CanvasPixelArray>& srcPixelArrayA, CanvasPix
}
}
}
+
+void FEComposite::determineAbsolutePaintRect(Filter* filter)
+{
+ 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(filter);
+ return;
+ }
+}
void FEComposite::apply(Filter* filter)
{
@@ -122,39 +144,39 @@ void FEComposite::apply(Filter* filter)
if (!in->resultImage() || !in2->resultImage())
return;
- GraphicsContext* filterContext = effectContext();
+ GraphicsContext* filterContext = effectContext(filter);
if (!filterContext)
return;
FloatRect srcRect = FloatRect(0, 0, -1, -1);
switch (m_type) {
case FECOMPOSITE_OPERATOR_OVER:
- filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates()));
- filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()));
+ filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
+ filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
break;
case FECOMPOSITE_OPERATOR_IN:
filterContext->save();
- filterContext->clipToImageBuffer(in2->resultImage(), drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates()));
- filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()));
+ filterContext->clipToImageBuffer(in2->resultImage(), drawingRegionOfInputImage(in2->absolutePaintRect()));
+ filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
filterContext->restore();
break;
case FECOMPOSITE_OPERATOR_OUT:
- filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()));
- filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates()), srcRect, CompositeDestinationOut);
+ filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+ filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut);
break;
case FECOMPOSITE_OPERATOR_ATOP:
- filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates()));
- filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()), srcRect, CompositeSourceAtop);
+ filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
+ filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop);
break;
case FECOMPOSITE_OPERATOR_XOR:
- filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates()));
- filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()), srcRect, CompositeXOR);
+ filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
+ filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR);
break;
case FECOMPOSITE_OPERATOR_ARITHMETIC: {
- IntRect effectADrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates());
+ IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data());
- IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->repaintRectInLocalCoordinates());
+ IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
RefPtr<ImageData> imageData(in2->resultImage()->getPremultipliedImageData(effectBDrawingRect));
CanvasPixelArray* srcPixelArrayB(imageData->data());
diff --git a/WebCore/platform/graphics/filters/FEComposite.h b/WebCore/platform/graphics/filters/FEComposite.h
index 82a3b06..ecdb037 100644
--- a/WebCore/platform/graphics/filters/FEComposite.h
+++ b/WebCore/platform/graphics/filters/FEComposite.h
@@ -61,6 +61,8 @@ public:
virtual void apply(Filter*);
virtual void dump();
+
+ virtual void determineAbsolutePaintRect(Filter*);
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
diff --git a/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp
index dd66c6a..d487a47 100644
--- a/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp
+++ b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp
@@ -377,11 +377,11 @@ void FEConvolveMatrix::apply(Filter* filter)
if (!in->resultImage())
return;
- if (!effectContext())
+ if (!effectContext(filter))
return;
IntRect imageRect(IntPoint(), resultImage()->size());
- IntRect effectDrawingRect = requestedRegionOfInputImageData(in->filterPrimitiveSubregion());
+ IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
RefPtr<CanvasPixelArray> srcPixelArray;
if (m_preserveAlpha)
diff --git a/WebCore/platform/graphics/filters/FEConvolveMatrix.h b/WebCore/platform/graphics/filters/FEConvolveMatrix.h
index 2fe634f..8d3439e 100644
--- a/WebCore/platform/graphics/filters/FEConvolveMatrix.h
+++ b/WebCore/platform/graphics/filters/FEConvolveMatrix.h
@@ -75,6 +75,8 @@ public:
virtual void apply(Filter*);
virtual void dump();
+ virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); }
+
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
private:
diff --git a/WebCore/platform/graphics/filters/FEDisplacementMap.cpp b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp
index 6b5dbaa..0c53241 100644
--- a/WebCore/platform/graphics/filters/FEDisplacementMap.cpp
+++ b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp
@@ -3,6 +3,7 @@
* 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
@@ -88,13 +89,13 @@ void FEDisplacementMap::apply(Filter* filter)
if (m_xChannelSelector == CHANNEL_UNKNOWN || m_yChannelSelector == CHANNEL_UNKNOWN)
return;
- if (!effectContext())
+ if (!effectContext(filter))
return;
- IntRect effectADrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates());
+ IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data());
- IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->repaintRectInLocalCoordinates());
+ IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
RefPtr<CanvasPixelArray> srcPixelArrayB(in2->resultImage()->getUnmultipliedImageData(effectBDrawingRect)->data());
IntRect imageRect(IntPoint(), resultImage()->size());
@@ -102,10 +103,10 @@ void FEDisplacementMap::apply(Filter* filter)
ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length());
- float scaleX = m_scale / 255.f * filter->filterResolution().width();
- float scaleY = m_scale / 255.f * filter->filterResolution().height();
- float scaleAdjustmentX = (0.5f - 0.5f * m_scale) * filter->filterResolution().width();
- float scaleAdjustmentY = (0.5f - 0.5f * m_scale) * filter->filterResolution().height();
+ 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 = imageRect.width() * 4;
for (int y = 0; y < imageRect.height(); ++y) {
int line = y * stride;
diff --git a/WebCore/platform/graphics/filters/FEDisplacementMap.h b/WebCore/platform/graphics/filters/FEDisplacementMap.h
index dc87b90..c5b97a7 100644
--- a/WebCore/platform/graphics/filters/FEDisplacementMap.h
+++ b/WebCore/platform/graphics/filters/FEDisplacementMap.h
@@ -53,6 +53,8 @@ public:
virtual void apply(Filter*);
virtual void dump();
+ virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); }
+
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
private:
diff --git a/WebCore/platform/graphics/filters/FEFlood.cpp b/WebCore/platform/graphics/filters/FEFlood.cpp
index 7804d89..b51a422 100644
--- a/WebCore/platform/graphics/filters/FEFlood.cpp
+++ b/WebCore/platform/graphics/filters/FEFlood.cpp
@@ -62,14 +62,14 @@ void FEFlood::setFloodOpacity(float floodOpacity)
m_floodOpacity = floodOpacity;
}
-void FEFlood::apply(Filter*)
+void FEFlood::apply(Filter* filter)
{
- GraphicsContext* filterContext = effectContext();
+ GraphicsContext* filterContext = effectContext(filter);
if (!filterContext)
return;
Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity());
- filterContext->fillRect(FloatRect(FloatPoint(), repaintRectInLocalCoordinates().size()), color, DeviceColorSpace);
+ filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color, ColorSpaceDeviceRGB);
}
void FEFlood::dump()
diff --git a/WebCore/platform/graphics/filters/FEFlood.h b/WebCore/platform/graphics/filters/FEFlood.h
index b615531..e6a9574 100644
--- a/WebCore/platform/graphics/filters/FEFlood.h
+++ b/WebCore/platform/graphics/filters/FEFlood.h
@@ -42,6 +42,8 @@ public:
virtual void apply(Filter*);
virtual void dump();
+ virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); }
+
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
private:
diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
index fd9a3d8..1f36ba7 100644
--- a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
+++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
@@ -4,6 +4,7 @@
* 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
@@ -34,7 +35,8 @@
using std::max;
-static const float gGaussianKernelFactor = (3 * sqrtf(2 * piFloat) / 4.f);
+static const float gGaussianKernelFactor = 3 / 4.f * sqrtf(2 * piFloat);
+static const unsigned gMaxKernelSize = 1000;
namespace WebCore {
@@ -97,7 +99,7 @@ static void boxBlur(CanvasPixelArray*& srcPixelArray, CanvasPixelArray*& dstPixe
}
}
-void FEGaussianBlur::kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight)
+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) {
@@ -125,6 +127,41 @@ void FEGaussianBlur::kernelPosition(int boxBlur, unsigned& std, int& dLeft, int&
}
}
+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(Filter* filter)
+{
+ 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(Filter* filter)
{
FilterEffect* in = inputEffect(0);
@@ -132,12 +169,12 @@ void FEGaussianBlur::apply(Filter* filter)
if (!in->resultImage())
return;
- if (!effectContext())
+ if (!effectContext(filter))
return;
setIsAlphaImage(in->isAlphaImage());
- IntRect effectDrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates());
+ IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
RefPtr<ImageData> srcImageData(in->resultImage()->getPremultipliedImageData(effectDrawingRect));
IntRect imageRect(IntPoint(), resultImage()->size());
@@ -147,12 +184,8 @@ void FEGaussianBlur::apply(Filter* filter)
}
unsigned kernelSizeX = 0;
- if (m_stdX)
- kernelSizeX = max(2U, static_cast<unsigned>(floor(m_stdX * filter->filterResolution().width() * gGaussianKernelFactor + 0.5f)));
-
unsigned kernelSizeY = 0;
- if (m_stdY)
- kernelSizeY = max(2U, static_cast<unsigned>(floor(m_stdY * filter->filterResolution().height() * gGaussianKernelFactor + 0.5f)));
+ calculateKernelSize(filter, kernelSizeX, kernelSizeY, m_stdX, m_stdY);
CanvasPixelArray* srcPixelArray(srcImageData->data());
RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height());
diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.h b/WebCore/platform/graphics/filters/FEGaussianBlur.h
index 745bcc8..50fc610 100644
--- a/WebCore/platform/graphics/filters/FEGaussianBlur.h
+++ b/WebCore/platform/graphics/filters/FEGaussianBlur.h
@@ -42,12 +42,13 @@ public:
virtual void apply(Filter*);
virtual void dump();
+
+ virtual void determineAbsolutePaintRect(Filter*);
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
private:
FEGaussianBlur(float, float);
- static void kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight);
float m_stdX;
float m_stdY;
diff --git a/WebCore/platform/graphics/filters/FELighting.cpp b/WebCore/platform/graphics/filters/FELighting.cpp
index f49b67d..e1df580 100644
--- a/WebCore/platform/graphics/filters/FELighting.cpp
+++ b/WebCore/platform/graphics/filters/FELighting.cpp
@@ -247,12 +247,12 @@ void FELighting::apply(Filter* filter)
if (!in->resultImage())
return;
- if (!effectContext())
+ if (!effectContext(filter))
return;
setIsAlphaImage(false);
- IntRect effectDrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates());
+ IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
RefPtr<ImageData> srcImageData(in->resultImage()->getUnmultipliedImageData(effectDrawingRect));
CanvasPixelArray* srcPixelArray(srcImageData->data());
@@ -261,8 +261,9 @@ void FELighting::apply(Filter* filter)
// output for various kernelUnitLengths, and I am not sure they are reliable.
// Anyway, feConvolveMatrix should also use the implementation
- if (drawLighting(srcPixelArray, effectDrawingRect.width(), effectDrawingRect.height()))
- resultImage()->putUnmultipliedImageData(srcImageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint());
+ IntSize absolutePaintSize = absolutePaintRect().size();
+ if (drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height()))
+ resultImage()->putUnmultipliedImageData(srcImageData.get(), IntRect(IntPoint(), absolutePaintSize), IntPoint());
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/filters/FELighting.h b/WebCore/platform/graphics/filters/FELighting.h
index 28c00c4..bd56cee 100644
--- a/WebCore/platform/graphics/filters/FELighting.h
+++ b/WebCore/platform/graphics/filters/FELighting.h
@@ -44,6 +44,8 @@ class FELighting : public FilterEffect {
public:
virtual void apply(Filter*);
+ virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); }
+
protected:
enum LightingType {
DiffuseLighting,
diff --git a/WebCore/platform/graphics/filters/FEMerge.cpp b/WebCore/platform/graphics/filters/FEMerge.cpp
index 19c832a..b136af3 100644
--- a/WebCore/platform/graphics/filters/FEMerge.cpp
+++ b/WebCore/platform/graphics/filters/FEMerge.cpp
@@ -50,13 +50,13 @@ void FEMerge::apply(Filter* filter)
return;
}
- GraphicsContext* filterContext = effectContext();
+ GraphicsContext* filterContext = effectContext(filter);
if (!filterContext)
return;
for (unsigned i = 0; i < size; ++i) {
FilterEffect* in = inputEffect(i);
- filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()));
+ filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
}
}
diff --git a/WebCore/platform/graphics/filters/FEMorphology.cpp b/WebCore/platform/graphics/filters/FEMorphology.cpp
index 7329e1e..ac26441 100644
--- a/WebCore/platform/graphics/filters/FEMorphology.cpp
+++ b/WebCore/platform/graphics/filters/FEMorphology.cpp
@@ -3,6 +3,7 @@
* 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
@@ -74,6 +75,15 @@ float FEMorphology::radiusY() const
return m_radiusY;
}
+void FEMorphology::determineAbsolutePaintRect(Filter* filter)
+{
+ FloatRect paintRect = inputEffect(0)->absolutePaintRect();
+ 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;
@@ -86,18 +96,18 @@ void FEMorphology::apply(Filter* filter)
if (!in->resultImage())
return;
- if (!effectContext())
+ if (!effectContext(filter))
return;
setIsAlphaImage(in->isAlphaImage());
-
- int radiusX = static_cast<int>(m_radiusX * filter->filterResolution().width());
- int radiusY = static_cast<int>(m_radiusY * filter->filterResolution().height());
- if (radiusX <= 0 || radiusY <= 0)
+ if (m_radiusX <= 0 || m_radiusY <= 0)
return;
+ int radiusX = static_cast<int>(floorf(filter->applyHorizontalScale(m_radiusX)));
+ int radiusY = static_cast<int>(floorf(filter->applyVerticalScale(m_radiusY)));
+
IntRect imageRect(IntPoint(), resultImage()->size());
- IntRect effectDrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates());
+ IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
RefPtr<CanvasPixelArray> srcPixelArray(in->resultImage()->getPremultipliedImageData(effectDrawingRect)->data());
RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height());
diff --git a/WebCore/platform/graphics/filters/FEMorphology.h b/WebCore/platform/graphics/filters/FEMorphology.h
index c8ce058..913671d 100644
--- a/WebCore/platform/graphics/filters/FEMorphology.h
+++ b/WebCore/platform/graphics/filters/FEMorphology.h
@@ -49,6 +49,8 @@ public:
virtual void apply(Filter*);
virtual void dump();
+ virtual void determineAbsolutePaintRect(Filter*);
+
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
private:
diff --git a/WebCore/platform/graphics/filters/FEOffset.cpp b/WebCore/platform/graphics/filters/FEOffset.cpp
index ea84cf0..6ca56aa 100644
--- a/WebCore/platform/graphics/filters/FEOffset.cpp
+++ b/WebCore/platform/graphics/filters/FEOffset.cpp
@@ -3,6 +3,7 @@
* 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
@@ -62,6 +63,14 @@ void FEOffset::setDy(float dy)
m_dy = dy;
}
+void FEOffset::determineAbsolutePaintRect(Filter* filter)
+{
+ FloatRect paintRect = inputEffect(0)->absolutePaintRect();
+ paintRect.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy));
+ paintRect.intersect(maxEffectRect());
+ setAbsolutePaintRect(enclosingIntRect(paintRect));
+}
+
void FEOffset::apply(Filter* filter)
{
FilterEffect* in = inputEffect(0);
@@ -69,28 +78,15 @@ void FEOffset::apply(Filter* filter)
if (!in->resultImage())
return;
- GraphicsContext* filterContext = effectContext();
+ GraphicsContext* filterContext = effectContext(filter);
if (!filterContext)
return;
setIsAlphaImage(in->isAlphaImage());
- FloatRect sourceImageRect = filter->sourceImageRect();
- sourceImageRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
-
- if (filter->effectBoundingBoxMode()) {
- m_dx *= sourceImageRect.width();
- m_dy *= sourceImageRect.height();
- }
- m_dx *= filter->filterResolution().width();
- m_dy *= filter->filterResolution().height();
-
- FloatRect dstRect = FloatRect(m_dx + in->repaintRectInLocalCoordinates().x() - repaintRectInLocalCoordinates().x(),
- m_dy + in->repaintRectInLocalCoordinates().y() - repaintRectInLocalCoordinates().y(),
- in->repaintRectInLocalCoordinates().width(),
- in->repaintRectInLocalCoordinates().height());
-
- filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, dstRect);
+ FloatRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect());
+ drawingRegion.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy));
+ filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegion);
}
void FEOffset::dump()
diff --git a/WebCore/platform/graphics/filters/FEOffset.h b/WebCore/platform/graphics/filters/FEOffset.h
index 052ba74..36575c5 100644
--- a/WebCore/platform/graphics/filters/FEOffset.h
+++ b/WebCore/platform/graphics/filters/FEOffset.h
@@ -40,6 +40,8 @@ public:
virtual void apply(Filter*);
virtual void dump();
+
+ virtual void determineAbsolutePaintRect(Filter*);
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
diff --git a/WebCore/platform/graphics/filters/FETile.cpp b/WebCore/platform/graphics/filters/FETile.cpp
index 41abd34..a695d3b 100644
--- a/WebCore/platform/graphics/filters/FETile.cpp
+++ b/WebCore/platform/graphics/filters/FETile.cpp
@@ -27,6 +27,7 @@
#include "Filter.h"
#include "GraphicsContext.h"
#include "Pattern.h"
+#include "SVGImageBufferTools.h"
namespace WebCore {
@@ -44,45 +45,51 @@ FloatRect FETile::determineFilterPrimitiveSubregion(Filter* filter)
{
inputEffect(0)->determineFilterPrimitiveSubregion(filter);
- filter->determineFilterPrimitiveSubregion(this, filter->filterRegion());
+ filter->determineFilterPrimitiveSubregion(this, filter->filterRegionInUserSpace());
return filterPrimitiveSubregion();
}
void FETile::apply(Filter* filter)
{
+// FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise.
+#if ENABLE(SVG)
FilterEffect* in = inputEffect(0);
in->apply(filter);
if (!in->resultImage())
return;
- GraphicsContext* filterContext = effectContext();
+ GraphicsContext* filterContext = effectContext(filter);
if (!filterContext)
return;
setIsAlphaImage(in->isAlphaImage());
- IntRect tileRect = enclosingIntRect(in->repaintRectInLocalCoordinates());
-
// 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.
- if (in->isSourceInput()) {
- FloatRect filterRegion = filter->filterRegion();
- filterRegion.scale(filter->filterResolution().width(), filter->filterResolution().height());
- tileRect = enclosingIntRect(filterRegion);
+ FloatRect tileRect = in->maxEffectRect();
+ FloatPoint inMaxEffectLocation = tileRect.location();
+ FloatPoint maxEffectLocation = maxEffectRect().location();
+ if (in->filterEffectType() == FilterEffectTypeSourceInput) {
+ tileRect = filter->filterRegion();
+ tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
}
- OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(tileRect.size());
+ OwnPtr<ImageBuffer> tileImage;
+ if (!SVGImageBufferTools::createImageBuffer(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB))
+ return;
+
GraphicsContext* tileImageContext = tileImage->context();
- tileImageContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, IntPoint());
- RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true);
+ tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y());
+ tileImageContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, in->absolutePaintRect().location());
- AffineTransform matrix;
- matrix.translate(in->repaintRectInLocalCoordinates().x() - repaintRectInLocalCoordinates().x(),
- in->repaintRectInLocalCoordinates().y() - repaintRectInLocalCoordinates().y());
- pattern.get()->setPatternSpaceTransform(matrix);
+ RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true);
+ AffineTransform patternTransform;
+ patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y());
+ pattern->setPatternSpaceTransform(patternTransform);
filterContext->setFillPattern(pattern);
- filterContext->fillRect(FloatRect(FloatPoint(), repaintRectInLocalCoordinates().size()));
+ filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()));
+#endif
}
void FETile::dump()
@@ -103,4 +110,3 @@ TextStream& FETile::externalRepresentation(TextStream& ts, int indent) const
} // namespace WebCore
#endif // ENABLE(FILTERS)
-
diff --git a/WebCore/platform/graphics/filters/FETile.h b/WebCore/platform/graphics/filters/FETile.h
index 20efbcd..8562c90 100644
--- a/WebCore/platform/graphics/filters/FETile.h
+++ b/WebCore/platform/graphics/filters/FETile.h
@@ -35,6 +35,8 @@ public:
virtual void apply(Filter*);
virtual void dump();
+ virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); }
+
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
virtual FloatRect determineFilterPrimitiveSubregion(Filter*);
diff --git a/WebCore/platform/graphics/filters/FETurbulence.cpp b/WebCore/platform/graphics/filters/FETurbulence.cpp
index bb24362..b1494a5 100644
--- a/WebCore/platform/graphics/filters/FETurbulence.cpp
+++ b/WebCore/platform/graphics/filters/FETurbulence.cpp
@@ -321,7 +321,7 @@ unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paint
void FETurbulence::apply(Filter* filter)
{
- if (!effectContext())
+ if (!effectContext(filter))
return;
IntRect imageRect(IntPoint(), resultImage()->size());
@@ -329,10 +329,10 @@ void FETurbulence::apply(Filter* filter)
return;
RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height());
- PaintingData paintingData(m_seed, imageRect.size());
+ PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size()));
initPaint(paintingData);
- FloatRect filterRegion = filter->filterRegion();
+ FloatRect filterRegion = absolutePaintRect();
FloatPoint point;
point.setY(filterRegion.y());
int indexOfPixelChannel = 0;
@@ -342,7 +342,7 @@ void FETurbulence::apply(Filter* filter)
for (int x = 0; x < imageRect.width(); ++x) {
point.setX(point.x() + 1);
for (paintingData.channel = 0; paintingData.channel < 4; ++paintingData.channel, ++indexOfPixelChannel)
- imageData->data()->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, point));
+ imageData->data()->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, filter->mapAbsolutePointToLocalPoint(point)));
}
}
resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint());
diff --git a/WebCore/platform/graphics/filters/FETurbulence.h b/WebCore/platform/graphics/filters/FETurbulence.h
index 1a5a28a..c15d7d1 100644
--- a/WebCore/platform/graphics/filters/FETurbulence.h
+++ b/WebCore/platform/graphics/filters/FETurbulence.h
@@ -60,6 +60,8 @@ public:
virtual void apply(Filter*);
virtual void dump();
+
+ virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); }
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
diff --git a/WebCore/platform/graphics/filters/Filter.h b/WebCore/platform/graphics/filters/Filter.h
index bce4be3..121e389 100644
--- a/WebCore/platform/graphics/filters/Filter.h
+++ b/WebCore/platform/graphics/filters/Filter.h
@@ -44,11 +44,18 @@ namespace WebCore {
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(); }
// SVG specific
virtual void determineFilterPrimitiveSubregion(FilterEffect*, const FloatRect&) { }
+
+ virtual FloatRect filterRegionInUserSpace() const { return FloatRect(); }
virtual FloatSize maxImageSize() const = 0;
virtual bool effectBoundingBoxMode() const = 0;
diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp
index 461b22a..121b921 100644
--- a/WebCore/platform/graphics/filters/FilterEffect.cpp
+++ b/WebCore/platform/graphics/filters/FilterEffect.cpp
@@ -46,7 +46,7 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(Filter* filter)
// FETurbulence, FEImage and FEFlood don't have input effects, take the filter region as unite rect.
if (!size)
- uniteRect = filter->filterRegion();
+ uniteRect = filter->filterRegionInUserSpace();
else {
for (unsigned i = 0; i < size; ++i)
uniteRect.unite(m_inputEffects.at(i)->determineFilterPrimitiveSubregion(filter));
@@ -56,18 +56,29 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(Filter* filter)
return m_filterPrimitiveSubregion;
}
-IntRect FilterEffect::requestedRegionOfInputImageData(const FloatRect& effectRect) const
+void FilterEffect::determineAbsolutePaintRect(Filter*)
+{
+ 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(m_effectBuffer);
- FloatPoint location = m_repaintRectInLocalCoordinates.location();
+ IntPoint location = m_absolutePaintRect.location();
location.move(-effectRect.x(), -effectRect.y());
- return IntRect(roundedIntPoint(location), m_effectBuffer->size());
+ return IntRect(location, m_effectBuffer->size());
}
-FloatRect FilterEffect::drawingRegionOfInputImage(const FloatRect& srcRect) const
+IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
{
- return FloatRect(FloatPoint(srcRect.x() - m_repaintRectInLocalCoordinates.x(),
- srcRect.y() - m_repaintRectInLocalCoordinates.y()), srcRect.size());
+ return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(),
+ srcRect.y() - m_absolutePaintRect.y()), srcRect.size());
}
FilterEffect* FilterEffect::inputEffect(unsigned number) const
@@ -76,10 +87,12 @@ FilterEffect* FilterEffect::inputEffect(unsigned number) const
return m_inputEffects.at(number).get();
}
-GraphicsContext* FilterEffect::effectContext()
+GraphicsContext* FilterEffect::effectContext(Filter* filter)
{
- IntRect bufferRect = enclosingIntRect(m_repaintRectInLocalCoordinates);
- m_effectBuffer = ImageBuffer::create(bufferRect.size(), LinearRGB);
+ determineAbsolutePaintRect(filter);
+ if (m_absolutePaintRect.isEmpty())
+ return 0;
+ m_effectBuffer = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
if (!m_effectBuffer)
return 0;
return m_effectBuffer->context();
diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h
index ebe1880..a614b59 100644
--- a/WebCore/platform/graphics/filters/FilterEffect.h
+++ b/WebCore/platform/graphics/filters/FilterEffect.h
@@ -39,6 +39,13 @@ namespace WebCore {
typedef Vector<RefPtr<FilterEffect> > FilterEffectVector;
+enum FilterEffectType {
+ FilterEffectTypeUnknown,
+ FilterEffectTypeImage,
+ FilterEffectTypeTile,
+ FilterEffectTypeSourceInput
+};
+
class FilterEffect : public RefCounted<FilterEffect> {
public:
virtual ~FilterEffect();
@@ -49,26 +56,31 @@ public:
// Creates the ImageBuffer for the current filter primitive result in the size of the
// repaintRect. Gives back the GraphicsContext of the own ImageBuffer.
- GraphicsContext* effectContext();
+ GraphicsContext* effectContext(Filter*);
FilterEffectVector& inputEffects() { return m_inputEffects; }
FilterEffect* inputEffect(unsigned) const;
unsigned numberOfEffectInputs() const { return m_inputEffects.size(); }
- FloatRect drawingRegionOfInputImage(const FloatRect&) const;
- IntRect requestedRegionOfInputImageData(const FloatRect&) const;
+ 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; }
- FloatRect repaintRectInLocalCoordinates() const { return m_repaintRectInLocalCoordinates; }
- void setRepaintRectInLocalCoordinates(const FloatRect& repaintRectInLocalCoordinates) { m_repaintRectInLocalCoordinates = repaintRectInLocalCoordinates; }
+ 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(Filter*) = 0;
virtual void dump() = 0;
- virtual bool isSourceInput() const { return false; }
+ virtual void determineAbsolutePaintRect(Filter*);
+
+ virtual FilterEffectType filterEffectType() const { return FilterEffectTypeUnknown; }
virtual TextStream& externalRepresentation(TextStream&, int indention = 0) const;
@@ -87,7 +99,7 @@ public:
bool hasHeight() const { return m_hasHeight; }
void setHasHeight(bool value) { m_hasHeight = value; }
- // FIXME: Pseudo primitives like SourceGraphic and SourceAlpha as well as FETile still need special handling.
+ // FIXME: FETile still needs special handling.
virtual FloatRect determineFilterPrimitiveSubregion(Filter*);
FloatRect filterPrimitiveSubregion() const { return m_filterPrimitiveSubregion; }
@@ -105,8 +117,11 @@ private:
bool m_alphaImage;
- // FIXME: Should be the paint region of the filter primitive, instead of the scaled subregion on use of filterRes.
- FloatRect m_repaintRectInLocalCoordinates;
+ 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;
private:
// The following member variables are SVG specific and will move to RenderSVGResourceFilterPrimitive.
diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.h b/WebCore/platform/graphics/filters/ImageBufferFilter.h
deleted file mode 100644
index cd4bc2f..0000000
--- a/WebCore/platform/graphics/filters/ImageBufferFilter.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
- * Copyright (C) 2009 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 ImageBufferFilter_h
-#define ImageBufferFilter_h
-
-#if ENABLE(FILTERS)
-#include "Filter.h"
-#include "FilterEffect.h"
-#include "FloatRect.h"
-#include "FloatSize.h"
-
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
-
-namespace WebCore {
-
-class ImageBufferFilter : public Filter {
-public:
- static PassRefPtr<ImageBufferFilter> create();
-
- virtual FloatRect filterRegion() const { return FloatRect(); }
- virtual FloatRect sourceImageRect() const { return FloatRect(); }
-
- // SVG specific
- virtual bool effectBoundingBoxMode() const { return false; }
-
- virtual FloatSize maxImageSize() const { return FloatSize(); }
- virtual void calculateEffectSubRegion(FilterEffect*) { }
-
-private:
- ImageBufferFilter();
-};
-
-} // namespace WebCore
-
-#endif // ENABLE(FILTERS)
-
-#endif // ImageBufferFilter_h
diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp
index beaf2e7..7dc56d9 100644
--- a/WebCore/platform/graphics/filters/SourceAlpha.cpp
+++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp
@@ -42,31 +42,25 @@ const AtomicString& SourceAlpha::effectName()
return s_effectName;
}
-FloatRect SourceAlpha::determineFilterPrimitiveSubregion(Filter* filter)
+void SourceAlpha::determineAbsolutePaintRect(Filter* filter)
{
- FloatRect clippedSourceRect = filter->sourceImageRect();
- if (filter->sourceImageRect().x() < filter->filterRegion().x())
- clippedSourceRect.setX(filter->filterRegion().x());
- if (filter->sourceImageRect().y() < filter->filterRegion().y())
- clippedSourceRect.setY(filter->filterRegion().y());
- setFilterPrimitiveSubregion(clippedSourceRect);
- clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
- setRepaintRectInLocalCoordinates(clippedSourceRect);
- return filter->filterRegion();
+ FloatRect paintRect = filter->sourceImageRect();
+ paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
+ setAbsolutePaintRect(enclosingIntRect(paintRect));
}
void SourceAlpha::apply(Filter* filter)
{
- GraphicsContext* filterContext = effectContext();
- if (!filterContext)
+ GraphicsContext* filterContext = effectContext(filter);
+ if (!filterContext || !filter->sourceImage())
return;
setIsAlphaImage(true);
- FloatRect imageRect(FloatPoint(), filter->sourceImage()->size());
+ FloatRect imageRect(FloatPoint(), absolutePaintRect().size());
filterContext->save();
filterContext->clipToImageBuffer(filter->sourceImage(), imageRect);
- filterContext->fillRect(imageRect, Color::black, DeviceColorSpace);
+ filterContext->fillRect(imageRect, Color::black, ColorSpaceDeviceRGB);
filterContext->restore();
}
diff --git a/WebCore/platform/graphics/filters/SourceAlpha.h b/WebCore/platform/graphics/filters/SourceAlpha.h
index f0fa319..83704e5 100644
--- a/WebCore/platform/graphics/filters/SourceAlpha.h
+++ b/WebCore/platform/graphics/filters/SourceAlpha.h
@@ -34,12 +34,12 @@ public:
static const AtomicString& effectName();
- virtual FloatRect determineFilterPrimitiveSubregion(Filter*);
-
virtual void apply(Filter*);
virtual void dump();
- virtual bool isSourceInput() const { return true; }
+ virtual void determineAbsolutePaintRect(Filter*);
+
+ virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; }
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp
index c014e68..fbb711a 100644
--- a/WebCore/platform/graphics/filters/SourceGraphic.cpp
+++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp
@@ -41,26 +41,20 @@ const AtomicString& SourceGraphic::effectName()
return s_effectName;
}
-FloatRect SourceGraphic::determineFilterPrimitiveSubregion(Filter* filter)
+void SourceGraphic::determineAbsolutePaintRect(Filter* filter)
{
- FloatRect clippedSourceRect = filter->sourceImageRect();
- if (filter->sourceImageRect().x() < filter->filterRegion().x())
- clippedSourceRect.setX(filter->filterRegion().x());
- if (filter->sourceImageRect().y() < filter->filterRegion().y())
- clippedSourceRect.setY(filter->filterRegion().y());
- setFilterPrimitiveSubregion(clippedSourceRect);
- clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
- setRepaintRectInLocalCoordinates(clippedSourceRect);
- return filter->filterRegion();
+ FloatRect paintRect = filter->sourceImageRect();
+ paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
+ setAbsolutePaintRect(enclosingIntRect(paintRect));
}
void SourceGraphic::apply(Filter* filter)
{
- GraphicsContext* filterContext = effectContext();
- if (!filterContext)
+ GraphicsContext* filterContext = effectContext(filter);
+ if (!filterContext || !filter->sourceImage())
return;
- filterContext->drawImageBuffer(filter->sourceImage(), DeviceColorSpace, IntPoint());
+ filterContext->drawImageBuffer(filter->sourceImage(), ColorSpaceDeviceRGB, IntPoint());
}
void SourceGraphic::dump()
diff --git a/WebCore/platform/graphics/filters/SourceGraphic.h b/WebCore/platform/graphics/filters/SourceGraphic.h
index 2378798..a13337d 100644
--- a/WebCore/platform/graphics/filters/SourceGraphic.h
+++ b/WebCore/platform/graphics/filters/SourceGraphic.h
@@ -35,12 +35,12 @@ public:
static const AtomicString& effectName();
- virtual FloatRect determineFilterPrimitiveSubregion(Filter*);
-
virtual void apply(Filter*);
virtual void dump();
- virtual bool isSourceInput() const { return true; }
+ virtual void determineAbsolutePaintRect(Filter*);
+
+ virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; }
virtual TextStream& externalRepresentation(TextStream&, int indention) const;
diff --git a/WebCore/platform/graphics/gpu/DrawingBuffer.cpp b/WebCore/platform/graphics/gpu/DrawingBuffer.cpp
index dc80954..2dc0517 100644
--- a/WebCore/platform/graphics/gpu/DrawingBuffer.cpp
+++ b/WebCore/platform/graphics/gpu/DrawingBuffer.cpp
@@ -30,31 +30,40 @@
#include "config.h"
-#include "DrawingBuffer.h"
+#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(3D_CANVAS)
-#include "GraphicsContext3D.h"
-#include "SharedGraphicsContext3D.h"
+#include "DrawingBuffer.h"
namespace WebCore {
-PassOwnPtr<DrawingBuffer> DrawingBuffer::create(SharedGraphicsContext3D* context, const IntSize& size)
+PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, const IntSize& size)
{
- unsigned framebuffer = context->createFramebuffer();
- ASSERT(framebuffer);
- if (!framebuffer)
- return 0;
- return adoptPtr(new DrawingBuffer(context, size, framebuffer));
+ RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, size));
+ return (drawingBuffer->m_context) ? drawingBuffer.release() : 0;
}
-void DrawingBuffer::bind()
+void DrawingBuffer::clear()
{
- m_context->bindFramebuffer(m_framebuffer);
- m_context->setViewport(m_size);
+ if (!m_context)
+ return;
+
+ m_context->makeContextCurrent();
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
+ m_context->deleteFramebuffer(m_fbo);
+ m_fbo = 0;
+
+ m_context.clear();
}
-void DrawingBuffer::setWillPublishCallback(PassOwnPtr<WillPublishCallback> callback)
+void DrawingBuffer::bind()
{
- m_callback = callback;
+ if (!m_context)
+ return;
+
+ m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
+ m_context->viewport(0, 0, m_size.width(), m_size.height());
}
} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/DrawingBuffer.h b/WebCore/platform/graphics/gpu/DrawingBuffer.h
index 23e6f4a..75c7f99 100644
--- a/WebCore/platform/graphics/gpu/DrawingBuffer.h
+++ b/WebCore/platform/graphics/gpu/DrawingBuffer.h
@@ -31,30 +31,39 @@
#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 {
-class SharedGraphicsContext3D;
-
+#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 Noncopyable {
+class DrawingBuffer : public RefCounted<DrawingBuffer> {
public:
- static PassOwnPtr<DrawingBuffer> create(SharedGraphicsContext3D*, const IntSize&);
+ 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();
+
#if USE(ACCELERATED_COMPOSITING)
PlatformLayer* platformLayer();
void publishToPlatformLayer();
@@ -62,21 +71,36 @@ public:
unsigned getRenderingResultsAsTexture();
+#if PLATFORM(CHROMIUM)
class WillPublishCallback : public Noncopyable {
public:
+ virtual ~WillPublishCallback() { }
+
virtual void willPublish() = 0;
};
- void setWillPublishCallback(PassOwnPtr<WillPublishCallback>);
+ void setWillPublishCallback(PassOwnPtr<WillPublishCallback> callback) { m_callback = callback; }
+#endif
+
+ PassRefPtr<GraphicsContext3D> graphicsContext3D() const { return m_context; }
+
private:
- DrawingBuffer(SharedGraphicsContext3D*, const IntSize&, unsigned framebuffer);
+ static PassRefPtr<DrawingBuffer> create(GraphicsContext3D*, const IntSize&);
+
+ DrawingBuffer(GraphicsContext3D*, const IntSize&);
- SharedGraphicsContext3D* m_context;
+ RefPtr<GraphicsContext3D> m_context;
IntSize m_size;
- unsigned m_framebuffer;
+ Platform3DObject m_fbo;
+#if PLATFORM(CHROMIUM)
OwnPtr<WillPublishCallback> m_callback;
OwnPtr<DrawingBufferInternal> m_internal;
+#endif
+
+#if PLATFORM(MAC)
+ RetainPtr<WebGLLayer> m_platformLayer;
+#endif
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp b/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp
index e43dc37..672b4d7 100644
--- a/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp
+++ b/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp
@@ -25,6 +25,8 @@
#include "config.h"
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "LoopBlinnClassifier.h"
#include "LoopBlinnMathUtils.h"
@@ -120,3 +122,5 @@ LoopBlinnClassifier::Result LoopBlinnClassifier::classify(const FloatPoint& c0,
}
} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp b/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp
index 3b73ff6..1517a67 100644
--- a/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp
+++ b/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp
@@ -25,6 +25,8 @@
#include "config.h"
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "LoopBlinnLocalTriangulator.h"
#include "LoopBlinnMathUtils.h"
@@ -273,3 +275,5 @@ bool LoopBlinnLocalTriangulator::isSharedEdge(Vertex* v0, Vertex* v1)
}
} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp b/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp
index 61ebc9b..5b155a5 100644
--- a/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp
+++ b/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp
@@ -25,12 +25,13 @@
#include "config.h"
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "LoopBlinnMathUtils.h"
#include "FloatPoint.h"
-#include "MathExtras.h"
#include <algorithm>
-#include <string.h> // for memcpy
+#include <wtf/MathExtras.h>
namespace WebCore {
namespace LoopBlinnMathUtils {
@@ -563,3 +564,5 @@ int numXRayCrossingsForCubic(const XRay& xRay, const FloatPoint cubic[4], bool&
} // namespace LoopBlinnMathUtils
} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp b/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp
index ac82637..d272fe1 100644
--- a/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp
+++ b/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp
@@ -25,6 +25,8 @@
#include "config.h"
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "LoopBlinnTextureCoords.h"
#include <math.h>
@@ -169,3 +171,5 @@ LoopBlinnTextureCoords::Result LoopBlinnTextureCoords::compute(const LoopBlinnCl
}
} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/PODInterval.h b/WebCore/platform/graphics/gpu/PODInterval.h
index 9df69ba..5c1dcc2 100644
--- a/WebCore/platform/graphics/gpu/PODInterval.h
+++ b/WebCore/platform/graphics/gpu/PODInterval.h
@@ -27,7 +27,7 @@
#define PODInterval_h
#ifndef NDEBUG
-#include "StringBuilder.h"
+#include <wtf/text/StringBuilder.h>
#endif
namespace WebCore {
@@ -57,14 +57,24 @@ namespace WebCore {
// constructor and assignment operator.
//
// In debug mode, printing of intervals and the data they contain is
-// enabled. This requires the following functions to be available:
+// enabled. This requires the following template specializations to be
+// available:
//
-// String valueToString(const T&);
-// String valueToString(const UserData&);
+// 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:
@@ -131,13 +141,13 @@ public:
{
StringBuilder builder;
builder.append("[PODInterval (");
- builder.append(valueToString(low()));
+ builder.append(ValueToString<T>::string(low()));
builder.append(", ");
- builder.append(valueToString(high()));
+ builder.append(ValueToString<T>::string(high()));
builder.append("), data=");
- builder.append(valueToString(data()));
+ builder.append(ValueToString<UserData>::string(data()));
builder.append(", maxHigh=");
- builder.append(valueToString(maxHigh()));
+ builder.append(ValueToString<T>::string(maxHigh()));
builder.append("]");
return builder.toString();
}
diff --git a/WebCore/platform/graphics/gpu/PODIntervalTree.h b/WebCore/platform/graphics/gpu/PODIntervalTree.h
index c0a86aa..320ce60 100644
--- a/WebCore/platform/graphics/gpu/PODIntervalTree.h
+++ b/WebCore/platform/graphics/gpu/PODIntervalTree.h
@@ -35,6 +35,11 @@
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.
@@ -191,7 +196,7 @@ private:
localMaxValue = node->data().high();
if (!(localMaxValue == node->data().maxHigh())) {
#ifndef NDEBUG
- String localMaxValueString = valueToString(localMaxValue);
+ 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
@@ -206,10 +211,12 @@ private:
#ifndef NDEBUG
// Support for printing PODIntervals at the PODRedBlackTree level.
template<class T, class UserData>
-String valueToString(const PODInterval<T, UserData>& interval)
-{
- return interval.toString();
-}
+struct ValueToString<PODInterval<T, UserData> > {
+ static String string(const PODInterval<T, UserData>& interval)
+ {
+ return interval.toString();
+ }
+};
#endif
} // namespace WebCore
diff --git a/WebCore/platform/graphics/gpu/PODRedBlackTree.h b/WebCore/platform/graphics/gpu/PODRedBlackTree.h
index 9b02037..6d5954c 100644
--- a/WebCore/platform/graphics/gpu/PODRedBlackTree.h
+++ b/WebCore/platform/graphics/gpu/PODRedBlackTree.h
@@ -42,9 +42,11 @@
// the "<" and "==" operators.
//
// In debug mode, printing of the data contained in the tree is
-// enabled. This requires the following function to be available:
+// enabled. This requires the template specialization to be available:
//
-// String valueToString(const T&);
+// 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
@@ -76,13 +78,18 @@
#include <wtf/RefPtr.h>
#ifndef NDEBUG
#include "Logging.h"
-#include "PlatformString.h"
-#include "StringBuilder.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:
@@ -723,7 +730,7 @@ private:
builder.append("-");
if (node) {
builder.append(" ");
- builder.append(valueToString(node->data()));
+ builder.append(ValueToString<T>::string(node->data()));
builder.append((node->color() == Black) ? " (black)" : " (red)");
}
LOG_ERROR("%s", builder.toString().ascii().data());
diff --git a/WebCore/platform/graphics/gpu/Shader.cpp b/WebCore/platform/graphics/gpu/Shader.cpp
index 59c50a7..8983adc 100644
--- a/WebCore/platform/graphics/gpu/Shader.cpp
+++ b/WebCore/platform/graphics/gpu/Shader.cpp
@@ -29,6 +29,9 @@
*/
#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "Shader.h"
#include "AffineTransform.h"
@@ -109,3 +112,5 @@ Shader::~Shader()
}
}
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp
index 7629735..87a0b69 100644
--- a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp
+++ b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp
@@ -30,6 +30,8 @@
#include "config.h"
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "SharedGraphicsContext3D.h"
#include "AffineTransform.h"
@@ -47,16 +49,26 @@
namespace WebCore {
// static
-PassRefPtr<SharedGraphicsContext3D> SharedGraphicsContext3D::create(PassOwnPtr<GraphicsContext3D> context)
-{
- return adoptRef(new SharedGraphicsContext3D(context));
-}
-
-SharedGraphicsContext3D::SharedGraphicsContext3D(PassOwnPtr<GraphicsContext3D> context)
+PassRefPtr<SharedGraphicsContext3D> SharedGraphicsContext3D::create(HostWindow* hostWindow)
+{
+ GraphicsContext3D::Attributes attr;
+ 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_quadVertices(0)
- , m_solidFillShader(SolidFillShader::create(m_context.get()))
- , m_texShader(TexShader::create(m_context.get()))
+ , m_solidFillShader(solidFillShader)
+ , m_texShader(texShader)
{
allContexts()->add(this);
}
@@ -215,8 +227,8 @@ void SharedGraphicsContext3D::removeTexturesFor(NativeImagePtr ptr)
// static
HashSet<SharedGraphicsContext3D*>* SharedGraphicsContext3D::allContexts()
{
- static OwnPtr<HashSet<SharedGraphicsContext3D*> > set(new HashSet<SharedGraphicsContext3D*>);
- return set.get();
+ DEFINE_STATIC_LOCAL(HashSet<SharedGraphicsContext3D*>, allContextsSet, ());
+ return &allContextsSet;
}
@@ -334,3 +346,5 @@ bool SharedGraphicsContext3D::paintsIntoCanvasBuffer() const
}
} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h
index 3ba3c52..05008c2 100644
--- a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h
+++ b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h
@@ -47,6 +47,7 @@ class AffineTransform;
class Color;
class GraphicsContext3D;
class FloatRect;
+class HostWindow;
class IntSize;
class SolidFillShader;
class TexShader;
@@ -55,7 +56,7 @@ typedef HashMap<NativeImagePtr, RefPtr<Texture> > TextureHashMap;
class SharedGraphicsContext3D : public RefCounted<SharedGraphicsContext3D> {
public:
- static PassRefPtr<SharedGraphicsContext3D> create(PassOwnPtr<GraphicsContext3D>);
+ static PassRefPtr<SharedGraphicsContext3D> create(HostWindow*);
~SharedGraphicsContext3D();
// Functions that delegate directly to GraphicsContext3D, with caching
@@ -117,14 +118,16 @@ public:
// the texture.
PassRefPtr<Texture> createTexture(Texture::Format, int width, int height);
+ GraphicsContext3D* graphicsContext3D() const { return m_context.get(); }
+
private:
- explicit SharedGraphicsContext3D(PassOwnPtr<GraphicsContext3D> context);
+ SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D>, PassOwnPtr<SolidFillShader>, PassOwnPtr<TexShader>);
// Used to implement removeTexturesFor(), see the comment above.
static HashSet<SharedGraphicsContext3D*>* allContexts();
void removeTextureFor(NativeImagePtr);
- OwnPtr<GraphicsContext3D> m_context;
+ RefPtr<GraphicsContext3D> m_context;
unsigned m_quadVertices;
diff --git a/WebCore/platform/graphics/gpu/SolidFillShader.cpp b/WebCore/platform/graphics/gpu/SolidFillShader.cpp
index ff1b1fa..86079be 100644
--- a/WebCore/platform/graphics/gpu/SolidFillShader.cpp
+++ b/WebCore/platform/graphics/gpu/SolidFillShader.cpp
@@ -29,6 +29,9 @@
*/
#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "SolidFillShader.h"
#include "Color.h"
@@ -86,3 +89,5 @@ void SolidFillShader::use(const AffineTransform& transform, const Color& color)
}
}
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/TexShader.cpp b/WebCore/platform/graphics/gpu/TexShader.cpp
index 01f4306..d7ffa17 100644
--- a/WebCore/platform/graphics/gpu/TexShader.cpp
+++ b/WebCore/platform/graphics/gpu/TexShader.cpp
@@ -29,6 +29,9 @@
*/
#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "TexShader.h"
#include "GraphicsContext3D.h"
@@ -93,3 +96,5 @@ void TexShader::use(const AffineTransform& transform, const AffineTransform& tex
}
}
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/Texture.cpp b/WebCore/platform/graphics/gpu/Texture.cpp
index 6023fe9..74807dc 100644
--- a/WebCore/platform/graphics/gpu/Texture.cpp
+++ b/WebCore/platform/graphics/gpu/Texture.cpp
@@ -30,6 +30,8 @@
#include "config.h"
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "Texture.h"
#include "FloatRect.h"
@@ -206,3 +208,5 @@ void Texture::bindTile(int tile)
}
}
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/Texture.h b/WebCore/platform/graphics/gpu/Texture.h
index eda475e..92b6d0a 100644
--- a/WebCore/platform/graphics/gpu/Texture.h
+++ b/WebCore/platform/graphics/gpu/Texture.h
@@ -31,11 +31,11 @@
#ifndef Texture_h
#define Texture_h
-#include "RefCounted.h"
-#include "RefPtr.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 {
diff --git a/WebCore/platform/graphics/gpu/TilingData.cpp b/WebCore/platform/graphics/gpu/TilingData.cpp
index 4da242b..a98add7 100644
--- a/WebCore/platform/graphics/gpu/TilingData.cpp
+++ b/WebCore/platform/graphics/gpu/TilingData.cpp
@@ -29,6 +29,9 @@
*/
#include "config.h"
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
#include "TilingData.h"
#include "FloatRect.h"
@@ -220,3 +223,5 @@ void TilingData::intersectDrawQuad(const FloatRect& srcRect, const FloatRect& ds
}
}
+
+#endif
diff --git a/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm b/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm
new file mode 100644
index 0000000..7a8c501
--- /dev/null
+++ b/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm
@@ -0,0 +1,84 @@
+/*
+ * 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 "WebGLLayer.h"
+
+#import "BlockExceptions.h"
+
+namespace WebCore {
+
+DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, const IntSize& size)
+ : m_context(context)
+ , m_size(size)
+ , m_fbo(context->createFramebuffer())
+{
+ 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
+}
+
+DrawingBuffer::~DrawingBuffer()
+{
+ clear();
+}
+
+void DrawingBuffer::reset(const IntSize& newSize)
+{
+ if (!m_context)
+ return;
+
+ if (m_size == newSize)
+ return;
+ m_size = newSize;
+
+ m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_size.width(), m_size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0);
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* DrawingBuffer::platformLayer()
+{
+ return m_platformLayer.get();
+}
+#endif
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp
index 539d92a..1cb561e 100644
--- a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp
+++ b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp
@@ -194,12 +194,14 @@ void GStreamerGWorld::setWindowOverlay(GstMessage* message)
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)
+ if (m_videoWindow) {
+ m_videoWindow->prepareForOverlay(message);
#if GST_CHECK_VERSION(0, 10, 31) || GST_VERSION_NANO
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
+ }
}
}
diff --git a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
index da9255b..7012c9f 100644
--- a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
@@ -1212,7 +1212,7 @@ void MediaPlayerPrivateGStreamer::paint(GraphicsContext* context, const IntRect&
if (!gstImage)
return;
- context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), sRGBColorSpace,
+ context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), ColorSpaceSRGB,
rect, CompositeCopy, false);
}
diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h
index f3df207..f2a3ff2 100644
--- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h
+++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h
@@ -25,6 +25,8 @@
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
+typedef struct _GstMessage GstMessage;
+
namespace WebCore {
class PlatformVideoWindow : public RefCounted<PlatformVideoWindow> {
@@ -34,6 +36,8 @@ class PlatformVideoWindow : public RefCounted<PlatformVideoWindow> {
PlatformVideoWindow();
~PlatformVideoWindow();
+
+ void prepareForOverlay(GstMessage*);
PlatformWidget window() const { return m_window; }
unsigned long videoWindowId() const { return m_videoWindowId; }
diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp
index c55b9cc..0097716 100644
--- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp
+++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp
@@ -35,4 +35,8 @@ PlatformVideoWindow::~PlatformVideoWindow()
notImplemented();
}
+void PlatformVideoWindow::prepareForOverlay(GstMessage*)
+{
+}
+
#endif // USE(GSTREAMER)
diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp
index 77343ae..c2f76cd 100644
--- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp
+++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp
@@ -61,4 +61,9 @@ PlatformVideoWindow::~PlatformVideoWindow()
m_videoWindowId = 0;
}
+
+void PlatformVideoWindow::prepareForOverlay(GstMessage*)
+{
+}
#endif // USE(GSTREAMER)
+
diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp
index 27f48fc..328ec4a 100644
--- a/WebCore/platform/graphics/gtk/FontGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontGtk.cpp
@@ -181,31 +181,15 @@ bool Font::canReturnFallbackFontsForComplexText()
return false;
}
-#ifndef GTK_API_VERSION_2
-static void cairo_region_shrink(cairo_region_t* region, int dx, int dy)
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
{
- int nRects = cairo_region_num_rectangles(region);
- // Clear region.
- cairo_region_subtract(region, region);
-
- for (int i = 0; i < nRects; i++) {
- cairo_rectangle_int_t rect;
- cairo_region_get_rectangle(region, i, &rect);
-
- if (rect.width <= 2 * dx || rect.height <= 2 * dy)
- continue;
-
- rect.x += dx;
- rect.y += dy;
- rect.width -= 2 * dx;
- rect.height -= 2 * dy;
- cairo_region_union_rectangle(region, &rect);
+#if defined(USE_FREETYPE)
+ if (!primaryFont()->platformData().m_pattern) {
+ drawSimpleText(context, run, point, from, to);
+ return;
}
-}
#endif
-void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
-{
cairo_t* cr = context->platformContext();
cairo_save(cr);
cairo_translate(cr, point.x(), point.y());
@@ -224,17 +208,13 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F
#else
cairo_region_t* partialRegion = 0;
#endif
+
if (to - from != run.length()) {
// Clip the region of the run to be rendered
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);
-#ifdef GTK_API_VERSION_2
- gdk_region_shrink(partialRegion, 0, -pixelSize());
-#else
- cairo_region_shrink(partialRegion, 0, -pixelSize());
-#endif
}
Color fillColor = context->fillColor();
@@ -290,7 +270,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F
// Re-enable the platform shadow we disabled earlier
if (hasShadow)
- context->setShadow(shadowOffset, shadowBlur, shadowColor, DeviceColorSpace);
+ context->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB);
// Pango sometimes leaves behind paths we don't want
cairo_new_path(cr);
@@ -323,8 +303,13 @@ static PangoLayout* getDefaultPangoLayout(const TextRun& run)
return layout;
}
-float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow*) const
+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;
@@ -345,6 +330,10 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon
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);
@@ -369,6 +358,11 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool
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);
diff --git a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp
index edb26f0..486a317 100644
--- a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp
+++ b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp
@@ -28,6 +28,7 @@
#include <cairo.h>
#include <gtk/gtk.h>
#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
namespace WebCore {
@@ -67,7 +68,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con
base64Encode(reinterpret_cast<const char*>(buffer.get()), bufferSize, out);
out.append('\0');
- return String::format("data:%s;base64,%s", mimeType.utf8().data(), out.data());
+ return makeString("data:", mimeType, ";base64,", out.data());
}
}
diff --git a/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp
index c5de485..d1b06f3 100644
--- a/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp
+++ b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp
@@ -33,6 +33,7 @@
#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>
@@ -367,8 +368,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double*) const
base64Encode(reinterpret_cast<const char*>(translatedStream.Buffer()),
translatedStream.BufferLength(), encodedBuffer);
- return String::format("data:%s;base64,%s", mimeType.utf8().data(),
- encodedBuffer.data());
+ return makeString("data:", mimeType, ";base64,", encodedBuffer.data());
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/haiku/PathHaiku.cpp b/WebCore/platform/graphics/haiku/PathHaiku.cpp
index c5b8c98..5377e10 100644
--- a/WebCore/platform/graphics/haiku/PathHaiku.cpp
+++ b/WebCore/platform/graphics/haiku/PathHaiku.cpp
@@ -144,12 +144,6 @@ bool Path::isEmpty() const
return !m_path->Frame().IsValid();
}
-String Path::debugString() const
-{
- notImplemented();
- return String();
-}
-
void Path::apply(void* info, PathApplierFunction function) const
{
notImplemented();
diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm
index c8ea9b1..07d6353 100644
--- a/WebCore/platform/graphics/mac/ColorMac.mm
+++ b/WebCore/platform/graphics/mac/ColorMac.mm
@@ -88,14 +88,15 @@ NSColor *nsColor(const Color& color)
static unsigned cachedRGBAValues[cacheSize];
static RetainPtr<NSColor>* cachedColors = new RetainPtr<NSColor>[cacheSize];
- for (int i = 0; i != cacheSize; ++i)
+ 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];
+ alpha:static_cast<CGFloat>(color.alpha()) / 255];
static int cursor;
cachedRGBAValues[cursor] = c;
@@ -107,24 +108,5 @@ NSColor *nsColor(const Color& color)
}
}
-static CGColorRef CGColorFromNSColor(NSColor *color)
-{
- // This needs to always use device colorspace so it can de-calibrate the color for
- // CGColor to possibly recalibrate it.
- CGFloat components[4];
- NSColor *deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- [deviceColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
- static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB();
- CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components);
- return cgColor;
-}
-
-CGColorRef createCGColor(const Color& c)
-{
- // We could directly create a CGColor here, but that would
- // skip any RGB caching the nsColor method does. A direct
- // creation could be investigated for a possible performance win.
- return CGColorFromNSColor(nsColor(c));
-}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm
index a4919d8..e079b44 100644
--- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm
+++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm
@@ -77,12 +77,12 @@ static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBi
attribs.append(static_cast<CGLPixelFormatAttribute>(0));
}
-PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
+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;
- OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs, hostWindow, false));
+ RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, false));
return context->m_contextObj ? context.release() : 0;
}
diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
index f3301d8..aa754f2 100644
--- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm
+++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -30,6 +30,7 @@
#import <AppKit/AppKit.h>
#import <wtf/StdLibExtras.h>
+#import "LocalCurrentGraphicsContext.h"
#import "WebCoreSystemInterface.h"
@class NSColor;
@@ -43,14 +44,14 @@ namespace WebCore {
// calls in this file are all exception-safe, so we don't block
// exceptions for those.
-static void drawFocusRingToContext(CGContextRef context, RetainPtr<CGPathRef> focusRingPath, RetainPtr<CGColorRef> colorRef, int radius)
+static void drawFocusRingToContext(CGContextRef context, CGPathRef focusRingPath, CGColorRef color, int radius)
{
#ifdef BUILDING_ON_TIGER
CGContextBeginTransparencyLayer(context, 0);
#endif
CGContextBeginPath(context);
- CGContextAddPath(context, focusRingPath.get());
- wkDrawFocusRing(context, colorRef.get(), radius);
+ CGContextAddPath(context, focusRingPath);
+ wkDrawFocusRing(context, color, radius);
#ifdef BUILDING_ON_TIGER
CGContextEndTransparencyLayer(context);
#endif
@@ -63,16 +64,14 @@ void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int of
int radius = (width - 1) / 2;
offset += radius;
- RetainPtr<CGColorRef> colorRef;
- if (color.isValid())
- colorRef.adoptCF(createCGColor(color));
-
+ CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0;
+
RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable());
unsigned pathCount = paths.size();
for (unsigned i = 0; i < pathCount; i++)
CGPathAddPath(focusRingPath.get(), 0, paths[i].platformPath());
- drawFocusRingToContext(platformContext(), focusRingPath, colorRef, radius);
+ drawFocusRingToContext(platformContext(), focusRingPath.get(), colorRef, radius);
}
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
@@ -82,16 +81,14 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int
int radius = (width - 1) / 2;
offset += radius;
- RetainPtr<CGColorRef> colorRef;
- if (color.isValid())
- colorRef.adoptCF(createCGColor(color));
+ 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, colorRef, radius);
+ drawFocusRingToContext(platformContext(), focusRingPath.get(), colorRef, radius);
}
#ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp.
@@ -182,6 +179,7 @@ void GraphicsContext::drawLineForTextChecking(const IntPoint& point, int width,
// for transforms.
// Draw underline.
+ LocalCurrentGraphicsContext localContext(this);
NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
CGContextRef context = (CGContextRef)[currentContext graphicsPort];
CGContextSaveGState(context);
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
index d4cd851..c4128ef 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
@@ -38,7 +38,6 @@
#import <QuartzCore/QuartzCore.h>
#import "RotateTransformOperation.h"
#import "ScaleTransformOperation.h"
-#import "StringBuilder.h"
#import "SystemTime.h"
#import "TranslateTransformOperation.h"
#import "WebLayer.h"
@@ -48,6 +47,7 @@
#import <wtf/CurrentTime.h>
#import <wtf/UnusedParam.h>
#import <wtf/RetainPtr.h>
+#import <wtf/text/StringConcatenate.h>
using namespace std;
@@ -248,7 +248,7 @@ static String propertyIdToString(AnimatedPropertyID property)
static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index)
{
- return animationName + String::format("_%d_%d", property, index);
+ return makeString(animationName, '_', String::number(property), '_', String::number(index));
}
static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction* timingFunction)
@@ -265,9 +265,7 @@ static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction* tim
static void setLayerBorderColor(PlatformLayer* layer, const Color& color)
{
- CGColorRef borderColor = createCGColor(color);
- [layer setBorderColor:borderColor];
- CGColorRelease(borderColor);
+ [layer setBorderColor:cachedCGColor(color, ColorSpaceDeviceRGB)];
}
static void clearBorderColor(PlatformLayer* layer)
@@ -277,9 +275,7 @@ static void clearBorderColor(PlatformLayer* layer)
static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color)
{
- CGColorRef bgColor = createCGColor(color);
- [layer setBackgroundColor:bgColor];
- CGColorRelease(bgColor);
+ [layer setBackgroundColor:cachedCGColor(color, ColorSpaceDeviceRGB)];
}
static void clearLayerBackgroundColor(PlatformLayer* layer)
diff --git a/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp
index 53d9b86..daf3b12 100644
--- a/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp
+++ b/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp
@@ -1161,11 +1161,11 @@ String GraphicsContext3D::getProgramInfoLog(Platform3DObject program)
makeContextCurrent();
GLint length;
::glGetProgramiv((GLuint) program, GL_INFO_LOG_LENGTH, &length);
-
+ if (!length)
+ return "";
+
GLsizei size;
GLchar* info = (GLchar*) fastMalloc(length);
- if (!info)
- return "";
::glGetProgramInfoLog((GLuint) program, length, &size, info);
String s(info);
@@ -1227,8 +1227,6 @@ String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader)
ASSERT(shader);
makeContextCurrent();
- GLint length;
- ::glGetShaderiv((GLuint) shader, GL_INFO_LOG_LENGTH, &length);
HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader);
@@ -1240,21 +1238,19 @@ String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader)
if (entry.isValid) {
GLint length;
::glGetShaderiv((GLuint) shader, GL_INFO_LOG_LENGTH, &length);
+ if (!length)
+ return "";
GLsizei size;
GLchar* info = (GLchar*) fastMalloc(length);
- if (!info)
- return "";
::glGetShaderInfoLog((GLuint) shader, length, &size, info);
String s(info);
fastFree(info);
return s;
- }
- else {
+ } else
return entry.log;
- }
}
String GraphicsContext3D::getShaderSource(Platform3DObject shader)
@@ -1449,6 +1445,11 @@ void GraphicsContext3D::synthesizeGLError(unsigned long error)
m_syntheticErrors.add(error);
}
+int GraphicsContext3D::getGraphicsResetStatusARB()
+{
+ return NO_ERROR;
+}
+
}
#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/platform/graphics/openvg/PathOpenVG.cpp b/WebCore/platform/graphics/openvg/PathOpenVG.cpp
index e74ea57..39a4b06 100644
--- a/WebCore/platform/graphics/openvg/PathOpenVG.cpp
+++ b/WebCore/platform/graphics/openvg/PathOpenVG.cpp
@@ -436,18 +436,6 @@ bool Path::hasCurrentPoint() const
return vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS) > 0;
}
-String Path::debugString() const
-{
- String debugString = "";
-
- // OpenVG provides no means to retrieve path segment information.
- // This is a bit unfortunate, we might need to store the segments in
- // memory if we want to implement this function properly.
- notImplemented();
-
- return debugString;
-}
-
void Path::apply(void* info, PathApplierFunction function) const
{
// OpenVG provides no means to retrieve path segment information.
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index e7566eb..b049181 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -137,7 +137,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float
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_blurRadius, -ctxShadow->m_blurRadius, ctxShadow->m_blurRadius, ctxShadow->m_blurRadius);
+ clip.adjust(-ctxShadow->m_blurDistance, -ctxShadow->m_blurDistance, ctxShadow->m_blurDistance, ctxShadow->m_blurDistance);
}
p->save();
p->setClipRect(clip.toRect(), Qt::IntersectClip);
diff --git a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
index 0756aa7..cda8606 100644
--- a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
@@ -286,6 +286,11 @@ bool GraphicsContext3D::isErrorGeneratedOnOutOfBoundsAccesses() const
return false;
}
+int GraphicsContext3D::getGraphicsResetStatusARB()
+{
+ return NO_ERROR;
+}
+
GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow)
: m_attrs(attrs)
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 7e4af40..8b34f51 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -204,6 +204,13 @@ public:
return shadow.m_type != ContextShadow::NoShadow;
}
+ inline void clearCurrentPath()
+ {
+ if (!currentPath.elementCount())
+ return;
+ currentPath = QPainterPath();
+ }
+
QRectF clipBoundingRect() const
{
#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
@@ -248,8 +255,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
setPaintingDisabled(!context);
if (context) {
// Make sure the context starts in sync with our state.
- setPlatformFillColor(fillColor(), DeviceColorSpace);
- setPlatformStrokeColor(strokeColor(), DeviceColorSpace);
+ setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
+ setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
// Make sure we start with the correct join mode.
setLineJoin(MiterJoin);
@@ -533,7 +540,7 @@ void GraphicsContext::fillPath()
} else
p->fillPath(path, p->brush());
- m_data->currentPath = QPainterPath();
+ m_data->clearCurrentPath();
}
void GraphicsContext::strokePath()
@@ -566,7 +573,7 @@ void GraphicsContext::strokePath()
p->strokePath(path, pen);
} else
p->strokePath(path, pen);
- m_data->currentPath = QPainterPath();
+ m_data->clearCurrentPath();
}
static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY)
@@ -722,7 +729,8 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
if (paintingDisabled() || !color.isValid())
return;
- Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight);
+ Path path;
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
QPainter* p = m_data->p();
if (m_data->hasShadow()) {
p->translate(m_data->shadow.offset());
@@ -734,7 +742,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
void GraphicsContext::beginPath()
{
- m_data->currentPath = QPainterPath();
+ m_data->clearCurrentPath();
}
void GraphicsContext::addPath(const Path& path)
@@ -777,7 +785,7 @@ void GraphicsContext::clipPath(WindRule clipRule)
QPainter* p = m_data->p();
QPainterPath newPath = m_data->currentPath;
newPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
- p->setClipPath(newPath);
+ p->setClipPath(newPath, Qt::IntersectClip);
}
void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
@@ -835,8 +843,28 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool)
if (paintingDisabled())
return;
+ IntPoint startPoint = origin;
IntPoint endPoint = origin + IntSize(width, 0);
- drawLine(origin, endPoint);
+
+ // 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)
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
index 079d8ba..e0941f5 100644
--- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
@@ -37,6 +37,7 @@
#include <QtGui/qgraphicseffect.h>
#include <QtGui/qgraphicsitem.h>
#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qgraphicswidget.h>
#include <QtGui/qpainter.h>
#include <QtGui/qpixmap.h>
#include <QtGui/qpixmapcache.h>
@@ -320,7 +321,7 @@ GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
// our items automatically.
const QList<QGraphicsItem*> children = childItems();
QList<QGraphicsItem*>::const_iterator cit;
- for (cit = children.begin(); cit != children.end(); ++cit) {
+ for (cit = children.constBegin(); cit != children.constEnd(); ++cit) {
if (QGraphicsItem* item = *cit) {
if (scene())
scene()->removeItem(item);
@@ -523,7 +524,7 @@ void GraphicsLayerQtImpl::updateTransform()
const QList<QGraphicsItem*> children = childItems();
QList<QGraphicsItem*>::const_iterator it;
- for (it = children.begin(); it != children.end(); ++it)
+ for (it = children.constBegin(); it != children.constEnd(); ++it)
if (GraphicsLayerQtImpl* layer= toGraphicsLayerQtImpl(*it))
layer->updateTransform();
}
@@ -610,13 +611,13 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
if (!m_layer || m_changeMask == NoChanges)
goto afterLayerChanges;
- if (m_currentContent.contentType == HTMLContentType && (m_changeMask & ParentChange)) {
+ 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()->nativeLayer() != parentItem())
- setParentItem(m_layer->parent()->nativeLayer());
+ setParentItem(m_layer->parent()->platformLayer());
}
if (m_changeMask & ChildrenChange) {
@@ -634,13 +635,13 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
const QSet<QGraphicsItem*> childrenToRemove = currentChildren - newChildren;
QSet<QGraphicsItem*>::const_iterator it;
- for (it = childrenToAdd.begin(); it != childrenToAdd.end(); ++it) {
+ for (it = childrenToAdd.constBegin(); it != childrenToAdd.constEnd(); ++it) {
if (QGraphicsItem* w = *it)
w->setParentItem(this);
}
QSet<QGraphicsItem*>::const_iterator rit;
- for (rit = childrenToRemove.begin(); rit != childrenToRemove.end(); ++rit) {
+ for (rit = childrenToRemove.constBegin(); rit != childrenToRemove.constEnd(); ++rit) {
if (GraphicsLayerQtImpl* w = toGraphicsLayerQtImpl(*rit))
w->setParentItem(0);
}
@@ -680,7 +681,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
if (scene())
scene()->update();
- if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | BackfaceVisibilityChange | PositionChange)) {
+ 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;
@@ -737,6 +738,11 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
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();
}
}
@@ -804,7 +810,7 @@ afterLayerChanges:
children.append(m_state.maskLayer->platformLayer());
QList<QGraphicsItem*>::const_iterator it;
- for (it = children.begin(); it != children.end(); ++it) {
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
if (QGraphicsItem* item = *it) {
if (GraphicsLayerQtImpl* layer = toGraphicsLayerQtImpl(item))
layer->flushChanges(true, forceUpdateTransform);
@@ -850,6 +856,20 @@ void GraphicsLayerQt::setNeedsDisplayInRect(const FloatRect& rect)
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)
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/WebCore/platform/graphics/qt/GraphicsLayerQt.h
index 75ca498..ed535eb 100644
--- a/WebCore/platform/graphics/qt/GraphicsLayerQt.h
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.h
@@ -75,6 +75,7 @@ public:
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)
diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
index ee01222..0cdc894 100644
--- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -35,6 +35,7 @@
#include "StillImageQt.h"
#include "TransparencyLayer.h"
#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
#include <QBuffer>
#include <QColor>
@@ -68,7 +69,7 @@ ImageBufferData::ImageBufferData(const IntSize& size)
pen.setColor(Qt::black);
pen.setWidth(1);
pen.setCapStyle(Qt::FlatCap);
- pen.setJoinStyle(Qt::MiterJoin);
+ pen.setJoinStyle(Qt::SvgMiterJoin);
pen.setMiterLimit(10);
painter->setPen(pen);
QBrush brush = painter->brush();
@@ -79,7 +80,7 @@ ImageBufferData::ImageBufferData(const IntSize& size)
m_image = StillImage::createForRendering(&m_pixmap);
}
-ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace, bool& success)
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, bool& success)
: m_data(size)
, m_size(size)
{
@@ -117,7 +118,7 @@ void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace,
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(), DeviceColorSpace, destRect, srcRect, op, useLowQualityScale);
+ destContext->drawImage(copy.get(), ColorSpaceDeviceRGB, destRect, srcRect, op, useLowQualityScale);
} else
destContext->drawImage(m_data.m_image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
}
@@ -139,7 +140,7 @@ void ImageBuffer::clip(GraphicsContext* context, const FloatRect& floatRect) con
if (!nativeImage)
return;
- IntRect rect(floatRect);
+ IntRect rect = enclosingIntRect(floatRect);
QPixmap alphaMask = *nativeImage;
if (alphaMask.width() != rect.width() || alphaMask.height() != rect.height())
alphaMask = alphaMask.scaled(rect.width(), rect.height());
@@ -216,7 +217,7 @@ PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& i
const uchar* bits = image.bits();
#endif
- quint32* destRows = reinterpret_cast_ptr<quint32*>(&data[desty * rect.width() + destx]);
+ quint32* destRows = reinterpret_cast_ptr<quint32*>(&data[desty * rect.width() * 4 + destx * 4]);
if (multiplied == Unmultiplied) {
for (int y = 0; y < numRows; ++y) {
@@ -401,7 +402,8 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con
}
buffer.close();
- return String::format("data:%s;base64,%s", mimeType.utf8().data(), data.toBase64().data());
+
+ return makeString("data:", mimeType, ";base64,", data.toBase64().data());
}
}
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
index 1a31d1e..962c931 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
@@ -27,6 +27,7 @@
#include "HTMLVideoElement.h"
#include "NetworkingContext.h"
#include "NotImplemented.h"
+#include "RenderVideo.h"
#include "TimeRanges.h"
#include "Widget.h"
#include "qwebframe.h"
@@ -42,6 +43,7 @@
#include <QPainter>
#include <QPoint>
#include <QRect>
+#include <QStyleOptionGraphicsItem>
#include <QTime>
#include <QTimer>
#include <QUrl>
@@ -49,6 +51,10 @@
#include <wtf/HashSet.h>
#include <wtf/text/CString.h>
+#if USE(ACCELERATED_COMPOSITING)
+#include "texmap/TextureMapperPlatformLayer.h"
+#endif
+
using namespace WTF;
namespace WebCore {
@@ -93,6 +99,8 @@ MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player)
, 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)
@@ -125,8 +133,7 @@ MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player)
this, SLOT(nativeSizeChanged(QSizeF)));
// Grab the player control
- QMediaService* service = m_mediaPlayer->service();
- if (service) {
+ if (QMediaService* service = m_mediaPlayer->service()) {
m_mediaPlayerControl = qobject_cast<QMediaPlayerControl *>(
service->requestControl(QMediaPlayerControl_iid));
}
@@ -134,6 +141,10 @@ MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player)
MediaPlayerPrivateQt::~MediaPlayerPrivateQt()
{
+ m_mediaPlayer->disconnect(this);
+ m_mediaPlayer->stop();
+ m_mediaPlayer->setMedia(QMediaContent());
+
delete m_mediaPlayer;
delete m_videoScene;
}
@@ -330,8 +341,7 @@ float MediaPlayerPrivateQt::duration() const
float MediaPlayerPrivateQt::currentTime() const
{
- float currentTime = m_mediaPlayer->position() / 1000.0f;
- return currentTime;
+ return m_mediaPlayer->position() / 1000.0f;
}
PassRefPtr<TimeRanges> MediaPlayerPrivateQt::buffered() const
@@ -437,8 +447,15 @@ void MediaPlayerPrivateQt::stateChanged(QMediaPlayer::State state)
}
}
-void MediaPlayerPrivateQt::nativeSizeChanged(const QSizeF&)
+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();
}
@@ -466,7 +483,7 @@ void MediaPlayerPrivateQt::seekTimeout()
void MediaPlayerPrivateQt::positionChanged(qint64)
{
- // Only propogate this event if we are seeking
+ // Only propagate this event if we are seeking
if (m_isSeeking && m_queuedSeek == -1) {
m_webCorePlayer->timeChanged();
m_isSeeking = false;
@@ -546,6 +563,9 @@ void MediaPlayerPrivateQt::updateStates()
void MediaPlayerPrivateQt::setSize(const IntSize& size)
{
+ LOG(Media, "MediaPlayerPrivateQt::setSize(%dx%d)",
+ size.width(), size.height());
+
if (size == m_currentSize)
return;
@@ -555,10 +575,15 @@ void MediaPlayerPrivateQt::setSize(const IntSize& size)
IntSize MediaPlayerPrivateQt::naturalSize() const
{
- if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata)
+ if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) {
+ LOG(Media, "MediaPlayerPrivateQt::naturalSize() -> 0x0 (!hasVideo || !haveMetaData)");
return IntSize();
+ }
- return IntSize(m_videoItem->nativeSize().toSize());
+ 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)
@@ -573,10 +598,7 @@ void MediaPlayerPrivateQt::paint(GraphicsContext* context, const IntRect& rect)
if (!m_isVisible)
return;
- // Grab the painter and widget
QPainter* painter = context->platformContext();
-
- // Render the video
m_videoScene->render(painter, QRectF(QRect(rect)), m_videoItem->sceneBoundingRect());
}
@@ -585,7 +607,41 @@ void MediaPlayerPrivateQt::repaint()
m_webCorePlayer->repaint();
}
-#if USE(ACCELERATED_COMPOSITING)
+#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();
@@ -595,14 +651,12 @@ void MediaPlayerPrivateQt::acceleratedRenderingStateChanged()
m_composited = composited;
if (composited)
- m_videoScene->removeItem(m_videoItem);
- else
- m_videoScene->addItem(m_videoItem);
+ m_platformLayer = new TextureMapperVideoLayerQt(m_videoItem);
}
PlatformLayer* MediaPlayerPrivateQt::platformLayer() const
{
- return m_composited ? m_videoItem : 0;
+ return m_composited ? m_platformLayer.get() : 0;
}
#endif
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h
index 179bf2a..93c9d1c 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h
@@ -33,6 +33,8 @@ QT_END_NAMESPACE
namespace WebCore {
+class TextureMapperVideoLayer;
+
class MediaPlayerPrivateQt : public QObject, public MediaPlayerPrivateInterface {
Q_OBJECT
@@ -91,12 +93,18 @@ public:
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;
@@ -125,11 +133,15 @@ private:
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;
diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp
index b8b9d5e..508ba6a 100644
--- a/WebCore/platform/graphics/qt/PathQt.cpp
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -335,6 +335,8 @@ void Path::addEllipse(const FloatRect& r)
void Path::clear()
{
+ if (!m_path.elementCount())
+ return;
m_path = QPainterPath();
}
@@ -355,41 +357,6 @@ FloatPoint Path::currentPoint() const
return m_path.currentPosition();
}
-String Path::debugString() const
-{
- QString ret;
- for (int i = 0; i < m_path.elementCount(); ++i) {
- const QPainterPath::Element &cur = m_path.elementAt(i);
-
- switch (cur.type) {
- case QPainterPath::MoveToElement:
- ret += QString(QLatin1String("M%1,%2 ")).arg(cur.x, 0, 'f', 2).arg(cur.y, 0, 'f', 2);
- break;
- case QPainterPath::LineToElement:
- ret += QString(QLatin1String("L%1,%2 ")).arg(cur.x, 0, 'f', 2).arg(cur.y, 0, 'f', 2);
- 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);
-
- ret += QString(QLatin1String("C%1,%2,%3,%4,%5,%6 ")).arg(cur.x, 0, 'f', 2).arg(cur.y, 0, 'f', 2).arg(c1.x, 0, 'f', 2)
- .arg(c1.y, 0, 'f', 2).arg(c2.x, 0, 'f', 2).arg(c2.y, 0, 'f', 2);
- i += 2;
- break;
- }
- case QPainterPath::CurveToDataElement:
- Q_ASSERT(false);
- break;
- }
- }
-
- return ret.trimmed();
-}
-
void Path::apply(void* info, PathApplierFunction function) const
{
PathElement pelement;
diff --git a/WebCore/platform/graphics/qt/TextureMapperQt.cpp b/WebCore/platform/graphics/qt/TextureMapperQt.cpp
new file mode 100644
index 0000000..9236dae
--- /dev/null
+++ b/WebCore/platform/graphics/qt/TextureMapperQt.cpp
@@ -0,0 +1,225 @@
+/*
+ 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 "texmap/TextureMapper.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qpaintengine.h>
+#include <QtGui/qpixmap.h>
+
+#ifdef QT_OPENGL_LIB
+# include "opengl/TextureMapperGL.h"
+#endif
+
+namespace WebCore {
+
+class BitmapTextureQt : public BitmapTexture {
+ friend class TextureMapperQt;
+public:
+ BitmapTextureQt() {}
+ 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(); }
+ virtual bool allowOfflineTextureUpload() const { return true; }
+ IntRect sourceRect() const { return IntRect(0, 0, contentSize().width(), contentSize().height()); }
+private:
+ QPainter m_painter;
+ QPixmap m_pixmap;
+};
+
+class TextureMapperQt : public TextureMapper {
+public:
+ 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 bool allowSurfaceForRoot() const { return false; }
+ TextureMapperQt(GraphicsContext* context);
+ virtual const char* type() const { return "TextureMapperQt"; }
+ virtual PassRefPtr<BitmapTexture> createTexture();
+
+ static void initialize(QPainter* painter)
+ {
+ painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
+ }
+
+private:
+ QPainter* m_painter;
+ RefPtr<BitmapTextureQt> m_currentSurface;
+};
+
+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 TextureMapperQt::setClip(const IntRect& rect)
+{
+ QPainter* painter = m_currentSurface ? &m_currentSurface->m_painter : m_painter;
+ painter->setClipRect(rect);
+}
+
+TextureMapperQt::TextureMapperQt(GraphicsContext* context)
+ : TextureMapper(context)
+ , m_painter(context->platformContext())
+ , m_currentSurface(0)
+{
+ TextureMapperQt::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);
+}
+
+PassRefPtr<TextureMapper> TextureMapper::create(GraphicsContext* context)
+{
+#ifdef QT_OPENGL_LIB
+ if (context->platformContext()->paintEngine()->type() == QPaintEngine::OpenGL2)
+ return adoptRef(new TextureMapperGL(context));
+#endif
+ return adoptRef(new TextureMapperQt(context));
+}
+
+
+PassRefPtr<BitmapTexture> TextureMapperQt::createTexture()
+{
+ return adoptRef(new BitmapTextureQt());
+}
+
+#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/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
index 2be7dc5..143d667 100644
--- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
@@ -45,6 +45,8 @@
#include "SkColorPriv.h"
#include "SkiaUtils.h"
+#include <wtf/text/StringConcatenate.h>
+
using namespace std;
namespace WebCore {
@@ -58,7 +60,7 @@ ImageBufferData::ImageBufferData(const IntSize& size)
{
}
-ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, bool& success)
: m_data(size)
, m_size(size)
{
@@ -290,6 +292,7 @@ void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint&
void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
{
+ context()->platformContext()->prepareForSoftwareDraw();
putImageData<Unmultiplied>(source, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size);
}
@@ -311,7 +314,7 @@ String ImageBuffer::toDataURL(const String&, const double*) const
base64EncodedData.append('\0');
// And the resulting string.
- return String::format("data:image/png;base64,%s", base64EncodedData.data());
+ return makeString("data:image/png;base64,", base64EncodedData.data());
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp
index e123256..23e7be6 100644
--- a/WebCore/platform/graphics/skia/ImageSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageSkia.cpp
@@ -143,9 +143,7 @@ static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext
// 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)))
+ if (platformContext->interpolationQuality() == InterpolationHigh)
return RESAMPLE_AWESOME;
return RESAMPLE_LINEAR;
@@ -175,12 +173,8 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm
&& srcIRect.height() == bitmap.height();
// We will always draw in integer sizes, so round the destination rect.
- // First we need to apply canvas transformation matrix to get desired size of
- // resampled image.
- SkRect destRectTransformed;
- canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect);
SkIRect destRectRounded;
- destRectTransformed.round(&destRectRounded);
+ destRect.round(&destRectRounded);
SkIRect resizedImageRect = // Represents the size of the resized image.
{ 0, 0, destRectRounded.width(), destRectRounded.height() };
@@ -194,10 +188,7 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm
// Compute the visible portion of our rect.
SkRect destBitmapSubsetSk;
ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk);
- // Determine size of resampled image based on clipped destination rect.
- SkRect destBitmapSubsetSkTransformed;
- canvas.getTotalMatrix().mapRect(&destBitmapSubsetSkTransformed, destBitmapSubsetSk);
- destBitmapSubsetSkTransformed.offset(-destBitmapSubsetSkTransformed.fLeft, -destBitmapSubsetSkTransformed.fTop);
+ destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop);
// The matrix inverting, etc. could have introduced rounding error which
// causes the bounds to be outside of the resized bitmap. We round outward
@@ -205,7 +196,7 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm
// need, and then clamp to the bitmap bounds so we don't get any invalid
// data.
SkIRect destBitmapSubsetSkI;
- destBitmapSubsetSkTransformed.roundOut(&destBitmapSubsetSkI);
+ destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI);
if (!destBitmapSubsetSkI.intersect(resizedImageRect))
return; // Resized image does not intersect.
diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp
index 12241f8..89323c4 100644
--- a/WebCore/platform/graphics/skia/PathSkia.cpp
+++ b/WebCore/platform/graphics/skia/PathSkia.cpp
@@ -227,62 +227,6 @@ void Path::transform(const AffineTransform& xform)
m_path->transform(xform);
}
-String Path::debugString() const
-{
- String result;
-
- SkPath::Iter iter(*m_path, false);
- SkPoint pts[4];
-
- int numPoints = m_path->getPoints(0, 0);
- SkPath::Verb verb;
-
- do {
- verb = iter.next(pts);
- switch (verb) {
- case SkPath::kMove_Verb:
- result += String::format("M%.2f,%.2f ", pts[0].fX, pts[0].fY);
- numPoints -= 1;
- break;
- case SkPath::kLine_Verb:
- if (!iter.isCloseLine()) {
- result += String::format("L%.2f,%.2f ", pts[1].fX, pts[1].fY);
- numPoints -= 1;
- }
- break;
- case SkPath::kQuad_Verb:
- result += String::format("Q%.2f,%.2f,%.2f,%.2f ",
- pts[1].fX, pts[1].fY,
- pts[2].fX, pts[2].fY);
- numPoints -= 2;
- break;
- case SkPath::kCubic_Verb:
- result += String::format("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f ",
- pts[1].fX, pts[1].fY,
- pts[2].fX, pts[2].fY,
- pts[3].fX, pts[3].fY);
- numPoints -= 3;
- break;
- case SkPath::kClose_Verb:
- result += "Z ";
- break;
- case SkPath::kDone_Verb:
- break;
- }
- } while (verb != SkPath::kDone_Verb);
-
- // If you have a path that ends with an M, Skia will not iterate the
- // trailing M. That's nice of it, but Apple's paths output the trailing M
- // and we want out layout dumps to look like theirs
- if (numPoints) {
- ASSERT(numPoints==1);
- m_path->getLastPt(pts);
- result += String::format("M%.2f,%.2f ", pts[0].fX, pts[0].fY);
- }
-
- return result.stripWhiteSpace();
-}
-
// 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)
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
index b469312..3f9e4c1 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -34,12 +34,10 @@
#include "AffineTransform.h"
#include "DrawingBuffer.h"
-#include "GLES2Canvas.h"
#include "GraphicsContext.h"
#include "GraphicsContext3D.h"
#include "ImageBuffer.h"
#include "NativeImageSkia.h"
-#include "SharedGraphicsContext3D.h"
#include "SkiaUtils.h"
#include "Texture.h"
#include "TilingData.h"
@@ -56,6 +54,11 @@
#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);
@@ -207,7 +210,9 @@ 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());
@@ -216,8 +221,10 @@ PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
PlatformContextSkia::~PlatformContextSkia()
{
+#if ENABLE(ACCELERATED_2D_CANVAS)
if (m_gpuCanvas)
m_gpuCanvas->drawingBuffer()->setWillPublishCallback(0);
+#endif
}
void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
@@ -705,6 +712,7 @@ private:
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);
@@ -716,6 +724,7 @@ void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* co
m_gpuCanvas.clear();
m_useGPU = false;
}
+#endif
}
void PlatformContextSkia::prepareForSoftwareDraw() const
@@ -808,6 +817,7 @@ void PlatformContextSkia::markDirtyRect(const IntRect& rect)
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();
@@ -816,7 +826,7 @@ void PlatformContextSkia::uploadSoftwareToHardware(CompositeOperator op) const
m_uploadTexture->updateSubRect(bitmap.getPixels(), m_softwareDirtyRect);
AffineTransform identity;
- gpuCanvas()->drawTexturedRect(m_uploadTexture.get(), m_softwareDirtyRect, m_softwareDirtyRect, identity, 1.0, DeviceColorSpace, op);
+ 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();
@@ -825,10 +835,12 @@ void PlatformContextSkia::uploadSoftwareToHardware(CompositeOperator op) const
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();
@@ -850,6 +862,7 @@ void PlatformContextSkia::readbackHardwareToSoftware() const
}
}
m_softwareDirtyRect.unite(IntRect(0, 0, width, height)); // Mark everything as dirty.
+#endif
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h
index eb03224..84e5d78 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.h
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h
@@ -183,8 +183,11 @@ public:
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;
@@ -224,9 +227,11 @@ private:
FloatSize m_imageResamplingHintDstSize;
bool m_drawingToImageBuffer;
bool m_useGPU;
+#if ENABLE(ACCELERATED_2D_CANVAS)
OwnPtr<GLES2Canvas> m_gpuCanvas;
- mutable enum { None, Software, Mixed, Hardware } m_backingStoreState;
mutable RefPtr<Texture> m_uploadTexture;
+#endif
+ mutable enum { None, Software, Mixed, Hardware } m_backingStoreState;
mutable IntRect m_softwareDirtyRect;
};
diff --git a/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp
new file mode 100644
index 0000000..cf90cb1
--- /dev/null
+++ b/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp
@@ -0,0 +1,1444 @@
+/*
+ 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 "CurrentTime.h"
+#include "FloatRect.h"
+#include "GraphicsContext.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"
+
+#define DEBUG_TEXMAP_FPS 0
+
+namespace WebCore {
+
+struct TexmapPaintOptions {
+ BitmapTexture* surface;
+ TextureMapper* textureMapper;
+ GraphicsContext* context;
+ TextureMapperNode* rootLayer;
+ float opacity;
+ IntRect scissorRect;
+ IntRect visibleRect;
+ bool isSurface;
+};
+class TextureMapperCache {
+public:
+ void mark(BitmapTexture* texture);
+
+ class Entry {
+ public:
+ RefPtr<BitmapTexture> texture;
+ Entry() : previousCost(0) { }
+ inline int calculateCost() const
+ {
+ if (!texture || !texture->isValid())
+ 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()
+{
+ // If this is in the GL implementation, we need an active GL context, because we might call glDeleteTextures.
+ 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].calculateCost();
+
+ 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())
+ continue;
+ m_totalCost -= entry.previousCost;
+ entry.texture->destroy();
+ 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;
+
+ if (index < m_data.size())
+ m_data.remove(index);
+ const int cost = entry.calculateCost();
+ m_totalCost -= entry.previousCost;
+ m_totalCost += (entry.previousCost = cost);
+ m_data.prepend(entry);
+}
+
+TextureMapperCache gTextureMapperCache;
+
+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;
+};
+
+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 StaticContentType { HTMLContentType, DirectImageContentType, ColorContentType, MediaContentType, Canvas3DContentType};
+
+ TextureMapperNode* rootLayer();
+
+ TextureMapperNode(GraphicsLayerTextureMapper* newLayer);
+ virtual ~TextureMapperNode();
+
+ void clearDirectImage();
+ void computeTransformations();
+ IntSize nearestSurfaceSize() const;
+ void computeReplicaTransform();
+ void computeLayerType();
+ void computeLocalTransform();
+ void flattenTo2DSpaceIfNecessary();
+ void initializeTextureMapper(TextureMapper*);
+ void invalidateTransform();
+ void notifyChange(ChangeMask);
+ void syncCompositingState(bool recurse);
+ void performPostSyncOperations();
+ void setNeedsDisplay();
+ void setNeedsDisplayInRect(IntRect);
+ virtual void cleanupTextureMapper();
+
+ void paintRecursive(TexmapPaintOptions options);
+ void paintSelf(const TexmapPaintOptions& options);
+ void uploadTextureFromContent(TextureMapper* textureMapper, const IntRect& visibleRect);
+
+ int countDescendantsWithContent() const;
+ bool hasSurfaceDescendants() const;
+
+ IntSize size() const { return m_size; }
+
+ virtual void setPlatformLayerClient(TextureMapperLayerClient*);
+ virtual void paint(GraphicsContext*, const IntSize&, const IntRect& targetRect, const IntRect& exposedRect, const TransformationMatrix& transform, float opacity);
+
+ static TextureMapperNode* toTextureMapperNode(GraphicsLayer*);
+public:
+ GraphicsLayerTextureMapper* m_layer;
+ const char* m_lastTextureMapperType;
+ RefPtr<TextureMapper> m_lastTextureMapper;
+ 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;
+
+ struct ContentData {
+ IntRect needsDisplayRect;
+ bool needsDisplay;
+ Color backgroundColor;
+
+ StaticContentType contentType;
+ RefPtr<Image> image;
+ TextureMapperVideoLayer* media;
+
+ ContentData()
+ : needsDisplay(false)
+ , contentType(HTMLContentType)
+ , image(0)
+ , media(0)
+ {
+ }
+
+ };
+
+ 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_pendingContent;
+ ContentData m_currentContent;
+
+ Vector<TextureMapperNode*> m_children;
+ TextureMapperNode* m_parent;
+ TextureMapperNode* m_effectTarget;
+ int m_changeMask;
+ 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;
+
+ 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;
+};
+
+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;
+}
+
+static int 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);
+}
+inline static void sortByZOrder(Vector<TextureMapperNode* >& array, int first, int last)
+{
+ qsort(array.data(), array.size(), sizeof(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;
+
+}
+
+void TextureMapperNode::paint(GraphicsContext* context, const IntSize& size, const IntRect& targetRect, const IntRect& exposedRect, const TransformationMatrix& transform, float opacity)
+{
+ ASSERT(m_layerType == RootLayer);
+ if (m_size.isEmpty())
+ return;
+
+#if 0
+ WTF::StopWatch stopWatch;
+ ("[TextureMapper] RootPaint!!\n");
+#endif
+
+ RefPtr<TextureMapper> textureMapper = TextureMapper::create(context);
+
+ if (textureMapper->type() != m_lastTextureMapperType)
+ gTextureMapperCache.m_data.clear();
+
+ m_lastTextureMapper = textureMapper;
+ TexmapPaintOptions opt;
+ opt.opacity = 1;
+ opt.rootLayer = this;
+ opt.scissorRect = targetRect;
+ opt.visibleRect = exposedRect;
+ opt.textureMapper = textureMapper.get();
+ opt.context = textureMapper->graphicsContext();
+ opt.surface = 0;
+ paintRecursive(opt);
+
+ if (textureMapper->allowSurfaceForRoot() || m_state.hasSurfaceDescendants) {
+ textureMapper->bindSurface(0);
+ textureMapper->paintToTarget(*m_surface.get(), size, transform, opacity * m_state.opacity, targetRect);
+ }
+ gTextureMapperCache.purge();
+}
+
+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;
+}
+
+inline TextureMapperNode* TextureMapperNode::toTextureMapperNode(GraphicsLayer* layer)
+{
+ return layer ? static_cast<GraphicsLayerTextureMapper*>(layer)->m_node.get() : 0;
+}
+
+void TextureMapperNode::computeLayerType()
+{
+ // calculate layer type. A layer can be one of the following:
+ // RootLayer: the top level. Draws to a framebuffer, and the target texture draws into the viewport.
+ // only one layer is the root layer.
+ // 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.
+ // 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.
+ // 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.
+ // DefaultLayer: draws itself and its children directly to the current framebuffer.
+ // any layer that doesn't conform to the other rules is a DefaultLayer.
+
+ 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;
+ m_layerType = DefaultLayer;
+
+ // Layer has no parent, it must be a 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;
+
+ // A layer with content-descendants and a mask is always a clip layer.
+ if (hasDescendantsWithContent && m_state.maskLayer) {
+ m_layerType = ClipLayer;
+ return;
+ }
+
+ // A masks-to bounds layer can be a clip or a scissor layer. It's a scissor layer only if it has a trivial clip (identity or translation), or if it has transparency.
+ // That's because a ClipLayer would create an intermediate drawing surface (FB) - we want to limit it to when it's actually necessary, i.e. transparency or non-trivial 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;
+ }
+
+ // We use a transparency layer when we have two of the following 3: replica, transparency, descendants with contents.
+ if ((hasReplica && hasDescendantsWithContent) || (hasReplica && hasTransparency) || (hasTransparency && m_state.descendantsWithContent > 1))
+ m_layerType = TransparencyLayer;
+}
+void TextureMapperNode::initializeTextureMapper(TextureMapper* textureMapper)
+{
+ if (textureMapper->type() == m_lastTextureMapperType)
+ return;
+ m_surface = textureMapper->createTexture();
+ m_replicaSurface = textureMapper->createTexture();
+ m_texture = textureMapper->createTexture();
+ gTextureMapperCache.mark(m_texture.get());
+ m_lastTextureMapperType = textureMapper->type();
+}
+
+TextureMapperNode::TextureMapperNode(GraphicsLayerTextureMapper* newLayer)
+ : m_layer(newLayer)
+ , m_lastTextureMapperType(0)
+ , m_lastTextureMapper(0)
+ , m_layerType(DefaultLayer)
+ , m_surface(0)
+ , m_parent(0)
+ , m_effectTarget(0)
+ , m_changeMask(NoChanges)
+ , m_platformClient(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)
+{
+ if (m_size.isEmpty() || !m_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;
+
+ WTF::StopWatch stopWatch;
+ 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);
+ m_pendingContent.needsDisplayRect = IntRect();
+
+ {
+ GraphicsContext context(m_texture->beginPaint(dirtyRect));
+ if (textureMapper && textureMapper->graphicsContext()) {
+ GraphicsContext* originalContext = textureMapper->graphicsContext();
+ context.setImageInterpolationQuality(originalContext->imageInterpolationQuality());
+ context.setTextDrawingMode(originalContext->textDrawingMode());
+ }
+ m_layer->paintGraphicsLayerContents(context, dirtyRect);
+ }
+ m_texture->endPaint();
+ {
+#if 0
+ LOG("[TextureMapper] Re-render(%d) layer(%p) %d::%d::%d (%dx%d) [%dms]\n", ++renderCount, this,
+ needsReset, m_currentContent.needsDisplay, !m_currentContent.needsDisplayRect.isEmpty(),
+ dirtyRect.width(), dirtyRect.height(), int(stopWatch.elapsed() * 1000));
+ static int renderCount = 0;
+ m_texture->save(String().format("/tmp/layer_%d.png", renderCount));
+#endif
+ }
+ m_currentContent.needsDisplay = false;
+
+}
+
+void TextureMapperNode::paintSelf(const TexmapPaintOptions& options)
+{
+ if (!m_layer || m_size.isEmpty() || (!m_state.drawsContent && m_currentContent.contentType == HTMLContentType))
+ return;
+
+ RefPtr<BitmapTexture> maskTexture = m_state.maskLayer ? m_state.maskLayer->m_texture : 0;
+ RefPtr<BitmapTexture> replicaMaskTexture = 0;
+ if (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer)
+ replicaMaskTexture = m_state.replicaLayer->m_state.maskLayer->m_texture;
+
+ const float opacity = options.isSurface ? 1 : options.opacity;
+
+ uploadTextureFromContent(options.textureMapper, options.visibleRect);
+ 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());
+}
+
+void TextureMapperNode::paintRecursive(TexmapPaintOptions options)
+{
+ WTF::StopWatch stopWatch;
+
+ 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;
+
+ initializeTextureMapper(options.textureMapper);
+ computeReplicaTransform();
+
+ if (m_state.maskLayer) {
+ m_state.maskLayer->initializeTextureMapper(options.textureMapper);
+ m_state.maskLayer->m_state.dirty = false;
+ }
+
+ if (m_state.replicaLayer) {
+ m_state.replicaLayer->initializeTextureMapper(options.textureMapper);
+ m_state.replicaLayer->m_state.dirty = false;
+ if (m_state.replicaLayer->m_state.maskLayer) {
+ m_state.replicaLayer->m_state.maskLayer->initializeTextureMapper(options.textureMapper);
+ m_state.replicaLayer->m_state.maskLayer->m_state.dirty = false;
+ }
+ }
+
+ TextureMapperNode* replica = m_state.replicaLayer;
+ const bool isSurface = (m_layerType == ClipLayer
+ || m_layerType == TransparencyLayer
+ || (m_layerType == RootLayer
+ && (options.textureMapper->allowSurfaceForRoot() || m_state.hasSurfaceDescendants)
+ ));
+ if (isSurface)
+ uploadTextureFromContent(options.textureMapper, options.visibleRect);
+ 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());
+
+ gTextureMapperCache.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);
+ gTextureMapperCache.mark(m_surface.get());
+ options.textureMapper->bindSurface(m_surface.get());
+
+ optionsForDescendants.surface = m_surface.get();
+ } else if (m_surface)
+ m_surface->destroy();
+
+ RefPtr<BitmapTexture> maskTexture;
+ RefPtr<BitmapTexture> replicaMaskTexture;
+ if (TextureMapperNode* mask = m_state.maskLayer) {
+ mask->uploadTextureFromContent(options.textureMapper, options.visibleRect);
+ maskTexture = mask->m_texture;
+ }
+
+ if (replica && replica->m_state.maskLayer) {
+ replica->m_state.maskLayer->uploadTextureFromContent(options.textureMapper, options.visibleRect);
+ replicaMaskTexture = replica->m_state.maskLayer->m_texture;
+ }
+
+ int childrenSize = m_children.size();
+ if (isDirty || !isSurface || m_state.tiled || !m_surface->isValid()) {
+ bool didPaintSelf = false;
+ if (!m_state.preserves3D || m_children.isEmpty()) {
+ paintSelf(options);
+ didPaintSelf = true;
+ }
+
+ if (m_children.isEmpty() && !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 < childrenSize; ++i) {
+ TextureMapperNode* layer = m_children[i];
+ if (!layer)
+ continue;
+
+ if (!didPaintSelf && layer->m_transforms.centerZ >= 0) {
+ paintSelf(options);
+ didPaintSelf = true;
+ }
+ layer->paintRecursive(optionsForDescendants);
+ if (isSurface) {
+ ASSERT(m_surface);
+ gTextureMapperCache.mark(m_surface.get());
+ options.textureMapper->bindSurface(m_surface.get());
+ }
+ }
+ if (!didPaintSelf) {
+ paintSelf(options);
+ didPaintSelf = true;
+ }
+ }
+
+ if (m_layerType == RootLayer || m_layerType == DefaultLayer || m_layerType == ScissorLayer)
+ return;
+
+ ASSERT(m_surface);
+ BitmapTexture& texture = *m_surface.get();
+ if (replica) {
+ ASSERT(m_replicaSurface);
+ m_replicaSurface->reset(options.surface->size());
+ m_replicaSurface->setOffset(options.surface->offset());
+ gTextureMapperCache.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);
+ gTextureMapperCache.mark(options.surface);
+ options.textureMapper->drawTexture(*m_replicaSurface.get(), IntRect(IntPoint(0, 0), options.surface->size()), TransformationMatrix(), options.opacity, 0);
+ 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());
+ gTextureMapperCache.mark(&texture);
+}
+
+void TextureMapperNode::cleanupTextureMapper()
+{
+ if (m_texture)
+ m_texture->destroy();
+ if (m_surface)
+ m_surface->destroy();
+ if (m_replicaSurface)
+ m_replicaSurface->destroy();
+ for (int i = 0; i < m_children.size(); ++i) {
+ if (m_children[i])
+ m_children[i]->cleanupTextureMapper();
+ }
+ if (m_lastTextureMapper)
+ m_lastTextureMapper->cleanup();
+}
+
+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));
+}
+
+void TextureMapperNode::notifyChange(ChangeMask changeMask)
+{
+ m_changeMask |= changeMask;
+ if (!m_layer->client())
+ return;
+ m_layer->client()->notifySyncRequired(m_layer);
+}
+
+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(bool recurse)
+{
+ bool needsToInvalidateTransform = false;
+
+ if (!m_layer)
+ return;
+
+ if (m_changeMask == NoChanges)
+ goto afterCurrentLayerSync;
+
+ setNeedsDisplay();
+ if (m_parent)
+ m_parent->m_state.dirty = true;
+
+ if (m_currentContent.contentType == HTMLContentType && (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())
+ m_parent = 0;
+ else
+ m_parent = toTextureMapperNode(m_layer->parent());
+
+ if (!m_layer->parent() && m_parent) {
+ size_t index = m_parent->m_children.find(this);
+ m_parent->m_children.remove(index);
+ }
+
+ }
+
+ if (m_changeMask & ChildrenChange) {
+ m_children.clear();
+ for (size_t i = 0; i < m_layer->children().size(); ++i) {
+ if (TextureMapperNode* child = toTextureMapperNode(m_layer->children()[i])) {
+ if (!child)
+ continue;
+ m_children.append(child);
+ child->m_parent = this;
+ }
+ }
+ m_state.dirty = true;
+ }
+
+ if (m_changeMask & (SizeChange | ContentsRectChange)) {
+ IntSize wantedSize = IntSize(m_layer->size().width(), m_layer->size().height());
+ if (wantedSize.isEmpty() && m_pendingContent.contentType == HTMLContentType)
+ wantedSize = IntSize(m_layer->contentsRect().width(), m_layer->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 (m_changeMask & MaskLayerChange) {
+ if (TextureMapperNode* layer = toTextureMapperNode(m_layer->maskLayer()))
+ layer->m_effectTarget = this;
+ }
+
+ if (m_changeMask & ReplicaLayerChange) {
+ if (TextureMapperNode* layer = toTextureMapperNode(m_layer->replicaLayer()))
+ layer->m_effectTarget = this;
+ }
+
+ if (m_changeMask & (TransformChange | SizeChange | AnchorPointChange | PositionChange))
+ m_transforms.localDirty = true;
+
+ if (m_changeMask & (ChildrenTransformChange | SizeChange))
+ m_transforms.perspectiveDirty = true;
+
+ if (m_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.
+ needsToInvalidateTransform = true;
+ }
+
+ if (m_changeMask & DisplayChange)
+ m_state.dirty = true;
+
+ m_state.maskLayer = toTextureMapperNode(m_layer->maskLayer());
+ m_state.replicaLayer = toTextureMapperNode(m_layer->replicaLayer());
+ 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.contentsRect = m_layer->contentsRect();
+ 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.contentType = m_pendingContent.contentType;
+ m_currentContent.image = m_pendingContent.image;
+ m_currentContent.media = m_pendingContent.media;
+ m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
+ m_currentContent.needsDisplay = m_currentContent.needsDisplay || m_pendingContent.needsDisplay;
+ m_currentContent.needsDisplayRect.unite(m_pendingContent.needsDisplayRect);
+ m_pendingContent.needsDisplay = false;
+ m_pendingContent.needsDisplayRect = IntRect();
+ m_changeMask = NoChanges;
+ afterCurrentLayerSync:
+ if (needsToInvalidateTransform)
+ invalidateTransform();
+
+ if (m_state.maskLayer) {
+ m_state.maskLayer->syncCompositingState(false);
+ if (m_state.maskLayer->m_size.isEmpty())
+ m_state.maskLayer->m_size = m_size;
+ }
+
+ if (m_state.replicaLayer)
+ m_state.replicaLayer->syncCompositingState(false);
+
+#if 0
+ if (m_state.dirty && m_texture && m_texture->allowOfflineTextureUpload())
+ uploadTextureFromContent(0);
+#endif
+
+ if (!recurse)
+ return;
+
+ const int childrenSize = m_children.size();
+ for (int i = childrenSize-1; i >= 0; --i)
+ m_children[i]->syncCompositingState(true);
+}
+
+GraphicsLayerTextureMapper::GraphicsLayerTextureMapper(GraphicsLayerClient* client)
+ : GraphicsLayer(client)
+ , m_node(new TextureMapperNode(this))
+{
+}
+
+void GraphicsLayerTextureMapper::setName(const String& name)
+{
+ m_node->m_name = name;
+}
+
+GraphicsLayerTextureMapper::~GraphicsLayerTextureMapper()
+{
+}
+
+/* \reimp (GraphicsLayer.h): The current size might change, thus we need to update the whole display.
+*/
+void GraphicsLayerTextureMapper::setNeedsDisplay()
+{
+ m_node->m_pendingContent.needsDisplay = true;
+ m_node->notifyChange(TextureMapperNode::DisplayChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ if (m_node->m_pendingContent.needsDisplay)
+ return;
+ m_node->m_pendingContent.needsDisplayRect.unite(IntRect(rect));
+ m_node->notifyChange(TextureMapperNode::DisplayChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setParent(GraphicsLayer* layer)
+{
+ m_node->notifyChange(TextureMapperNode::ParentChange);
+ GraphicsLayer::setParent(layer);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+bool GraphicsLayerTextureMapper::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ m_node->notifyChange(TextureMapperNode::ChildrenChange);
+ return GraphicsLayer::setChildren(children);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::addChild(GraphicsLayer* layer)
+{
+ m_node->notifyChange(TextureMapperNode::ChildrenChange);
+ GraphicsLayer::addChild(layer);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::addChildAtIndex(GraphicsLayer* layer, int index)
+{
+ GraphicsLayer::addChildAtIndex(layer, index);
+ m_node->notifyChange(TextureMapperNode::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildAbove(layer, sibling);
+ m_node->notifyChange(TextureMapperNode::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+
+ GraphicsLayer::addChildBelow(layer, sibling);
+ m_node->notifyChange(TextureMapperNode::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+bool GraphicsLayerTextureMapper::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ m_node->notifyChange(TextureMapperNode::ChildrenChange);
+ return true;
+ }
+
+ return false;
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::removeFromParent()
+{
+ if (!parent())
+ return;
+ m_node->notifyChange(TextureMapperNode::ParentChange);
+ GraphicsLayer::removeFromParent();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setMaskLayer(GraphicsLayer* value)
+{
+ if (value == maskLayer())
+ return;
+ GraphicsLayer::setMaskLayer(value);
+ m_node->notifyChange(TextureMapperNode::MaskLayerChange);
+}
+
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setReplicatedByLayer(GraphicsLayer* value)
+{
+ if (value == replicaLayer())
+ return;
+ GraphicsLayer::setReplicatedByLayer(value);
+ m_node->notifyChange(TextureMapperNode::ReplicaLayerChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setPosition(const FloatPoint& value)
+{
+ if (value == position())
+ return;
+ GraphicsLayer::setPosition(value);
+ m_node->notifyChange(TextureMapperNode::PositionChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setAnchorPoint(const FloatPoint3D& value)
+{
+ if (value == anchorPoint())
+ return;
+ GraphicsLayer::setAnchorPoint(value);
+ m_node->notifyChange(TextureMapperNode::AnchorPointChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setSize(const FloatSize& value)
+{
+ if (value == size())
+ return;
+
+ GraphicsLayer::setSize(value);
+ m_node->notifyChange(TextureMapperNode::SizeChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setTransform(const TransformationMatrix& value)
+{
+ if (value == transform())
+ return;
+
+ GraphicsLayer::setTransform(value);
+ m_node->notifyChange(TextureMapperNode::TransformChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setChildrenTransform(const TransformationMatrix& value)
+{
+ if (value == childrenTransform())
+ return;
+ GraphicsLayer::setChildrenTransform(value);
+ m_node->notifyChange(TextureMapperNode::ChildrenTransformChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setPreserves3D(bool value)
+{
+ if (value == preserves3D())
+ return;
+ GraphicsLayer::setPreserves3D(value);
+ m_node->notifyChange(TextureMapperNode::Preserves3DChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setMasksToBounds(bool value)
+{
+ if (value == masksToBounds())
+ return;
+ GraphicsLayer::setMasksToBounds(value);
+ m_node->notifyChange(TextureMapperNode::MasksToBoundsChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setDrawsContent(bool value)
+{
+ if (value == drawsContent())
+ return;
+ m_node->notifyChange(TextureMapperNode::DrawsContentChange);
+ GraphicsLayer::setDrawsContent(value);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setBackgroundColor(const Color& value)
+{
+ if (value == m_node->m_pendingContent.backgroundColor)
+ return;
+ m_node->m_pendingContent.backgroundColor = value;
+ GraphicsLayer::setBackgroundColor(value);
+ m_node->notifyChange(TextureMapperNode::BackgroundColorChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::clearBackgroundColor()
+{
+ if (!m_node->m_pendingContent.backgroundColor.isValid())
+ return;
+ m_node->m_pendingContent.backgroundColor = Color();
+ GraphicsLayer::clearBackgroundColor();
+ m_node->notifyChange(TextureMapperNode::BackgroundColorChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsOpaque(bool value)
+{
+ if (value == contentsOpaque())
+ return;
+ m_node->notifyChange(TextureMapperNode::ContentsOpaqueChange);
+ GraphicsLayer::setContentsOpaque(value);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setBackfaceVisibility(bool value)
+{
+ if (value == backfaceVisibility())
+ return;
+ GraphicsLayer::setBackfaceVisibility(value);
+ m_node->notifyChange(TextureMapperNode::BackfaceVisibilityChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setOpacity(float value)
+{
+ if (value == opacity())
+ return;
+ GraphicsLayer::setOpacity(value);
+ m_node->notifyChange(TextureMapperNode::OpacityChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsRect(const IntRect& value)
+{
+ if (value == contentsRect())
+ return;
+ GraphicsLayer::setContentsRect(value);
+ m_node->notifyChange(TextureMapperNode::ContentsRectChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsToImage(Image* image)
+{
+ m_node->notifyChange(TextureMapperNode::ContentChange);
+ m_node->m_pendingContent.contentType = image ? TextureMapperNode::DirectImageContentType : TextureMapperNode::HTMLContentType;
+ m_node->m_pendingContent.image = image;
+ GraphicsLayer::setContentsToImage(image);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsBackgroundColor(const Color& color)
+{
+ m_node->notifyChange(TextureMapperNode::ContentChange);
+ m_node->m_pendingContent.contentType = TextureMapperNode::ColorContentType;
+ m_node->m_pendingContent.backgroundColor = color;
+ GraphicsLayer::setContentsBackgroundColor(color);
+}
+
+
+void GraphicsLayerTextureMapper::setContentsToMedia(PlatformLayer* media)
+{
+ GraphicsLayer::setContentsToMedia(media);
+ m_node->notifyChange(TextureMapperNode::ContentChange);
+ m_node->m_pendingContent.contentType = media ? TextureMapperNode::MediaContentType : TextureMapperNode::HTMLContentType;
+ if (media)
+ m_node->m_pendingContent.media = static_cast<TextureMapperVideoLayer*>(media);
+ else
+ m_node->m_pendingContent.media = 0;
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::setContentsOrientation(CompositingCoordinatesOrientation orientation)
+{
+ if (contentsOrientation() == orientation)
+ return;
+ m_node->notifyChange(TextureMapperNode::ContentsOrientationChange);
+ GraphicsLayer::setContentsOrientation(orientation);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::syncCompositingStateForThisLayerOnly()
+{
+ m_node->syncCompositingState(false);
+ m_node->performPostSyncOperations();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerTextureMapper::syncCompositingState()
+{
+ GraphicsLayer::syncCompositingState();
+ m_node->syncCompositingState(true);
+ m_node->performPostSyncOperations();
+}
+
+/* \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/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h b/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h
new file mode 100644
index 0000000..36ebd74
--- /dev/null
+++ b/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h
@@ -0,0 +1,96 @@
+/*
+ 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"
+
+#if ENABLE(3D_CANVAS)
+#include "GraphicsContext3D.h"
+#endif
+
+#define ENABLE_TEXMAP_ANIMATION 0
+
+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; }
+
+private:
+ OwnPtr<TextureMapperNode> m_node;
+};
+
+}
+#endif // GraphicsLayerTextureMapper_h
diff --git a/WebCore/platform/graphics/texmap/TextureMapper.h b/WebCore/platform/graphics/texmap/TextureMapper.h
new file mode 100644
index 0000000..03c1c6d
--- /dev/null
+++ b/WebCore/platform/graphics/texmap/TextureMapper.h
@@ -0,0 +1,120 @@
+/*
+ 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 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; }
+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 : public RefCounted<TextureMapper> {
+ friend class BitmapTexture;
+
+public:
+ static PassRefPtr<TextureMapper> create(GraphicsContext*);
+ 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 setClip(const IntRect&) = 0;
+ virtual bool allowSurfaceForRoot() const = 0;
+ virtual PassRefPtr<BitmapTexture> createTexture() = 0;
+ virtual const char* type() const = 0;
+ virtual void cleanup() {}
+
+ GraphicsContext* graphicsContext() const
+ {
+ return m_gc;
+ }
+
+protected:
+ TextureMapper(GraphicsContext* gc) : m_gc(gc) {}
+ GraphicsContext* m_gc;
+};
+
+};
+
+#endif
+
+#endif
diff --git a/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h b/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h
new file mode 100644
index 0000000..23e9fc9
--- /dev/null
+++ b/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h
@@ -0,0 +1,70 @@
+/*
+ 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 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;
+};
+
+class TextureMapperPlatformLayer {
+public:
+ enum Type {
+ ContentLayer,
+ VideoLayer
+ };
+
+ virtual Type layerType() const = 0;
+ virtual ~TextureMapperPlatformLayer() {}
+};
+
+class TextureMapperContentLayer : public TextureMapperPlatformLayer {
+public:
+ virtual void setPlatformLayerClient(TextureMapperLayerClient*) = 0;
+ virtual void paint(GraphicsContext*, const IntSize&, const IntRect& targetRect, const IntRect& exposedRect, const TransformationMatrix& transform, float opacity) {}
+ virtual IntSize size() const = 0;
+ virtual void cleanupTextureMapper() {}
+ 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/WebCore/platform/graphics/transforms/AffineTransform.cpp b/WebCore/platform/graphics/transforms/AffineTransform.cpp
index be18e07..f275526 100644
--- a/WebCore/platform/graphics/transforms/AffineTransform.cpp
+++ b/WebCore/platform/graphics/transforms/AffineTransform.cpp
@@ -41,8 +41,8 @@ static void affineTransformDecompose(const AffineTransform& matrix, double sr[9]
AffineTransform m(matrix);
// Compute scaling factors
- double sx = sqrt(m.a() * m.a() + m.b() * m.b());
- double sy = sqrt(m.c() * m.c() + m.d() * m.d());
+ double sx = matrix.xScale();
+ double sy = matrix.yScale();
// Compute cross product of transformed unit vectors. If negative,
// one axis was flipped.
@@ -119,6 +119,16 @@ bool AffineTransform::isIdentity() const
&& 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];
diff --git a/WebCore/platform/graphics/transforms/AffineTransform.h b/WebCore/platform/graphics/transforms/AffineTransform.h
index 289ec54..baee102 100644
--- a/WebCore/platform/graphics/transforms/AffineTransform.h
+++ b/WebCore/platform/graphics/transforms/AffineTransform.h
@@ -110,7 +110,10 @@ public:
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;
diff --git a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h
index 7430dbc..0a0aaf0 100644
--- a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h
@@ -37,6 +37,8 @@ public:
return adoptRef(new Matrix3DTransformOperation(matrix));
}
+ TransformationMatrix matrix() const {return m_matrix; }
+
private:
virtual bool isIdentity() const { return m_matrix.isIdentity(); }
diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
index ee47a11..fd9b27e 100644
--- a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
@@ -42,6 +42,8 @@ public:
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; }
diff --git a/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h
index a665f3e..834cc83 100644
--- a/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h
@@ -36,6 +36,8 @@ public:
{
return adoptRef(new PerspectiveTransformOperation(p));
}
+
+ double perspective() const { return m_p; }
private:
virtual bool isIdentity() const { return m_p == 0; }
diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.h b/WebCore/platform/graphics/transforms/RotateTransformOperation.h
index 699ea43..2acb002 100644
--- a/WebCore/platform/graphics/transforms/RotateTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.h
@@ -41,6 +41,9 @@ public:
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:
diff --git a/WebCore/platform/graphics/transforms/SkewTransformOperation.h b/WebCore/platform/graphics/transforms/SkewTransformOperation.h
index 6343710..afe9a7b 100644
--- a/WebCore/platform/graphics/transforms/SkewTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/SkewTransformOperation.h
@@ -36,6 +36,9 @@ public:
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; }
diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
index a66cc3d..ea48d49 100644
--- a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
@@ -46,6 +46,10 @@ public:
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; }
diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp
index c6437f2..2f1fb41 100644
--- a/WebCore/platform/graphics/win/FontCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -360,14 +360,14 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
graphicsContext->clearShadow();
Color fillColor = graphicsContext->fillColor();
Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
- graphicsContext->setFillColor(shadowFillColor, DeviceColorSpace);
+ graphicsContext->setFillColor(shadowFillColor, ColorSpaceDeviceRGB);
CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width(), point.y() + translation.height() + shadowOffset.height());
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, DeviceColorSpace);
+ graphicsContext->setFillColor(fillColor, ColorSpaceDeviceRGB);
}
CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height());
@@ -378,7 +378,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
}
if (hasSimpleShadow)
- graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, DeviceColorSpace);
+ graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB);
wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle);
}
diff --git a/WebCore/platform/graphics/win/GDIExtras.cpp b/WebCore/platform/graphics/win/GDIExtras.cpp
new file mode 100644
index 0000000..4bd95da
--- /dev/null
+++ b/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/WebCore/platform/graphics/win/GDIExtras.h b/WebCore/platform/graphics/win/GDIExtras.h
new file mode 100644
index 0000000..0166124
--- /dev/null
+++ b/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/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
index 0203d42..c9288e5 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * 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
@@ -70,8 +70,8 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
setPaintingDisabled(!m_data->m_cgContext);
if (m_data->m_cgContext) {
// Make sure the context starts in sync with our state.
- setPlatformFillColor(fillColor(), DeviceColorSpace);
- setPlatformStrokeColor(strokeColor(), DeviceColorSpace);
+ setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
+ setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
}
}
@@ -129,6 +129,8 @@ void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int of
// 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())
@@ -136,7 +138,7 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int
float radius = (width - 1) / 2.0f;
offset += radius;
- CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0;
+ CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0;
CGMutablePathRef focusRingPath = CGPathCreateMutable();
unsigned rectCount = rects.size();
@@ -151,8 +153,6 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int
wkDrawFocusRing(context, colorRef, radius);
- CGColorRelease(colorRef);
-
CGPathRelease(focusRingPath);
CGContextRestoreGState(context);
diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
index dad5da1..f7674db 100644
--- a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
+++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
@@ -99,9 +99,7 @@ TransformationMatrix CAToTransform3D(const CATransform3D& fromT3D)
static void setLayerBorderColor(WKCACFLayer* layer, const Color& color)
{
- CGColorRef borderColor = createCGColor(color);
- layer->setBorderColor(borderColor);
- CGColorRelease(borderColor);
+ layer->setBorderColor(cachedCGColor(color, ColorSpaceDeviceRGB));
}
static void clearBorderColor(WKCACFLayer* layer)
@@ -111,9 +109,7 @@ static void clearBorderColor(WKCACFLayer* layer)
static void setLayerBackgroundColor(WKCACFLayer* layer, const Color& color)
{
- CGColorRef bgColor = createCGColor(color);
- layer->setBackgroundColor(bgColor);
- CGColorRelease(bgColor);
+ layer->setBackgroundColor(cachedCGColor(color, ColorSpaceDeviceRGB));
}
static void clearLayerBackgroundColor(WKCACFLayer* layer)
diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp
index a0fbba7..e65b859 100644
--- a/WebCore/platform/graphics/win/ImageCGWin.cpp
+++ b/WebCore/platform/graphics/win/ImageCGWin.cpp
@@ -78,9 +78,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
IntSize imageSize = BitmapImage::size();
if (size)
- drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy);
+ 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()), DeviceColorSpace, CompositeCopy);
+ 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);
diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp
index e3c5ea0..70b132e 100644
--- a/WebCore/platform/graphics/win/ImageCairoWin.cpp
+++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp
@@ -82,9 +82,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
IntSize imageSize = BitmapImage::size();
if (size)
- drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy);
+ 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()), DeviceColorSpace, CompositeCopy);
+ 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);
@@ -100,7 +100,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float
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()), DeviceColorSpace, compositeOp);
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), ColorSpaceDeviceRGB, compositeOp);
m_currentFrame = currentFrame;
return;
}
@@ -108,7 +108,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float
// 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()), DeviceColorSpace, compositeOp);
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, compositeOp);
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp
index 4a7e45e..4a7e45e 100755..100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp
index 354e0bf..1b4f1d9 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp
@@ -42,7 +42,6 @@
#include "ScrollView.h"
#include "Settings.h"
#include "SoftLinking.h"
-#include "StringBuilder.h"
#include "TimeRanges.h"
#include "Timer.h"
#include <AssertMacros.h>
@@ -53,6 +52,7 @@
#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)
@@ -174,6 +174,8 @@ MediaPlayerPrivateQuickTimeVisualContext::MediaPlayerPrivateQuickTimeVisualConte
, m_movieTransform(CGAffineTransformIdentity)
#endif
, m_visualContextClient(new MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient(this))
+ , m_delayingLoad(false)
+ , m_preload(MediaPlayer::Auto)
{
}
@@ -241,7 +243,7 @@ static void addCookieParam(StringBuilder& cookieBuilder, const String& name, con
// Add parameter name, and value if there is one.
cookieBuilder.append(name);
if (!value.isEmpty()) {
- cookieBuilder.append("=");
+ cookieBuilder.append('=');
cookieBuilder.append(value);
}
}
@@ -275,7 +277,7 @@ void MediaPlayerPrivateQuickTimeVisualContext::setUpCookiesForQuickTime(const St
addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires));
if (cookie.httpOnly)
addCookieParam(cookieBuilder, "httpOnly", String());
- cookieBuilder.append(";");
+ cookieBuilder.append(';');
String cookieURL;
if (!cookie.domain.isEmpty()) {
@@ -316,8 +318,28 @@ static void disableComponentsOnce()
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;
@@ -347,6 +369,12 @@ void MediaPlayerPrivateQuickTimeVisualContext::load(const String& url)
m_movie->setVolume(m_player->volume());
}
+void MediaPlayerPrivateQuickTimeVisualContext::prepareToPlay()
+{
+ if (!m_movie || m_delayingLoad)
+ resumeLoad();
+}
+
void MediaPlayerPrivateQuickTimeVisualContext::play()
{
if (!m_movie)
@@ -1005,6 +1033,13 @@ bool MediaPlayerPrivateQuickTimeVisualContext::hasSingleSecurityOrigin() const
return true;
}
+void MediaPlayerPrivateQuickTimeVisualContext::setPreload(MediaPlayer::Preload preload)
+{
+ m_preload = preload;
+ if (m_delayingLoad && m_preload != MediaPlayer::None)
+ resumeLoad();
+}
+
MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::currentRenderingMode() const
{
if (!m_movie)
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h
index 272b90f..4c62558 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h
@@ -74,9 +74,12 @@ private:
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;
@@ -111,6 +114,8 @@ private:
bool hasClosedCaptions() const;
void setClosedCaptionsVisible(bool);
+ void setPreload(MediaPlayer::Preload);
+
void updateStates();
void doSeek();
void cancelSeek();
@@ -189,6 +194,9 @@ private:
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;
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index c37f5d5..39e8a11 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -38,7 +38,6 @@
#include "QTMovieTask.h"
#include "ScrollView.h"
#include "SoftLinking.h"
-#include "StringBuilder.h"
#include "TimeRanges.h"
#include "Timer.h"
#include <Wininet.h>
@@ -46,6 +45,7 @@
#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)
@@ -159,7 +159,7 @@ static void addCookieParam(StringBuilder& cookieBuilder, const String& name, con
// Add parameter name, and value if there is one.
cookieBuilder.append(name);
if (!value.isEmpty()) {
- cookieBuilder.append("=");
+ cookieBuilder.append('=');
cookieBuilder.append(value);
}
}
@@ -194,7 +194,7 @@ void MediaPlayerPrivate::setUpCookiesForQuickTime(const String& url)
addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires));
if (cookie.httpOnly)
addCookieParam(cookieBuilder, "httpOnly", String());
- cookieBuilder.append(";");
+ cookieBuilder.append(';');
String cookieURL;
if (!cookie.domain.isEmpty()) {
diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp
index 1685a30..d75c854 100644
--- a/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp
+++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp
@@ -29,8 +29,8 @@
#include "WKCACFContextFlusher.h"
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
#include <wtf/StdLibExtras.h>
-#include <QuartzCore/CACFContext.h>
namespace WebCore {
@@ -48,24 +48,18 @@ WKCACFContextFlusher::~WKCACFContextFlusher()
{
}
-void WKCACFContextFlusher::addContext(CACFContextRef context)
+void WKCACFContextFlusher::addContext(WKCACFContext* context)
{
ASSERT(context);
- if (m_contexts.add(context).second)
- CFRetain(context);
+ m_contexts.add(context);
}
-void WKCACFContextFlusher::removeContext(CACFContextRef context)
+void WKCACFContextFlusher::removeContext(WKCACFContext* context)
{
ASSERT(context);
- ContextSet::iterator found = m_contexts.find(context);
- if (found == m_contexts.end())
- return;
-
- CFRelease(*found);
- m_contexts.remove(found);
+ m_contexts.remove(context);
}
void WKCACFContextFlusher::flushAllContexts()
@@ -76,11 +70,8 @@ void WKCACFContextFlusher::flushAllContexts()
contextsToFlush.swap(m_contexts);
ContextSet::const_iterator end = contextsToFlush.end();
- for (ContextSet::const_iterator it = contextsToFlush.begin(); it != end; ++it) {
- CACFContextRef context = *it;
- CACFContextFlush(context);
- CFRelease(context);
- }
+ for (ContextSet::const_iterator it = contextsToFlush.begin(); it != end; ++it)
+ wkCACFContextFlush(*it);
}
}
diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.h b/WebCore/platform/graphics/win/WKCACFContextFlusher.h
index 9ce76aa..17ec41d 100644
--- a/WebCore/platform/graphics/win/WKCACFContextFlusher.h
+++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.h
@@ -32,7 +32,7 @@
#include <wtf/HashSet.h>
-typedef struct _CACFContext* CACFContextRef;
+struct WKCACFContext;
namespace WebCore {
@@ -40,8 +40,8 @@ class WKCACFContextFlusher : public Noncopyable {
public:
static WKCACFContextFlusher& shared();
- void addContext(CACFContextRef);
- void removeContext(CACFContextRef);
+ void addContext(WKCACFContext*);
+ void removeContext(WKCACFContext*);
void flushAllContexts();
@@ -49,7 +49,7 @@ private:
WKCACFContextFlusher();
~WKCACFContextFlusher();
- typedef HashSet<CACFContextRef> ContextSet;
+ typedef HashSet<WKCACFContext*> ContextSet;
ContextSet m_contexts;
};
diff --git a/WebCore/platform/graphics/win/WKCACFLayer.cpp b/WebCore/platform/graphics/win/WKCACFLayer.cpp
index bf47925..a8714e3 100644
--- a/WebCore/platform/graphics/win/WKCACFLayer.cpp
+++ b/WebCore/platform/graphics/win/WKCACFLayer.cpp
@@ -30,15 +30,10 @@
#include "WKCACFLayer.h"
#include "WKCACFLayerRenderer.h"
-#include <wtf/text/CString.h>
-
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
#include <stdio.h>
-#include <QuartzCore/CACFContext.h>
-#include <QuartzCore/CARender.h>
-
-#ifndef NDEBUG
#include <wtf/CurrentTime.h>
-#endif
+#include <wtf/text/CString.h>
namespace WebCore {
@@ -190,9 +185,9 @@ WKCACFLayer::~WKCACFLayer()
CACFLayerSetDisplayCallback(layer(), 0);
}
-void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context)
+void WKCACFLayer::becomeRootLayerForContext(WKCACFContext* context)
{
- CACFContextSetLayer(context, layer());
+ wkCACFContextSetLayer(context, layer());
setNeedsCommit();
}
diff --git a/WebCore/platform/graphics/win/WKCACFLayer.h b/WebCore/platform/graphics/win/WKCACFLayer.h
index 7243508..4c6639a 100644
--- a/WebCore/platform/graphics/win/WKCACFLayer.h
+++ b/WebCore/platform/graphics/win/WKCACFLayer.h
@@ -41,6 +41,8 @@
#include "PlatformString.h"
#include "TransformationMatrix.h"
+struct WKCACFContext;
+
namespace WebCore {
class WKCACFLayer;
@@ -83,7 +85,7 @@ public:
}
// Makes this layer the root when the passed context is rendered
- void becomeRootLayerForContext(CACFContextRef);
+ void becomeRootLayerForContext(WKCACFContext*);
static RetainPtr<CFTypeRef> cfValue(float value) { return RetainPtr<CFTypeRef>(AdoptCF, CFNumberCreate(0, kCFNumberFloat32Type, &value)); }
static RetainPtr<CFTypeRef> cfValue(const TransformationMatrix& value)
diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
index 4f39b13..73cb794 100755..100644
--- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
+++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
@@ -36,9 +36,7 @@
#include "WKCACFContextFlusher.h"
#include "WKCACFLayer.h"
#include "WebCoreInstanceHandle.h"
-#include <CoreGraphics/CGSRegion.h>
-#include <QuartzCore/CACFContext.h>
-#include <QuartzCore/CARenderOGL.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
#include <wtf/HashMap.h>
#include <wtf/OwnArrayPtr.h>
#include <wtf/OwnPtr.h>
@@ -108,7 +106,7 @@ private:
WKCACFLayerRenderer* m_renderer;
};
-typedef HashMap<CACFContextRef, WKCACFLayerRenderer*> ContextToWindowMap;
+typedef HashMap<WKCACFContext*, WKCACFLayerRenderer*> ContextToWindowMap;
static ContextToWindowMap& windowsForContexts()
{
@@ -206,7 +204,7 @@ bool WKCACFLayerRenderer::acceleratedCompositingAvailable()
return available;
}
-void WKCACFLayerRenderer::didFlushContext(CACFContextRef context)
+void WKCACFLayerRenderer::didFlushContext(WKCACFContext* context)
{
WKCACFLayerRenderer* window = windowsForContexts().get(context);
if (!window)
@@ -226,15 +224,13 @@ WKCACFLayerRenderer::WKCACFLayerRenderer(WKCACFLayerRendererClient* client)
: m_client(client)
, m_mightBeAbleToCreateDeviceLater(true)
, m_rootLayer(WKCACFRootLayer::create(this))
- , m_context(AdoptCF, CACFContextCreate(0))
- , m_renderContext(static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get())))
- , m_renderer(0)
+ , m_context(wkCACFContextCreate())
, m_hostWindow(0)
, m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired)
, m_backingStoreDirty(false)
, m_mustResetLostDeviceBeforeRendering(false)
{
- windowsForContexts().set(m_context.get(), this);
+ windowsForContexts().set(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.
@@ -250,13 +246,13 @@ WKCACFLayerRenderer::WKCACFLayerRenderer(WKCACFLayerRendererClient* client)
m_rootLayer->setGeometryFlipped(true);
#ifndef NDEBUG
- CGColorRef debugColor = createCGColor(Color(255, 0, 0, 204));
+ CGColorRef debugColor = CGColorCreateGenericRGB(1, 0, 0, 0.8);
m_rootLayer->setBackgroundColor(debugColor);
CGColorRelease(debugColor);
#endif
if (m_context)
- m_rootLayer->becomeRootLayerForContext(m_context.get());
+ m_rootLayer->becomeRootLayerForContext(m_context);
#ifndef NDEBUG
char* printTreeFlag = getenv("CA_PRINT_TREE");
@@ -267,6 +263,7 @@ WKCACFLayerRenderer::WKCACFLayerRenderer(WKCACFLayerRendererClient* client)
WKCACFLayerRenderer::~WKCACFLayerRenderer()
{
destroyRenderer();
+ wkCACFContextDestroy(m_context);
}
WKCACFLayer* WKCACFLayerRenderer::rootLayer() const
@@ -298,7 +295,7 @@ void WKCACFLayerRenderer::setRootChildLayer(WKCACFLayer* layer)
void WKCACFLayerRenderer::layerTreeDidChange()
{
- WKCACFContextFlusher::shared().addContext(m_context.get());
+ WKCACFContextFlusher::shared().addContext(m_context);
renderSoon();
}
@@ -373,7 +370,7 @@ bool WKCACFLayerRenderer::createRenderer()
initD3DGeometry();
- m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0);
+ wkCACFContextInitializeD3DDevice(m_context, m_d3dDevice.get());
if (IsWindow(m_hostWindow))
m_rootLayer->setBounds(bounds());
@@ -384,14 +381,10 @@ bool WKCACFLayerRenderer::createRenderer()
void WKCACFLayerRenderer::destroyRenderer()
{
if (m_context) {
- CACFContextSetLayer(m_context.get(), 0);
- windowsForContexts().remove(m_context.get());
- WKCACFContextFlusher::shared().removeContext(m_context.get());
+ windowsForContexts().remove(m_context);
+ WKCACFContextFlusher::shared().removeContext(m_context);
}
- if (m_renderer)
- CARenderOGLDestroy(m_renderer);
- m_renderer = 0;
m_d3dDevice = 0;
if (s_d3d)
s_d3d->Release();
@@ -476,7 +469,7 @@ void WKCACFLayerRenderer::paint()
render(dirtyRects);
}
-void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects)
+void WKCACFLayerRenderer::render(const Vector<CGRect>& windowDirtyRects)
{
ASSERT(m_d3dDevice);
@@ -499,31 +492,21 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects)
CFTimeInterval t = CACurrentMediaTime();
// Give the renderer some space to use. This needs to be valid until the
- // CARenderUpdateFinish() call below.
+ // wkCACFContextFinishUpdate() call below.
char space[4096];
- CARenderUpdate* u = CARenderUpdateBegin(space, sizeof(space), t, 0, 0, &bounds);
- if (!u)
+ if (!wkCACFContextBeginUpdate(m_context, space, sizeof(space), t, bounds, windowDirtyRects.data(), windowDirtyRects.size()))
return;
- CARenderContextLock(m_renderContext);
- CARenderUpdateAddContext(u, m_renderContext);
- CARenderContextUnlock(m_renderContext);
-
- for (size_t i = 0; i < dirtyRects.size(); ++i)
- CARenderUpdateAddRect(u, &dirtyRects[i]);
-
HRESULT err = S_OK;
do {
- CGSRegionObj rgn = CARenderUpdateCopyRegion(u);
+ // FIXME: don't need to clear dirty region if layer tree is opaque.
- if (!rgn)
+ WKCACFUpdateRectEnumerator* e = wkCACFContextCopyUpdateRectEnumerator(m_context);
+ if (!e)
break;
- // FIXME: don't need to clear dirty region if layer tree is opaque.
-
Vector<D3DRECT, 64> rects;
- CGSRegionEnumeratorObj e = CGSRegionEnumerator(rgn);
- for (const CGRect* r = CGSNextRect(e); r; r = CGSNextRect(e)) {
+ for (const CGRect* r = wkCACFUpdateRectEnumeratorNextRect(e); r; r = wkCACFUpdateRectEnumeratorNextRect(e)) {
D3DRECT rect;
rect.x1 = r->origin.x;
rect.x2 = rect.x1 + r->size.width;
@@ -532,8 +515,7 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects)
rects.append(rect);
}
- CGSReleaseRegionEnumerator(e);
- CGSReleaseRegion(rgn);
+ wkCACFUpdateRectEnumeratorRelease(e);
if (rects.isEmpty())
break;
@@ -541,13 +523,13 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects)
m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0);
m_d3dDevice->BeginScene();
- CARenderOGLRender(m_renderer, u);
+ wkCACFContextRenderUpdate(m_context);
m_d3dDevice->EndScene();
err = m_d3dDevice->Present(0, 0, 0, 0);
if (err == D3DERR_DEVICELOST) {
- CARenderUpdateAddRect(u, &bounds);
+ wkCACFContextAddUpdateRect(m_context, bounds);
if (!resetDevice(LostDevice)) {
// We can't reset the device right now. Try again soon.
renderSoon();
@@ -556,7 +538,7 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects)
}
} while (err == D3DERR_DEVICELOST);
- CARenderUpdateFinish(u);
+ wkCACFContextFinishUpdate(m_context);
#ifndef NDEBUG
if (m_printTree)
@@ -598,7 +580,7 @@ void WKCACFLayerRenderer::initD3DGeometry()
bool WKCACFLayerRenderer::resetDevice(ResetReason reason)
{
ASSERT(m_d3dDevice);
- ASSERT(m_renderContext);
+ ASSERT(m_context);
HRESULT hr = m_d3dDevice->TestCooperativeLevel();
@@ -617,10 +599,10 @@ bool WKCACFLayerRenderer::resetDevice(ResetReason reason)
// We can reset the device.
- // We have to purge the CARenderOGLContext whenever we reset the IDirect3DDevice9 in order to
+ // 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>.
- CARenderOGLPurge(m_renderer);
+ wkCACFContextReleaseD3DResources(m_context);
D3DPRESENT_PARAMETERS parameters = initialPresentationParameters();
hr = m_d3dDevice->Reset(&parameters);
diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
index 1d73b99..763fffa 100755..100644
--- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
+++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
@@ -41,9 +41,7 @@
#include <CoreGraphics/CGGeometry.h>
interface IDirect3DDevice9;
-typedef struct _CACFContext* CACFContextRef;
-typedef struct _CARenderContext CARenderContext;
-typedef struct _CARenderOGLContext CARenderOGLContext;
+struct WKCACFContext;
namespace WebCore {
@@ -64,7 +62,7 @@ public:
~WKCACFLayerRenderer();
static bool acceleratedCompositingAvailable();
- static void didFlushContext(CACFContextRef);
+ static void didFlushContext(WKCACFContext*);
void setRootContents(CGImageRef);
void setRootContentsAndDisplay(CGImageRef);
@@ -104,9 +102,7 @@ private:
COMPtr<IDirect3DDevice9> m_d3dDevice;
RefPtr<WKCACFRootLayer> m_rootLayer;
RefPtr<WKCACFLayer> m_rootChildLayer;
- RetainPtr<CACFContextRef> m_context;
- CARenderContext* m_renderContext;
- CARenderOGLContext* m_renderer;
+ WKCACFContext* m_context;
HWND m_hostWindow;
Timer<WKCACFLayerRenderer> m_renderTimer;
bool m_backingStoreDirty;
diff --git a/WebCore/platform/graphics/win/WebLayer.cpp b/WebCore/platform/graphics/win/WebLayer.cpp
index 70a522d..ecda294 100644
--- a/WebCore/platform/graphics/win/WebLayer.cpp
+++ b/WebCore/platform/graphics/win/WebLayer.cpp
@@ -94,7 +94,7 @@ void WebLayer::drawInContext(PlatformGraphicsContext* context)
#endif
if (m_owner->showRepaintCounter()) {
- String text = String::format("%d", m_owner->incrementRepaintCount());;
+ String text = String::number(m_owner->incrementRepaintCount());
CGContextSaveGState(context);
@@ -129,7 +129,7 @@ void WebLayer::drawInContext(PlatformGraphicsContext* context)
font.update(0);
GraphicsContext cg(context);
- cg.setFillColor(Color::black, DeviceColorSpace);
+ cg.setFillColor(Color::black, ColorSpaceDeviceRGB);
cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 5, aBounds.origin.y + 17));
CGContextRestoreGState(context);
diff --git a/WebCore/platform/graphics/win/WebTiledLayer.cpp b/WebCore/platform/graphics/win/WebTiledLayer.cpp
index 01dd6ae..4705033 100644
--- a/WebCore/platform/graphics/win/WebTiledLayer.cpp
+++ b/WebCore/platform/graphics/win/WebTiledLayer.cpp
@@ -201,7 +201,7 @@ void WebTiledLayer::addTile()
CACFLayerInsertSublayer(m_tileParent.get(), newLayer.get(), sublayers ? CFArrayGetCount(sublayers) : 0);
if (m_owner->showDebugBorders()) {
- CGColorRef borderColor = createCGColor(Color(128, 0, 128, 180));
+ CGColorRef borderColor = CGColorCreateGenericRGB(0.5, 0, 0.5, 0.7);
CACFLayerSetBorderColor(newLayer.get(), borderColor);
CGColorRelease(borderColor);
CACFLayerSetBorderWidth(newLayer.get(), 2);
diff --git a/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp b/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp
index a91b988..a0c10fc 100644
--- a/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp
+++ b/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp
@@ -1,5 +1,6 @@
/*
* 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
@@ -24,6 +25,7 @@
#include "AffineTransform.h"
#include "CharacterNames.h"
#include "Font.h"
+#include "GDIExtras.h"
#include "GlyphBuffer.h"
#include "Gradient.h"
#include "GraphicsContextPrivate.h"
@@ -322,8 +324,7 @@ public:
if (hdc == m_dc)
return;
-#if !defined(NO_ALPHABLEND)
- if (alphaPaint == AlphaPaintOther) {
+ if (alphaPaint == AlphaPaintOther && hasAlphaBlendSupport()) {
ASSERT(bmp && bmp->bytes() && bmp->is32bit());
unsigned* pixels = (unsigned*)bmp->bytes();
const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels();
@@ -332,13 +333,13 @@ public:
++pixels;
}
}
- if (m_opacity < 1. || alphaPaint == AlphaPaintOther) {
+ 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 };
- AlphaBlend(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend);
+ 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
-#endif
StretchBlt(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, SRCCOPY);
}
@@ -347,7 +348,7 @@ public:
Vector<GraphicsContextPlatformPrivateData> m_backupData;
};
-static HPEN createPen(const Color& col, double fWidth, StrokeStyle style)
+static PassOwnPtr<HPEN> createPen(const Color& col, double fWidth, StrokeStyle style)
{
int width = stableRound(fWidth);
if (width < 1)
@@ -367,12 +368,12 @@ static HPEN createPen(const Color& col, double fWidth, StrokeStyle style)
break;
}
- return CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue()));
+ return adoptPtr(CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue())));
}
-static inline HGDIOBJ createBrush(const Color& col)
+static inline PassOwnPtr<HBRUSH> createBrush(const Color& col)
{
- return CreateSolidBrush(RGB(col.red(), col.green(), col.blue()));
+ 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)
@@ -644,41 +645,33 @@ void GraphicsContext::drawRect(const IntRect& rect)
return;
trRect.move(transparentDC.toShift());
- HGDIOBJ brush = 0;
+ OwnPtr<HBRUSH> brush;
HGDIOBJ oldBrush;
if (fillColor().alpha()) {
brush = createBrush(fillColor());
- oldBrush = SelectObject(dc, brush);
+ oldBrush = SelectObject(dc, brush.get());
} else
- SelectObject(dc, GetStockObject(NULL_BRUSH));
+ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
- HGDIOBJ pen = 0;
+ OwnPtr<HPEN> pen;
HGDIOBJ oldPen;
if (strokeStyle() != NoStroke) {
pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
- oldPen = SelectObject(dc, pen);
+ oldPen = SelectObject(dc, pen.get());
} else
- SelectObject(dc, GetStockObject(NULL_PEN));
+ oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
- if (!brush && !pen)
- return;
-
- if (trRect.width() <= 0)
- trRect.setWidth(1);
- if (trRect.height() <= 0)
- trRect.setHeight(1);
-
- Rectangle(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+ if (brush || pen) {
+ if (trRect.width() <= 0)
+ trRect.setWidth(1);
+ if (trRect.height() <= 0)
+ trRect.setHeight(1);
- if (pen) {
- SelectObject(dc, oldPen);
- DeleteObject(pen);
+ Rectangle(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
}
- if (brush) {
- SelectObject(dc, oldBrush);
- DeleteObject(brush);
- }
+ SelectObject(dc, oldPen);
+ SelectObject(dc, oldBrush);
}
void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
@@ -702,14 +695,13 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
trPoint1 += transparentDC.toShift();
trPoint2 += transparentDC.toShift();
- HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
- HGDIOBJ oldPen = SelectObject(dc, pen);
+ 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);
- DeleteObject(pen);
}
void GraphicsContext::drawEllipse(const IntRect& rect)
@@ -728,32 +720,27 @@ void GraphicsContext::drawEllipse(const IntRect& rect)
return;
trRect.move(transparentDC.toShift());
- HGDIOBJ brush = 0;
+ OwnPtr<HBRUSH> brush;
HGDIOBJ oldBrush;
if (fillColor().alpha()) {
brush = createBrush(fillColor());
- oldBrush = SelectObject(dc, brush);
+ oldBrush = SelectObject(dc, brush.get());
} else
- SelectObject(dc, GetStockObject(NULL_BRUSH));
- HGDIOBJ pen = 0;
- HGDIOBJ oldPen;
+ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+
+ OwnPtr<HPEN> pen;
+ HGDIOBJ oldPen = 0;
if (strokeStyle() != NoStroke) {
pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
- oldPen = SelectObject(dc, pen);
+ oldPen = SelectObject(dc, pen.get());
} else
- SelectObject(dc, GetStockObject(NULL_PEN));
-
- Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+ oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
- if (pen) {
- SelectObject(dc, oldPen);
- DeleteObject(pen);
- }
+ if (brush || pen)
+ Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
- if (brush) {
- SelectObject(dc, oldBrush);
- DeleteObject(brush);
- }
+ SelectObject(dc, oldPen);
+ SelectObject(dc, oldBrush);
}
static inline bool equalAngle(double a, double b)
@@ -815,8 +802,8 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp
return;
trRect.move(transparentDC.toShift());
- HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
- HGDIOBJ oldPen = SelectObject(dc, pen);
+ 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;
@@ -872,7 +859,6 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp
SelectClipRgn(dc, clipRgn.get());
SelectObject(dc, oldPen);
- DeleteObject(pen);
}
void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
@@ -916,36 +902,27 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
winPoints[i].y += transparentDC.toShift().height();
}
- HGDIOBJ brush = 0;
+ OwnPtr<HBRUSH> brush;
HGDIOBJ oldBrush;
if (fillColor().alpha()) {
brush = createBrush(fillColor());
- oldBrush = SelectObject(dc, brush);
+ oldBrush = SelectObject(dc, brush.get());
} else
- SelectObject(dc, GetStockObject(NULL_BRUSH));
+ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
- HGDIOBJ pen = 0;
+ OwnPtr<HPEN> pen;
HGDIOBJ oldPen;
if (strokeStyle() != NoStroke) {
pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
- oldPen = SelectObject(dc, pen);
+ oldPen = SelectObject(dc, pen.get());
} else
- SelectObject(dc, GetStockObject(NULL_PEN));
-
- if (!brush && !pen)
- return;
-
- Polygon(dc, winPoints.data(), npoints);
+ oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
- if (pen) {
- SelectObject(dc, oldPen);
- DeleteObject(pen);
- }
+ if (brush || pen)
+ Polygon(dc, winPoints.data(), npoints);
- if (brush) {
- SelectObject(dc, oldBrush);
- DeleteObject(brush);
- }
+ SelectObject(dc, oldPen);
+ SelectObject(dc, oldBrush);
}
void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
@@ -1104,7 +1081,7 @@ void GraphicsContext::clearRect(const FloatRect& rect)
return;
}
- fillRect(rect, Color(Color::white), DeviceColorSpace);
+ fillRect(rect, Color(Color::white), ColorSpaceDeviceRGB);
}
void GraphicsContext::strokeRect(const FloatRect& rect, float width)
@@ -1124,8 +1101,8 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width)
return;
trRect.move(transparentDC.toShift());
- HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
- HGDIOBJ oldPen = SelectObject(dc, pen);
+ OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ HGDIOBJ oldPen = SelectObject(dc, pen.get());
int right = trRect.right() - 1;
int bottom = trRect.bottom() - 1;
@@ -1141,7 +1118,6 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width)
Polyline(dc, intPoints, 5);
SelectObject(dc, oldPen);
- DeleteObject(pen);
}
void GraphicsContext::beginTransparencyLayer(float opacity)
@@ -1286,9 +1262,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& to
RECT rectWin = dstRect;
- HGDIOBJ brush = createBrush(shadowColor);
- HGDIOBJ oldBrush = SelectObject(dc, brush);
-
+ OwnPtr<HBRUSH> brush = createBrush(shadowColor);
+ HGDIOBJ oldBrush = SelectObject(dc, brush.get());
+
SelectObject(dc, GetStockObject(NULL_PEN));
IntPoint centerPoint = rectCenterPoint(rectWin);
@@ -1324,7 +1300,6 @@ void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& to
drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomRight.width() * 2), stableRound(newBottomRight.height() * 2));
SelectObject(dc, oldBrush);
- DeleteObject(brush);
}
@@ -1382,8 +1357,9 @@ void GraphicsContext::fillPath()
if (!m_data->m_dc)
return;
+ OwnPtr<HBRUSH> brush = createBrush(c);
+
if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
- HGDIOBJ brush = createBrush(c);
for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) {
IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect()));
trRect.inflate(1);
@@ -1396,19 +1372,16 @@ void GraphicsContext::fillPath()
tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
SelectObject(dc, GetStockObject(NULL_PEN));
- HGDIOBJ oldBrush = SelectObject(dc, brush);
+ HGDIOBJ oldBrush = SelectObject(dc, brush.get());
i->platformPath()->fillPath(dc, &tr);
SelectObject(dc, oldBrush);
}
- DeleteObject(brush);
} else {
SelectObject(m_data->m_dc, GetStockObject(NULL_PEN));
- HGDIOBJ brush = createBrush(c);
- HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush);
+ HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush.get());
for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i)
i->platformPath()->fillPath(m_data->m_dc, &m_data->m_transform);
SelectObject(m_data->m_dc, oldBrush);
- DeleteObject(brush);
}
}
@@ -1422,8 +1395,9 @@ void GraphicsContext::strokePath()
if (!m_data->m_dc)
return;
+ OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+
if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
- HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) {
IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect()));
trRect.inflate(1);
@@ -1436,19 +1410,16 @@ void GraphicsContext::strokePath()
tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
SelectObject(dc, GetStockObject(NULL_BRUSH));
- HGDIOBJ oldPen = SelectObject(dc, pen);
+ HGDIOBJ oldPen = SelectObject(dc, pen.get());
i->platformPath()->strokePath(dc, &tr);
SelectObject(dc, oldPen);
}
- DeleteObject(pen);
} else {
SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH));
- HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
- HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen);
+ HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen.get());
for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i)
i->platformPath()->strokePath(m_data->m_dc, &m_data->m_transform);
SelectObject(m_data->m_dc, oldPen);
- DeleteObject(pen);
}
}
@@ -1465,7 +1436,7 @@ void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient)
if (numStops == 1) {
const Gradient::ColorStop& stop = stops.first();
Color color(stop.red, stop.green, stop.blue, stop.alpha);
- fillRect(r, color, DeviceColorSpace);
+ fillRect(r, color, ColorSpaceDeviceRGB);
return;
}
@@ -1555,7 +1526,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
if (m_common->state.fillGradient)
fillRect(rect, m_common->state.fillGradient.get());
else
- fillRect(rect, fillColor(), DeviceColorSpace);
+ fillRect(rect, fillColor(), ColorSpaceDeviceRGB);
restorePlatformState();
}
diff --git a/WebCore/platform/graphics/wince/ImageWinCE.cpp b/WebCore/platform/graphics/wince/ImageWinCE.cpp
index 61ec954..53b9b68 100644
--- a/WebCore/platform/graphics/wince/ImageWinCE.cpp
+++ b/WebCore/platform/graphics/wince/ImageWinCE.cpp
@@ -82,9 +82,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
IntSize imageSize = BitmapImage::size();
if (size)
- drawFrameMatchingSourceSize(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy);
+ 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()), DeviceColorSpace, CompositeCopy);
+ draw(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0, 0, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy);
}
SelectObject(hdc.get(), hOldBmp);
diff --git a/WebCore/platform/graphics/wince/PathWinCE.cpp b/WebCore/platform/graphics/wince/PathWinCE.cpp
index 4f0195c..fa4c8fb 100644
--- a/WebCore/platform/graphics/wince/PathWinCE.cpp
+++ b/WebCore/platform/graphics/wince/PathWinCE.cpp
@@ -123,11 +123,6 @@ bool Path::isEmpty() const
return m_path->isEmpty();
}
-String Path::debugString() const
-{
- return m_path->debugString();
-}
-
void Path::apply(void* info, PathApplierFunction function) const
{
m_path->apply(info, function);
diff --git a/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp b/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp
index 80e01a9..8534f89 100644
--- a/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp
+++ b/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp
@@ -754,43 +754,6 @@ void PlatformPath::addEllipse(const FloatRect& r)
addEllipse(r.location() + radius, radius.width(), radius.height(), 0, 0, true);
}
-String PlatformPath::debugString() const
-{
- String ret;
- for (PlatformPathElements::const_iterator i(m_elements.begin()); i != m_elements.end(); ++i) {
- switch (i->platformType()) {
- case PlatformPathElement::PathMoveTo:
- case PlatformPathElement::PathLineTo:
- ret += String::format("M %f %f\n", i->pointAt(0).m_x, i->pointAt(0).m_y);
- break;
- case PlatformPathElement::PathArcTo:
- ret += String::format("A %f %f %f %f %f %f %c\n"
- , i->arcTo().m_end.m_x, i->arcTo().m_end.m_y
- , i->arcTo().m_center.m_x, i->arcTo().m_center.m_y
- , i->arcTo().m_radius.m_x, i->arcTo().m_radius.m_y
- , i->arcTo().m_clockwise? 'Y' : 'N');
- break;
- case PlatformPathElement::PathQuadCurveTo:
- ret += String::format("Q %f %f %f %f\n"
- , i->pointAt(0).m_x, i->pointAt(0).m_y
- , i->pointAt(1).m_x, i->pointAt(1).m_y);
- break;
- case PlatformPathElement::PathBezierCurveTo:
- ret += String::format("B %f %f %f %f %f %f\n"
- , i->pointAt(0).m_x, i->pointAt(0).m_y
- , i->pointAt(1).m_x, i->pointAt(1).m_y
- , i->pointAt(2).m_x, i->pointAt(2).m_y);
- break;
- default:
- ASSERT(i->platformType() == PlatformPathElement::PathCloseSubpath);
- ret += "S\n";
- break;
- }
- }
-
- return ret;
-}
-
void PlatformPath::apply(void* info, PathApplierFunction function) const
{
PathElement pelement;
diff --git a/WebCore/platform/graphics/wince/PlatformPathWinCE.h b/WebCore/platform/graphics/wince/PlatformPathWinCE.h
index 3414b04..4c86fc3 100644
--- a/WebCore/platform/graphics/wince/PlatformPathWinCE.h
+++ b/WebCore/platform/graphics/wince/PlatformPathWinCE.h
@@ -164,7 +164,6 @@ namespace WebCore {
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);
- String debugString() const;
void apply(void* info, PathApplierFunction function) const;
private:
diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
index a39404a..30daa67 100644
--- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
+++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
@@ -120,8 +120,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
setPaintingDisabled(!context);
if (context) {
// Make sure the context starts in sync with our state.
- setPlatformFillColor(fillColor(), DeviceColorSpace);
- setPlatformStrokeColor(strokeColor(), DeviceColorSpace);
+ setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
+ setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
}
#if USE(WXGC)
m_data->context = (wxGCDC*)context;
diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp
index 3006e27..f5355f2 100644
--- a/WebCore/platform/graphics/wx/PathWx.cpp
+++ b/WebCore/platform/graphics/wx/PathWx.cpp
@@ -117,12 +117,6 @@ bool Path::strokeContains(StrokeStyleApplier*, const FloatPoint&) const
return false;
}
-String Path::debugString() const
-{
- notImplemented();
- return String();
-}
-
Path& Path::operator=(const Path& path)
{
*m_path = *path.platformPath();
diff --git a/WebCore/platform/gtk/ClipboardGtk.cpp b/WebCore/platform/gtk/ClipboardGtk.cpp
index e7ee432..49bcb7d 100644
--- a/WebCore/platform/gtk/ClipboardGtk.cpp
+++ b/WebCore/platform/gtk/ClipboardGtk.cpp
@@ -139,23 +139,13 @@ void ClipboardGtk::clearAllData()
m_helper->writeClipboardContents(m_clipboard);
}
-static String joinURIList(Vector<KURL> uriList)
-{
- if (uriList.isEmpty())
- return String();
-
- String joined(uriList[0].string());
- for (size_t i = 1; i < uriList.size(); i++) {
- joined.append("\r\n");
- joined.append(uriList[i].string());
- }
-
- return joined;
-}
-
String ClipboardGtk::getData(const String& typeString, bool& success) const
{
- success = false; // Pessimism.
+ success = true; // According to http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html
+ // "The getData(format) method must return the data that is associated with the type format converted
+ // to ASCII lowercase, if any, and must return the empty string otherwise." Since success == false
+ // results in an 'undefined' return value, we always want to return success == true. This parameter
+ // should eventually be removed.
if (policy() != ClipboardReadable || !m_dataObject)
return String();
@@ -163,33 +153,14 @@ String ClipboardGtk::getData(const String& typeString, bool& success) const
m_helper->getClipboardContents(m_clipboard);
ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString);
- if (type == ClipboardDataTypeURIList) {
- if (!m_dataObject->hasURIList())
- return String();
- success = true;
- return joinURIList(m_dataObject->uriList());
- }
-
- if (type == ClipboardDataTypeURL) {
- if (!m_dataObject->hasURL())
- return String();
- success = true;
+ if (type == ClipboardDataTypeURIList)
+ return m_dataObject->uriList();
+ if (type == ClipboardDataTypeURL)
return m_dataObject->url();
- }
-
- if (type == ClipboardDataTypeMarkup) {
- if (!m_dataObject->hasMarkup())
- return String();
- success = true;
+ if (type == ClipboardDataTypeMarkup)
return m_dataObject->markup();
- }
-
- if (type == ClipboardDataTypeText) {
- if (!m_dataObject->hasText())
- return String();
- success = true;
+ if (type == ClipboardDataTypeText)
return m_dataObject->text();
- }
return String();
}
@@ -202,18 +173,8 @@ bool ClipboardGtk::setData(const String& typeString, const String& data)
bool success = false;
ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString);
if (type == ClipboardDataTypeURIList || type == ClipboardDataTypeURL) {
- Vector<KURL> uriList;
- gchar** uris = g_uri_list_extract_uris(data.utf8().data());
- if (uris) {
- gchar** currentURI = uris;
- while (*currentURI) {
- uriList.append(KURL(KURL(), *currentURI));
- currentURI++;
- }
- g_strfreev(uris);
- m_dataObject->setURIList(uriList);
- success = true;
- }
+ m_dataObject->setURIList(data);
+ success = true;
} else if (type == ClipboardDataTypeMarkup) {
m_dataObject->setMarkup(data);
success = true;
@@ -248,9 +209,11 @@ HashSet<String> ClipboardGtk::types() const
if (m_dataObject->hasURIList()) {
types.add("text/uri-list");
types.add("URL");
- types.add("Files");
}
+ if (m_dataObject->hasFilenames())
+ types.add("Files");
+
return types;
}
@@ -263,11 +226,9 @@ PassRefPtr<FileList> ClipboardGtk::files() const
m_helper->getClipboardContents(m_clipboard);
RefPtr<FileList> fileList = FileList::create();
- Vector<String> fileVector(m_dataObject->files());
-
- for (size_t i = 0; i < fileVector.size(); i++)
- fileList->append(File::create(fileVector[i]));
-
+ const Vector<String>& filenames = m_dataObject->filenames();
+ for (size_t i = 0; i < filenames.size(); i++)
+ fileList->append(File::create(filenames[i]));
return fileList.release();
}
diff --git a/WebCore/platform/gtk/CursorGtk.cpp b/WebCore/platform/gtk/CursorGtk.cpp
index d1f1293..9971bfb 100644
--- a/WebCore/platform/gtk/CursorGtk.cpp
+++ b/WebCore/platform/gtk/CursorGtk.cpp
@@ -28,28 +28,17 @@
#include "config.h"
#include "CursorGtk.h"
+#include "GtkVersioning.h"
#include "Image.h"
#include "IntPoint.h"
+#include "PlatformRefPtrCairo.h"
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <wtf/Assertions.h>
namespace WebCore {
-static GdkPixmap* createPixmapFromBits(const unsigned char* bits, const IntSize& size)
-{
- cairo_surface_t* dataSurface = cairo_image_surface_create_for_data(const_cast<unsigned char*>(bits), CAIRO_FORMAT_A1, size.width(), size.height(), size.width() / 8);
- GdkPixmap* pixmap = gdk_pixmap_new(0, size.width(), size.height(), 1);
- cairo_t* cr = gdk_cairo_create(pixmap);
- cairo_set_source_surface(cr, dataSurface, 0, 0);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint(cr);
- cairo_destroy(cr);
- cairo_surface_destroy(dataSurface);
- return pixmap;
-}
-
static PlatformRefPtr<GdkCursor> createNamedCursor(CustomCursorType cursorType)
{
CustomCursor cursor = CustomCursors[cursorType];
@@ -57,12 +46,17 @@ static PlatformRefPtr<GdkCursor> createNamedCursor(CustomCursorType cursorType)
if (c)
return c;
- const GdkColor fg = { 0, 0, 0, 0 };
- const GdkColor bg = { 65535, 65535, 65535, 65535 };
IntSize cursorSize = IntSize(32, 32);
- PlatformRefPtr<GdkPixmap> source = adoptPlatformRef(createPixmapFromBits(cursor.bits, cursorSize));
- PlatformRefPtr<GdkPixmap> mask = adoptPlatformRef(createPixmapFromBits(cursor.mask_bits, cursorSize));
- return adoptPlatformRef(gdk_cursor_new_from_pixmap(source.get(), mask.get(), &fg, &bg, cursor.hot_x, cursor.hot_y));
+ PlatformRefPtr<cairo_surface_t> source = adoptPlatformRef(cairo_image_surface_create_for_data(const_cast<unsigned char*>(cursor.bits), CAIRO_FORMAT_A1, 32, 32, 4));
+ PlatformRefPtr<cairo_surface_t> mask = adoptPlatformRef(cairo_image_surface_create_for_data(const_cast<unsigned char*>(cursor.mask_bits), CAIRO_FORMAT_A1, 32, 32, 4));
+ PlatformRefPtr<cairo_surface_t> surface = adoptPlatformRef(cairo_image_surface_create(CAIRO_FORMAT_A1, 32, 32));
+ PlatformRefPtr<cairo_t> cr = adoptPlatformRef(cairo_create(surface.get()));
+
+ cairo_set_source_surface(cr.get(), source.get(), cursor.hot_x, cursor.hot_y);
+ cairo_mask_surface(cr.get(), mask.get(), cursor.hot_x, cursor.hot_y);
+
+ PlatformRefPtr<GdkPixbuf> pixbuf = adoptPlatformRef(gdk_pixbuf_get_from_surface(surface.get(), 0, 0, 32, 32));
+ return adoptPlatformRef(gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf.get(), 0, 0));
}
static PlatformRefPtr<GdkCursor> createCustomCursor(Image* image, const IntPoint& hotSpot)
diff --git a/WebCore/platform/gtk/DataObjectGtk.cpp b/WebCore/platform/gtk/DataObjectGtk.cpp
index db13345..05a2da9 100644
--- a/WebCore/platform/gtk/DataObjectGtk.cpp
+++ b/WebCore/platform/gtk/DataObjectGtk.cpp
@@ -59,8 +59,51 @@ void DataObjectGtk::setMarkup(const String& newMarkup)
m_markup = newMarkup;
}
+void DataObjectGtk::setURIList(const String& uriListString)
+{
+ m_uriList = uriListString;
+
+ // This code is originally from: platform/chromium/ChromiumDataObject.cpp.
+ // FIXME: We should make this code cross-platform eventually.
+
+ // Line separator is \r\n per RFC 2483 - however, for compatibility
+ // reasons we also allow just \n here.
+ Vector<String> uriList;
+ uriListString.split('\n', uriList);
+
+ // Process the input and copy the first valid URL into the url member.
+ // In case no URLs can be found, subsequent calls to getData("URL")
+ // will get an empty string. This is in line with the HTML5 spec (see
+ // "The DragEvent and DataTransfer interfaces"). Also extract all filenames
+ // from the URI list.
+ bool setURL = false;
+ for (size_t i = 0; i < uriList.size(); ++i) {
+ String& line = uriList[i];
+ line = line.stripWhiteSpace();
+ if (line.isEmpty())
+ continue;
+ if (line[0] == '#')
+ continue;
+
+ KURL url = KURL(KURL(), line);
+ if (url.isValid()) {
+ if (!setURL) {
+ m_url = url;
+ setURL = true;
+ }
+
+ GOwnPtr<GError> error;
+ GOwnPtr<gchar> filename(g_filename_from_uri(line.utf8().data(), 0, &error.outPtr()));
+ if (!error && filename)
+ m_filenames.append(String::fromUTF8(filename.get()));
+ }
+ }
+}
+
void DataObjectGtk::setURL(const KURL& url, const String& label)
{
+ m_url = url;
+ m_uriList = url;
setText(url.string());
String actualLabel(label);
@@ -75,10 +118,6 @@ void DataObjectGtk::setURL(const KURL& url, const String& label)
append(markup, String::fromUTF8(escaped.get()));
append(markup, "</a>");
setMarkup(String::adopt(markup));
-
- Vector<KURL> uriList;
- uriList.append(url);
- setURIList(uriList);
}
void DataObjectGtk::clearText()
@@ -93,34 +132,6 @@ void DataObjectGtk::clearMarkup()
m_markup = "";
}
-Vector<String> DataObjectGtk::files()
-{
- Vector<KURL> uris(uriList());
- Vector<String> files;
-
- for (size_t i = 0; i < uris.size(); i++) {
- KURL& uri = uris[0];
- if (!uri.isValid() || !uri.isLocalFile())
- continue;
-
- files.append(uri.string());
- }
-
- return files;
-}
-
-String DataObjectGtk::url()
-{
- Vector<KURL> uris(uriList());
- for (size_t i = 0; i < uris.size(); i++) {
- KURL& uri = uris[0];
- if (uri.isValid())
- return uri;
- }
-
- return String();
-}
-
String DataObjectGtk::urlLabel()
{
if (hasText())
@@ -132,18 +143,19 @@ String DataObjectGtk::urlLabel()
return String();
}
-bool DataObjectGtk::hasURL()
-{
- return !url().isEmpty();
-}
-
void DataObjectGtk::clear()
{
m_text = "";
m_markup = "";
- m_uriList.clear();
+ m_uriList = "";
+ m_url = KURL();
m_image = 0;
m_range = 0;
+
+ // We do not clear filenames. According to the spec: "The clearData() method
+ // does not affect whether any files were included in the drag, so the types
+ // attribute's list might still not be empty after calling clearData() (it would
+ // still contain the "Files" string if any files were included in the drag)."
}
DataObjectGtk* DataObjectGtk::forClipboard(GtkClipboard* clipboard)
diff --git a/WebCore/platform/gtk/DataObjectGtk.h b/WebCore/platform/gtk/DataObjectGtk.h
index e6095da..f6b13fd 100644
--- a/WebCore/platform/gtk/DataObjectGtk.h
+++ b/WebCore/platform/gtk/DataObjectGtk.h
@@ -36,28 +36,30 @@ public:
return adoptRef(new DataObjectGtk());
}
- Vector<KURL> uriList() { return m_uriList; }
+ const KURL& url() { return m_url; }
+ const String& uriList() { return m_uriList; }
+ const Vector<String>& filenames() { return m_filenames; }
GdkPixbuf* image() { return m_image.get(); }
void setRange(PassRefPtr<Range> newRange) { m_range = newRange; }
- void setURIList(const Vector<KURL>& newURIList) { m_uriList = newURIList; }
void setImage(GdkPixbuf* newImage) { m_image = newImage; }
void setDragContext(GdkDragContext* newDragContext) { m_dragContext = newDragContext; }
void setURL(const KURL&, const String&);
bool hasText() { return m_range || !m_text.isEmpty(); }
bool hasMarkup() { return m_range || !m_markup.isEmpty(); }
bool hasURIList() { return !m_uriList.isEmpty(); }
+ bool hasURL() { return !m_url.isEmpty() && m_url.isValid(); }
+ bool hasFilenames() { return !m_filenames.isEmpty(); }
bool hasImage() { return m_image; }
- void clearURIList() { m_uriList.clear(); }
+ void clearURIList() { m_uriList = ""; }
+ void clearURL() { m_url = KURL(); }
void clearImage() { m_image = 0; }
GdkDragContext* dragContext() { return m_dragContext.get(); }
String text();
String markup();
- Vector<String> files();
- void setText(const String& newText);
- void setMarkup(const String& newMarkup);
- bool hasURL();
- String url();
+ void setText(const String&);
+ void setMarkup(const String&);
+ void setURIList(const String&);
String urlLabel();
void clear();
void clearText();
@@ -68,7 +70,9 @@ public:
private:
String m_text;
String m_markup;
- Vector<KURL> m_uriList;
+ KURL m_url;
+ String m_uriList;
+ Vector<String> m_filenames;
PlatformRefPtr<GdkPixbuf> m_image;
PlatformRefPtr<GdkDragContext> m_dragContext;
RefPtr<Range> m_range;
diff --git a/WebCore/platform/gtk/DragDataGtk.cpp b/WebCore/platform/gtk/DragDataGtk.cpp
index 69966aa..42ddb16 100644
--- a/WebCore/platform/gtk/DragDataGtk.cpp
+++ b/WebCore/platform/gtk/DragDataGtk.cpp
@@ -37,14 +37,12 @@ bool DragData::containsColor() const
bool DragData::containsFiles() const
{
- return !m_platformDragData->files().isEmpty();
+ return m_platformDragData->hasFilenames();
}
void DragData::asFilenames(Vector<String>& result) const
{
- Vector<String> files(m_platformDragData->files());
- for (size_t i = 0; i < files.size(); i++)
- result.append(files[i]);
+ result = m_platformDragData->filenames();
}
bool DragData::containsPlainText() const
diff --git a/WebCore/platform/gtk/FileChooserGtk.cpp b/WebCore/platform/gtk/FileChooserGtk.cpp
index 4600215..54763d4 100644
--- a/WebCore/platform/gtk/FileChooserGtk.cpp
+++ b/WebCore/platform/gtk/FileChooserGtk.cpp
@@ -34,7 +34,6 @@
#include <wtf/text/CString.h>
#include <glib.h>
-#include <gtk/gtk.h>
namespace WebCore {
diff --git a/WebCore/platform/gtk/GtkVersioning.c b/WebCore/platform/gtk/GtkVersioning.c
index f5466be..071c5e5 100644
--- a/WebCore/platform/gtk/GtkVersioning.c
+++ b/WebCore/platform/gtk/GtkVersioning.c
@@ -52,7 +52,7 @@ void gtk_adjustment_configure(GtkAdjustment* adjustment, gdouble value, gdouble
GdkDevice *getDefaultGDKPointerDevice(GdkWindow* window)
{
#ifndef GTK_API_VERSION_2
- GdkDeviceManager *manager = gdk_display_get_device_manager(gdk_drawable_get_display(window));
+ GdkDeviceManager *manager = gdk_display_get_device_manager(gdk_window_get_display(window));
return gdk_device_manager_get_client_pointer(manager);
#else
return gdk_device_get_core_pointer();
@@ -98,3 +98,166 @@ const gchar* gtk_menu_item_get_label(GtkMenuItem* menuItem)
return 0;
}
#endif // GTK_CHECK_VERSION(2, 16, 0)
+
+#ifdef GTK_API_VERSION_2
+static cairo_format_t
+gdk_cairo_format_for_content(cairo_content_t content)
+{
+ switch (content) {
+ case CAIRO_CONTENT_COLOR:
+ return CAIRO_FORMAT_RGB24;
+ case CAIRO_CONTENT_ALPHA:
+ return CAIRO_FORMAT_A8;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ default:
+ return CAIRO_FORMAT_ARGB32;
+ }
+}
+
+static cairo_surface_t*
+gdk_cairo_surface_coerce_to_image(cairo_surface_t* surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_surface_t * copy;
+ cairo_t * cr;
+
+ if (cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE
+ && cairo_surface_get_content(surface) == content
+ && cairo_image_surface_get_width(surface) >= width
+ && cairo_image_surface_get_height(surface) >= height)
+ return cairo_surface_reference(surface);
+
+ copy = cairo_image_surface_create(gdk_cairo_format_for_content(content),
+ width,
+ height);
+
+ cr = cairo_create(copy);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface(cr, surface, 0, 0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+
+ return copy;
+}
+
+static void
+convert_alpha(guchar * destData, int destStride,
+ guchar * srcData, int srcStride,
+ int srcX, int srcY, int width, int height)
+{
+ int x, y;
+
+ srcData += srcStride * srcY + srcY * 4;
+
+ for (y = 0; y < height; y++) {
+ guint32 * src = (guint32 *) srcData;
+
+ for (x = 0; x < width; x++) {
+ guint alpha = src[x] >> 24;
+
+ if (!alpha) {
+ destData[x * 4 + 0] = 0;
+ destData[x * 4 + 1] = 0;
+ destData[x * 4 + 2] = 0;
+ } else {
+ destData[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+ destData[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
+ destData[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
+ }
+ destData[x * 4 + 3] = alpha;
+ }
+
+ srcData += srcStride;
+ destData += destStride;
+ }
+}
+
+static void
+convert_no_alpha(guchar * destData, int destStride, guchar * srcData,
+ int srcStride, int srcX, int srcY,
+ int width, int height)
+{
+ int x, y;
+
+ srcData += srcStride * srcY + srcX * 4;
+
+ for (y = 0; y < height; y++) {
+ guint32 * src = (guint32 *) srcData;
+
+ for (x = 0; x < width; x++) {
+ destData[x * 3 + 0] = src[x] >> 16;
+ destData[x * 3 + 1] = src[x] >> 8;
+ destData[x * 3 + 2] = src[x];
+ }
+
+ srcData += srcStride;
+ destData += destStride;
+ }
+}
+
+/**
+ * gdk_pixbuf_get_from_surface:
+ * @surface: surface to copy from
+ * @src_x: Source X coordinate within @surface
+ * @src_y: Source Y coordinate within @surface
+ * @width: Width in pixels of region to get
+ * @height: Height in pixels of region to get
+ *
+ * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
+ * representation inside a #GdkPixbuf. This allows you to efficiently read
+ * individual pixels from cairo surfaces. For #GdkWindows, use
+ * gdk_pixbuf_get_from_window() instead.
+ *
+ * This function will create an RGB pixbuf with 8 bits per channel. The pixbuf
+ * will contain an alpha channel if the @surface contains one.
+ *
+ * Return value: (transfer full): A newly-created pixbuf with a reference count
+ * of 1, or %NULL on error
+ **/
+GdkPixbuf*
+gdk_pixbuf_get_from_surface(cairo_surface_t * surface,
+ int srcX, int srcY,
+ int width, int height)
+{
+ cairo_content_t content;
+ GdkPixbuf * dest;
+
+ /* General sanity checks */
+ g_return_val_if_fail(!surface, NULL);
+ g_return_val_if_fail(srcX >= 0 && srcY >= 0, NULL);
+ g_return_val_if_fail(width > 0 && height > 0, NULL);
+
+ content = cairo_surface_get_content(surface) | CAIRO_CONTENT_COLOR;
+ dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+ !!(content & CAIRO_CONTENT_ALPHA),
+ 8,
+ width, height);
+
+ surface = gdk_cairo_surface_coerce_to_image(surface, content, srcX + width, srcY + height);
+ cairo_surface_flush(surface);
+ if (cairo_surface_status(surface) || !dest) {
+ cairo_surface_destroy(surface);
+ return NULL;
+ }
+
+ if (gdk_pixbuf_get_has_alpha(dest))
+ convert_alpha(gdk_pixbuf_get_pixels(dest),
+ gdk_pixbuf_get_rowstride(dest),
+ cairo_image_surface_get_data(surface),
+ cairo_image_surface_get_stride(surface),
+ srcX, srcY,
+ width, height);
+ else
+ convert_no_alpha(gdk_pixbuf_get_pixels(dest),
+ gdk_pixbuf_get_rowstride(dest),
+ cairo_image_surface_get_data(surface),
+ cairo_image_surface_get_stride(surface),
+ srcX, srcY,
+ width, height);
+
+ cairo_surface_destroy(surface);
+ return dest;
+}
+#endif // GTK_API_VERSION_2
diff --git a/WebCore/platform/gtk/GtkVersioning.h b/WebCore/platform/gtk/GtkVersioning.h
index a874e9e..b40e497 100644
--- a/WebCore/platform/gtk/GtkVersioning.h
+++ b/WebCore/platform/gtk/GtkVersioning.h
@@ -32,8 +32,18 @@ G_BEGIN_DECLS
// Macros to avoid deprecation checking churn
#ifndef GTK_API_VERSION_2
#define GDK_DISPLAY() (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()))
+#else
+GdkPixbuf* gdk_pixbuf_get_from_surface(cairo_surface_t* surface, int srcX, int srcY,
+ int width, int height);
#endif
+#if !GTK_CHECK_VERSION(2, 24, 0)
+#define gdk_window_get_display(window) gdk_drawable_get_display(window)
+#ifdef GDK_DISABLE_DEPRECATED
+#define gdk_window_get_visual gdk_drawable_get_visual
+#endif
+#endif // GTK_CHECK_VERSION(2, 24, 0)
+
#if !GTK_CHECK_VERSION(2, 21, 2)
#define gdk_visual_get_depth(visual) (visual)->depth
#define gdk_visual_get_bits_per_rgb(visual) (visual)->bits_per_rgb
diff --git a/WebCore/platform/gtk/Language.cpp b/WebCore/platform/gtk/LanguageGtk.cpp
index f1d5750..7d7a66d 100644
--- a/WebCore/platform/gtk/Language.cpp
+++ b/WebCore/platform/gtk/LanguageGtk.cpp
@@ -24,16 +24,15 @@
#include "PlatformString.h"
#include <wtf/text/CString.h>
-#include <gtk/gtk.h>
+#include <glib.h>
#include <locale.h>
-#include <pango/pango.h>
namespace WebCore {
// Using pango_language_get_default() here is not an option, because
// it doesn't support changing the locale in runtime, so it returns
// always the same value.
-String defaultLanguage()
+String platformDefaultLanguage()
{
char* localeDefault = setlocale(LC_CTYPE, NULL);
diff --git a/WebCore/platform/gtk/PasteboardHelper.cpp b/WebCore/platform/gtk/PasteboardHelper.cpp
index 95df25f..9f75728 100644
--- a/WebCore/platform/gtk/PasteboardHelper.cpp
+++ b/WebCore/platform/gtk/PasteboardHelper.cpp
@@ -92,17 +92,6 @@ GtkTargetList* PasteboardHelper::targetList() const
return m_targetList;
}
-static Vector<KURL> urisToKURLVector(gchar** uris)
-{
- ASSERT(uris);
-
- Vector<KURL> uriList;
- for (int i = 0; *(uris + i); i++)
- uriList.append(KURL(KURL(), *(uris + i)));
-
- return uriList;
-}
-
static String selectionDataToUTF8String(GtkSelectionData* data)
{
// g_strndup guards against selection data that is not null-terminated.
@@ -130,11 +119,7 @@ void PasteboardHelper::getClipboardContents(GtkClipboard* clipboard)
if (gtk_clipboard_wait_is_target_available(clipboard, uriListAtom)) {
if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, uriListAtom)) {
- gchar** uris = gtk_selection_data_get_uris(data);
- if (uris) {
- dataObject->setURIList(urisToKURLVector(uris));
- g_strfreev(uris);
- }
+ dataObject->setURIList(selectionDataToUTF8String(data));
gtk_selection_data_free(data);
}
}
@@ -151,13 +136,9 @@ void PasteboardHelper::fillSelectionData(GtkSelectionData* selectionData, guint
reinterpret_cast<const guchar*>(markup.get()), strlen(markup.get()) + 1);
} else if (info == getIdForTargetType(TargetTypeURIList)) {
- Vector<KURL> uriList(dataObject->uriList());
- gchar** uris = g_new0(gchar*, uriList.size() + 1);
- for (size_t i = 0; i < uriList.size(); i++)
- uris[i] = g_strdup(uriList[i].string().utf8().data());
-
- gtk_selection_data_set_uris(selectionData, uris);
- g_strfreev(uris);
+ CString uriList = dataObject->uriList().utf8();
+ gtk_selection_data_set(selectionData, uriListAtom, 8,
+ reinterpret_cast<const guchar*>(uriList.data()), uriList.length() + 1);
} else if (info == getIdForTargetType(TargetTypeNetscapeURL) && dataObject->hasURL()) {
String url(dataObject->url());
@@ -209,27 +190,16 @@ void PasteboardHelper::fillDataObjectFromDropData(GtkSelectionData* data, guint
else if (target == markupAtom)
dataObject->setMarkup(selectionDataToUTF8String(data));
else if (target == uriListAtom) {
- gchar** uris = gtk_selection_data_get_uris(data);
- if (!uris)
- return;
-
- Vector<KURL> uriList(urisToKURLVector(uris));
- dataObject->setURIList(uriList);
- g_strfreev(uris);
+ dataObject->setURIList(selectionDataToUTF8String(data));
} else if (target == netscapeURLAtom) {
String urlWithLabel(selectionDataToUTF8String(data));
-
Vector<String> pieces;
urlWithLabel.split("\n", pieces);
// Give preference to text/uri-list here, as it can hold more
// than one URI but still take the label if there is one.
- if (!dataObject->hasURL()) {
- Vector<KURL> uriList;
- uriList.append(KURL(KURL(), pieces[0]));
- dataObject->setURIList(uriList);
- }
-
+ if (!dataObject->hasURIList())
+ dataObject->setURIList(pieces[0]);
if (pieces.size() > 1)
dataObject->setText(pieces[1]);
}
diff --git a/WebCore/platform/gtk/PlatformScreenGtk.cpp b/WebCore/platform/gtk/PlatformScreenGtk.cpp
index 6ace728..9c70d0e 100644
--- a/WebCore/platform/gtk/PlatformScreenGtk.cpp
+++ b/WebCore/platform/gtk/PlatformScreenGtk.cpp
@@ -63,8 +63,7 @@ static GdkVisual* getVisual(Widget* widget)
return 0;
}
-
- return gdk_drawable_get_visual(GDK_DRAWABLE(gtk_widget_get_window(container)));
+ return gdk_window_get_visual(gtk_widget_get_window(container));
}
int screenDepth(Widget* widget)
@@ -123,7 +122,7 @@ FloatRect screenAvailableRect(Widget* widget)
return screenRect(widget);
GdkDrawable* rootWindow = GDK_DRAWABLE(gtk_widget_get_root_window(container));
- GdkDisplay* display = gdk_drawable_get_display(rootWindow);
+ GdkDisplay* display = gdk_window_get_display(rootWindow);
Atom xproperty = gdk_x11_get_xatom_by_name_for_display(display, "_NET_WORKAREA");
Atom retType;
diff --git a/WebCore/platform/gtk/PopupMenuGtk.cpp b/WebCore/platform/gtk/PopupMenuGtk.cpp
index d3e933d..a679734 100644
--- a/WebCore/platform/gtk/PopupMenuGtk.cpp
+++ b/WebCore/platform/gtk/PopupMenuGtk.cpp
@@ -90,7 +90,7 @@ void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index)
#ifdef GTK_API_VERSION_2
gtk_widget_size_request(GTK_WIDGET(m_popup.get()), &requisition);
#else
- gtk_size_request_get_size(GTK_SIZE_REQUEST(m_popup.get()), &requisition, NULL);
+ gtk_widget_get_preferred_size(GTK_WIDGET(m_popup.get()), &requisition, 0);
#endif
gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), std::max(rect.width(), requisition.width), -1);
@@ -107,7 +107,7 @@ void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index)
#ifdef GTK_API_VERSION_2
gtk_widget_get_child_requisition(item, &itemRequisition);
#else
- gtk_size_request_get_size(GTK_SIZE_REQUEST(item), &itemRequisition, NULL);
+ gtk_widget_get_preferred_size(item, &itemRequisition, 0);
#endif
m_menuPosition.setY(m_menuPosition.y() - itemRequisition.height);
diff --git a/WebCore/platform/gtk/RenderThemeGtk.cpp b/WebCore/platform/gtk/RenderThemeGtk.cpp
index 9329179..b2e3fd2 100644
--- a/WebCore/platform/gtk/RenderThemeGtk.cpp
+++ b/WebCore/platform/gtk/RenderThemeGtk.cpp
@@ -192,6 +192,7 @@ RenderThemeGtk::~RenderThemeGtk()
GtkThemeParts* RenderThemeGtk::partsForDrawable(GdkDrawable* drawable) const
{
+#ifdef GTK_API_VERSION_2
// A null drawable represents the default screen colormap.
GdkColormap* colormap = 0;
if (!drawable)
@@ -205,6 +206,10 @@ GtkThemeParts* RenderThemeGtk::partsForDrawable(GdkDrawable* drawable) const
parts->colormap = colormap;
g_hash_table_insert(m_partsTable.get(), colormap, parts);
}
+#else
+ // For GTK+ 3.0 we no longer have to worry about maintaining a set of widgets per-colormap.
+ static GtkThemeParts* parts = g_slice_new0(GtkThemeParts);
+#endif // GTK_API_VERSION_2
return parts;
}
@@ -284,6 +289,7 @@ static void adjustMozillaStyle(const RenderThemeGtk* theme, RenderStyle* style,
style->setPaddingBottom(Length(ypadding + bottom, Fixed));
}
+#ifdef GTK_API_VERSION_2
bool RenderThemeGtk::paintMozillaGtkWidget(GtkThemeWidgetType type, GraphicsContext* context, const IntRect& rect, GtkWidgetState* widgetState, int flags, GtkTextDirection textDirection)
{
// Painting is disabled so just claim to have succeeded
@@ -333,6 +339,18 @@ bool RenderThemeGtk::paintMozillaGtkWidget(GtkThemeWidgetType type, GraphicsCont
return !success;
}
+#else
+bool RenderThemeGtk::paintMozillaGtkWidget(GtkThemeWidgetType type, GraphicsContext* context, const IntRect& rect, GtkWidgetState* widgetState, int flags, GtkTextDirection textDirection)
+{
+ // Painting is disabled so just claim to have succeeded
+ if (context->paintingDisabled())
+ return false;
+
+ // false == success, because of awesome.
+ GdkRectangle paintRect = rect;
+ return moz_gtk_widget_paint(type, context->platformContext(), &paintRect, widgetState, flags, textDirection) != MOZ_GTK_SUCCESS;
+}
+#endif
bool RenderThemeGtk::paintRenderObject(GtkThemeWidgetType type, RenderObject* renderObject, GraphicsContext* context, const IntRect& rect, int flags)
{
@@ -343,7 +361,13 @@ bool RenderThemeGtk::paintRenderObject(GtkThemeWidgetType type, RenderObject* re
GtkWidgetState widgetState;
widgetState.active = isPressed(renderObject);
widgetState.focused = isFocused(renderObject);
- widgetState.inHover = isHovered(renderObject);
+
+ // https://bugs.webkit.org/show_bug.cgi?id=18364
+ // The Mozilla theme drawing code, only paints a button as pressed when it's pressed
+ // while hovered. Until we move away from the Mozila code, work-around the issue by
+ // forcing a pressed button into the hovered state. This ensures that buttons activated
+ // via the keyboard have the proper rendering.
+ widgetState.inHover = isHovered(renderObject) || (type == MOZ_GTK_BUTTON && isPressed(renderObject));
// FIXME: Disabled does not always give the correct appearance for ReadOnly
widgetState.disabled = !isEnabled(renderObject) || isReadOnlyControl(renderObject);
@@ -362,16 +386,6 @@ bool RenderThemeGtk::paintRenderObject(GtkThemeWidgetType type, RenderObject* re
return paintMozillaGtkWidget(type, context, rect, &widgetState, flags, textDirection);
}
-static void setButtonPadding(RenderStyle* style)
-{
- // FIXME: This looks incorrect.
- const int padding = 8;
- style->setPaddingLeft(Length(padding, Fixed));
- style->setPaddingRight(Length(padding, Fixed));
- style->setPaddingTop(Length(padding / 2, Fixed));
- style->setPaddingBottom(Length(padding / 2, Fixed));
-}
-
static void setToggleSize(const RenderThemeGtk* theme, RenderStyle* style, ControlPart appearance)
{
// The width and height are both specified, so we shouldn't change them.
@@ -426,18 +440,9 @@ bool RenderThemeGtk::paintRadio(RenderObject* o, const PaintInfo& i, const IntRe
void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
{
- // FIXME: Is this condition necessary?
- if (style->appearance() == PushButtonPart) {
- style->resetBorder();
- style->setHeight(Length(Auto));
- style->setWhiteSpace(PRE);
- setButtonPadding(style);
- } else {
- // FIXME: This should not be hard-coded.
- style->setMinHeight(Length(14, Fixed));
- style->resetBorderTop();
- style->resetBorderBottom();
- }
+ // Some layout tests check explicitly that buttons ignore line-height.
+ if (style->appearance() == PushButtonPart)
+ style->setLineHeight(RenderStyle::initialLineHeight());
}
bool RenderThemeGtk::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
@@ -499,13 +504,26 @@ void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* s
style->setHeight(Length(size.height(), Fixed));
}
-bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& i, const IntRect& rect)
+static IntRect centerRectVerticallyInParentInputElement(RenderObject* object, const IntRect& rect)
{
- GraphicsContext* context = i.context;
+ IntRect centeredRect(rect);
+ Node* input = object->node()->shadowAncestorNode(); // Get the renderer of <input> element.
+ if (!input->renderer()->isBox())
+ return centeredRect;
- static Image* searchImage = Image::loadPlatformThemeIcon(GTK_STOCK_FIND, rect.width()).releaseRef();
- context->drawImage(searchImage, DeviceColorSpace, rect);
+ // If possible center the y-coordinate of the rect vertically in the parent input element.
+ // We also add one pixel here to ensure that the y coordinate is rounded up for box heights
+ // that are even, which looks in relation to the box text.
+ IntRect inputContentBox = toRenderBox(input->renderer())->absoluteContentBox();
+ centeredRect.setY(inputContentBox.y() + (inputContentBox.height() - centeredRect.height() + 1) / 2);
+ return centeredRect;
+}
+bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* object, const PaintInfo& i, const IntRect& rect)
+{
+ static Image* searchImage = Image::loadPlatformThemeIcon(GTK_STOCK_FIND, rect.width()).releaseRef();
+ IntRect centeredRect(centerRectVerticallyInParentInputElement(object, rect));
+ i.context->drawImage(searchImage, ColorSpaceDeviceRGB, centeredRect);
return false;
}
@@ -520,14 +538,12 @@ void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* select
style->setHeight(Length(size.height(), Fixed));
}
-bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
+bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* object, const PaintInfo& i, const IntRect& rect)
{
- GraphicsContext* context = i.context;
-
// TODO: Brightening up the image on hover is desirable here, I believe.
static Image* cancelImage = Image::loadPlatformThemeIcon(GTK_STOCK_CLEAR, rect.width()).releaseRef();
- context->drawImage(cancelImage, DeviceColorSpace, rect);
-
+ IntRect centeredRect(centerRectVerticallyInParentInputElement(object, rect));
+ i.context->drawImage(cancelImage, ColorSpaceDeviceRGB, centeredRect);
return false;
}
@@ -550,7 +566,7 @@ bool RenderThemeGtk::paintSliderTrack(RenderObject* object, const PaintInfo& inf
if (part == SliderVerticalPart)
gtkPart = MOZ_GTK_SCALE_VERTICAL;
- return paintRenderObject(gtkPart, object, info.context, rect);
+ return paintRenderObject(gtkPart, object, info.context, toRenderBox(object)->absoluteContentBox());
}
void RenderThemeGtk::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
@@ -655,10 +671,46 @@ double RenderThemeGtk::caretBlinkInterval() const
return time / 2000.;
}
-void RenderThemeGtk::systemFont(int, FontDescription&) const
+static double getScreenDPI()
+{
+ // FIXME: Really this should be the widget's screen.
+ GdkScreen* screen = gdk_screen_get_default();
+ if (!screen)
+ return 96; // Default to 96 DPI.
+
+ float dpi = gdk_screen_get_resolution(screen);
+ if (dpi <= 0)
+ return 96;
+ return dpi;
+}
+
+void RenderThemeGtk::systemFont(int, FontDescription& fontDescription) const
{
- // If you remove this notImplemented(), replace it with an comment that explains why.
- notImplemented();
+ GtkSettings* settings = gtk_settings_get_default();
+ if (!settings)
+ return;
+
+ // This will be a font selection string like "Sans 10" so we cannot use it as the family name.
+ GOwnPtr<gchar> fontName;
+ g_object_get(settings, "gtk-font-name", &fontName.outPtr(), NULL);
+
+ PangoFontDescription* pangoDescription = pango_font_description_from_string(fontName.get());
+ if (!pangoDescription)
+ return;
+
+ fontDescription.firstFamily().setFamily(pango_font_description_get_family(pangoDescription));
+
+ int size = pango_font_description_get_size(pangoDescription) / PANGO_SCALE;
+ // If the size of the font is in points, we need to convert it to pixels.
+ if (!pango_font_description_get_size_is_absolute(pangoDescription))
+ size = size * (getScreenDPI() / 72.0);
+
+ fontDescription.setSpecifiedSize(size);
+ fontDescription.setIsAbsoluteSize(true);
+ fontDescription.setGenericFamily(FontDescription::NoFamily);
+ fontDescription.setWeight(FontWeightNormal);
+ fontDescription.setItalic(false);
+ pango_font_description_free(pangoDescription);
}
Color RenderThemeGtk::systemColor(int cssValueId) const
@@ -753,8 +805,8 @@ String RenderThemeGtk::extraMediaControlsStyleSheet()
static inline bool paintMediaButton(GraphicsContext* context, const IntRect& r, Image* image, Color panelColor, int mediaIconSize)
{
- context->fillRect(FloatRect(r), panelColor, DeviceColorSpace);
- context->drawImage(image, DeviceColorSpace,
+ context->fillRect(FloatRect(r), panelColor, ColorSpaceDeviceRGB);
+ context->drawImage(image, ColorSpaceDeviceRGB,
IntRect(r.x() + (r.width() - mediaIconSize) / 2,
r.y() + (r.height() - mediaIconSize) / 2,
mediaIconSize, mediaIconSize));
@@ -800,9 +852,9 @@ bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const PaintInfo& pai
{
GraphicsContext* context = paintInfo.context;
- context->fillRect(FloatRect(r), m_panelColor, DeviceColorSpace);
+ context->fillRect(FloatRect(r), m_panelColor, ColorSpaceDeviceRGB);
context->fillRect(FloatRect(IntRect(r.x(), r.y() + (r.height() - m_mediaSliderHeight) / 2,
- r.width(), m_mediaSliderHeight)), m_sliderColor, DeviceColorSpace);
+ r.width(), m_mediaSliderHeight)), m_sliderColor, ColorSpaceDeviceRGB);
RenderStyle* style = o->style();
HTMLMediaElement* mediaElement = toParentMediaElement(o);
@@ -859,7 +911,7 @@ bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const PaintInfo& pai
bool RenderThemeGtk::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
// Make the thumb nicer with rounded corners.
- paintInfo.context->fillRoundedRect(r, IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), m_sliderThumbColor, DeviceColorSpace);
+ paintInfo.context->fillRoundedRect(r, IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), m_sliderThumbColor, ColorSpaceDeviceRGB);
return false;
}
#endif
diff --git a/WebCore/platform/gtk/ScrollbarThemeGtk.cpp b/WebCore/platform/gtk/ScrollbarThemeGtk.cpp
index 2e942fe..19b897c 100644
--- a/WebCore/platform/gtk/ScrollbarThemeGtk.cpp
+++ b/WebCore/platform/gtk/ScrollbarThemeGtk.cpp
@@ -221,14 +221,8 @@ void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, Scrollbar
void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar)
{
+ // This is unused by the moz_gtk_scrollecd_window_paint.
GtkWidgetState state;
- state.focused = FALSE;
- state.isDefault = FALSE;
- state.canDefault = FALSE;
- state.disabled = FALSE;
- state.active = TRUE;
- state.inHover = FALSE;
-
IntRect fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());
static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->paintMozillaGtkWidget(MOZ_GTK_SCROLLED_WINDOW, context, fullScrollbarRect, &state, 0);
}
@@ -303,7 +297,6 @@ bool ScrollbarThemeGtk::paint(Scrollbar* scrollbar, GraphicsContext* graphicsCon
scrollMask |= ThumbPart;
}
- // Paint the scrollbar background (only used by custom CSS scrollbars).
paintScrollbarBackground(graphicsContext, scrollbar);
if (scrollMask & TrackBGPart)
diff --git a/WebCore/platform/gtk/gtk2drawing.c b/WebCore/platform/gtk/gtk2drawing.c
index fd770d2..2f2edb6 100644
--- a/WebCore/platform/gtk/gtk2drawing.c
+++ b/WebCore/platform/gtk/gtk2drawing.c
@@ -44,6 +44,11 @@
* Adapted from the gtkdrawing.c, and gtk+2.0 source.
*/
+#ifdef GTK_API_VERSION_2
+
+#undef GTK_DISABLE_DEPRECATED
+#undef GDK_DISABLE_DEPRECATED
+
#include <gdk/gdkprivate.h>
#include "gtkdrawing.h"
#include "GtkVersioning.h"
@@ -52,7 +57,6 @@
#define XTHICKNESS(style) (style->xthickness)
#define YTHICKNESS(style) (style->ythickness)
-#define WINDOW_IS_MAPPED(window) ((window) && GDK_IS_WINDOW(window) && gdk_window_is_visible(window))
static GtkThemeParts *gParts = NULL;
static style_prop_t style_prop_func;
@@ -122,26 +126,6 @@ ensure_button_widget()
}
static gint
-ensure_hpaned_widget()
-{
- if (!gParts->hpanedWidget) {
- gParts->hpanedWidget = gtk_hpaned_new();
- setup_widget_prototype(gParts->hpanedWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_vpaned_widget()
-{
- if (!gParts->vpanedWidget) {
- gParts->vpanedWidget = gtk_vpaned_new();
- setup_widget_prototype(gParts->vpanedWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
ensure_toggle_button_widget()
{
if (!gParts->toggleButtonWidget) {
@@ -201,16 +185,6 @@ ensure_scrollbar_widget()
}
static gint
-ensure_spin_widget()
-{
- if (!gParts->spinWidget) {
- gParts->spinWidget = gtk_spin_button_new(NULL, 1, 0);
- setup_widget_prototype(gParts->spinWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
ensure_scale_widget()
{
if (!gParts->hScaleWidget) {
@@ -337,171 +311,6 @@ ensure_combo_box_widgets()
return MOZ_GTK_SUCCESS;
}
-/* We need to have pointers to the inner widgets (entry, button, arrow) of
- * the ComboBoxEntry to get the correct rendering from theme engines which
- * special cases their look. Since the inner layout can change, we ask GTK
- * to NULL our pointers when they are about to become invalid because the
- * corresponding widgets don't exist anymore. It's the role of
- * g_object_add_weak_pointer().
- * Note that if we don't find the inner widgets (which shouldn't happen), we
- * fallback to use generic "non-inner" widgets, and they don't need that kind
- * of weak pointer since they are explicit children of gParts->protoWindow and as
- * such GTK holds a strong reference to them. */
-static void
-moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget,
- gpointer client_data)
-{
- if (GTK_IS_TOGGLE_BUTTON(widget)) {
- gParts->comboBoxEntryButtonWidget = widget;
- g_object_add_weak_pointer(G_OBJECT(widget),
- (gpointer) &gParts->comboBoxEntryButtonWidget);
- } else if (GTK_IS_ENTRY(widget)) {
- gParts->comboBoxEntryTextareaWidget = widget;
- g_object_add_weak_pointer(G_OBJECT(widget),
- (gpointer) &gParts->comboBoxEntryTextareaWidget);
- } else
- return;
- gtk_widget_realize(widget);
- g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
-}
-
-static void
-moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data)
-{
- if (GTK_IS_ARROW(widget)) {
- gParts->comboBoxEntryArrowWidget = widget;
- g_object_add_weak_pointer(G_OBJECT(widget),
- (gpointer) &gParts->comboBoxEntryArrowWidget);
- gtk_widget_realize(widget);
- g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
-}
-
-static gint
-ensure_combo_box_entry_widgets()
-{
- GtkWidget* buttonChild;
-
- if (gParts->comboBoxEntryTextareaWidget &&
- gParts->comboBoxEntryButtonWidget &&
- gParts->comboBoxEntryArrowWidget)
- return MOZ_GTK_SUCCESS;
-
- /* Create a ComboBoxEntry if needed */
- if (!gParts->comboBoxEntryWidget) {
- gParts->comboBoxEntryWidget = gtk_combo_box_entry_new();
- setup_widget_prototype(gParts->comboBoxEntryWidget);
- }
-
- /* Get its inner Entry and Button */
- gtk_container_forall(GTK_CONTAINER(gParts->comboBoxEntryWidget),
- moz_gtk_get_combo_box_entry_inner_widgets,
- NULL);
-
- if (!gParts->comboBoxEntryTextareaWidget) {
- ensure_entry_widget();
- gParts->comboBoxEntryTextareaWidget = gParts->entryWidget;
- }
-
- if (gParts->comboBoxEntryButtonWidget) {
- /* Get the Arrow inside the Button */
- buttonChild = gtk_bin_get_child(GTK_BIN(gParts->comboBoxEntryButtonWidget));
- if (GTK_IS_HBOX(buttonChild)) {
- /* appears-as-list = FALSE, cell-view = TRUE; the button
- * contains an hbox. This hbox is there because ComboBoxEntry
- * inherits from ComboBox which needs to place a cell renderer,
- * a separator, and an arrow in the button when appears-as-list
- * is FALSE. Here the hbox should only contain an arrow, since
- * a ComboBoxEntry doesn't need all those widgets in the
- * button. */
- gtk_container_forall(GTK_CONTAINER(buttonChild),
- moz_gtk_get_combo_box_entry_arrow,
- NULL);
- } else if(GTK_IS_ARROW(buttonChild)) {
- /* appears-as-list = TRUE, or cell-view = FALSE;
- * the button only contains an arrow */
- gParts->comboBoxEntryArrowWidget = buttonChild;
- g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
- &gParts->comboBoxEntryArrowWidget);
- gtk_widget_realize(gParts->comboBoxEntryArrowWidget);
- g_object_set_data(G_OBJECT(gParts->comboBoxEntryArrowWidget),
- "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
- } else {
- /* Shouldn't be reached with current internal gtk implementation;
- * we use a generic toggle button as last resort fallback to avoid
- * crashing. */
- ensure_toggle_button_widget();
- gParts->comboBoxEntryButtonWidget = gParts->toggleButtonWidget;
- }
-
- if (!gParts->comboBoxEntryArrowWidget) {
- /* Shouldn't be reached with current internal gtk implementation;
- * we gParts->buttonArrowWidget as last resort fallback to avoid
- * crashing. */
- ensure_button_arrow_widget();
- gParts->comboBoxEntryArrowWidget = gParts->buttonArrowWidget;
- }
-
- return MOZ_GTK_SUCCESS;
-}
-
-
-static gint
-ensure_handlebox_widget()
-{
- if (!gParts->handleBoxWidget) {
- gParts->handleBoxWidget = gtk_handle_box_new();
- setup_widget_prototype(gParts->handleBoxWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_toolbar_widget()
-{
- if (!gParts->toolbarWidget) {
- ensure_handlebox_widget();
- gParts->toolbarWidget = gtk_toolbar_new();
- gtk_container_add(GTK_CONTAINER(gParts->handleBoxWidget), gParts->toolbarWidget);
- gtk_widget_realize(gParts->toolbarWidget);
- g_object_set_data(G_OBJECT(gParts->toolbarWidget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_toolbar_separator_widget()
-{
- if (!gParts->toolbarSeparatorWidget) {
- ensure_toolbar_widget();
- gParts->toolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new());
- setup_widget_prototype(gParts->toolbarSeparatorWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_tooltip_widget()
-{
- if (!gParts->tooltipWidget) {
- gParts->tooltipWidget = gtk_window_new(GTK_WINDOW_POPUP);
- gtk_widget_realize(gParts->tooltipWidget);
- moz_gtk_set_widget_name(gParts->tooltipWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_tab_widget()
-{
- if (!gParts->tabWidget) {
- gParts->tabWidget = gtk_notebook_new();
- setup_widget_prototype(gParts->tabWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
static gint
ensure_progress_widget()
{
@@ -513,200 +322,6 @@ ensure_progress_widget()
}
static gint
-ensure_statusbar_widget()
-{
- if (!gParts->statusbarWidget) {
- gParts->statusbarWidget = gtk_statusbar_new();
- setup_widget_prototype(gParts->statusbarWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_frame_widget()
-{
- if (!gParts->frameWidget) {
- ensure_statusbar_widget();
- gParts->frameWidget = gtk_frame_new(NULL);
- gtk_container_add(GTK_CONTAINER(gParts->statusbarWidget), gParts->frameWidget);
- gtk_widget_realize(gParts->frameWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_menu_bar_widget()
-{
- if (!gParts->menuBarWidget) {
- gParts->menuBarWidget = gtk_menu_bar_new();
- setup_widget_prototype(gParts->menuBarWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_menu_bar_item_widget()
-{
- if (!gParts->menuBarItemWidget) {
- ensure_menu_bar_widget();
- gParts->menuBarItemWidget = gtk_menu_item_new();
- gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuBarWidget),
- gParts->menuBarItemWidget);
- gtk_widget_realize(gParts->menuBarItemWidget);
- g_object_set_data(G_OBJECT(gParts->menuBarItemWidget),
- "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_menu_popup_widget()
-{
- if (!gParts->menuPopupWidget) {
- ensure_menu_bar_item_widget();
- gParts->menuPopupWidget = gtk_menu_new();
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(gParts->menuBarItemWidget),
- gParts->menuPopupWidget);
- gtk_widget_realize(gParts->menuPopupWidget);
- g_object_set_data(G_OBJECT(gParts->menuPopupWidget),
- "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_menu_item_widget()
-{
- if (!gParts->menuItemWidget) {
- ensure_menu_popup_widget();
- gParts->menuItemWidget = gtk_menu_item_new_with_label("M");
- gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget),
- gParts->menuItemWidget);
- gtk_widget_realize(gParts->menuItemWidget);
- g_object_set_data(G_OBJECT(gParts->menuItemWidget),
- "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_image_menu_item_widget()
-{
- if (!gParts->imageMenuItemWidget) {
- ensure_menu_popup_widget();
- gParts->imageMenuItemWidget = gtk_image_menu_item_new();
- gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget),
- gParts->imageMenuItemWidget);
- gtk_widget_realize(gParts->imageMenuItemWidget);
- g_object_set_data(G_OBJECT(gParts->imageMenuItemWidget),
- "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_menu_separator_widget()
-{
- if (!gParts->menuSeparatorWidget) {
- ensure_menu_popup_widget();
- gParts->menuSeparatorWidget = gtk_separator_menu_item_new();
- gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget),
- gParts->menuSeparatorWidget);
- gtk_widget_realize(gParts->menuSeparatorWidget);
- g_object_set_data(G_OBJECT(gParts->menuSeparatorWidget),
- "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_check_menu_item_widget()
-{
- if (!gParts->checkMenuItemWidget) {
- ensure_menu_popup_widget();
- gParts->checkMenuItemWidget = gtk_check_menu_item_new_with_label("M");
- gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget),
- gParts->checkMenuItemWidget);
- gtk_widget_realize(gParts->checkMenuItemWidget);
- g_object_set_data(G_OBJECT(gParts->checkMenuItemWidget),
- "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_tree_view_widget()
-{
- if (!gParts->treeViewWidget) {
- gParts->treeViewWidget = gtk_tree_view_new();
- setup_widget_prototype(gParts->treeViewWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_tree_header_cell_widget()
-{
- if(!gParts->treeHeaderCellWidget) {
- /*
- * Some GTK engines paint the first and last cell
- * of a TreeView header with a highlight.
- * Since we do not know where our widget will be relative
- * to the other buttons in the TreeView header, we must
- * paint it as a button that is between two others,
- * thus ensuring it is neither the first or last button
- * in the header.
- * GTK doesn't give us a way to do this explicitly,
- * so we must paint with a button that is between two
- * others.
- */
-
- GtkTreeViewColumn* firstTreeViewColumn;
- GtkTreeViewColumn* lastTreeViewColumn;
-
- ensure_tree_view_widget();
-
- /* Create and append our three columns */
- firstTreeViewColumn = gtk_tree_view_column_new();
- gtk_tree_view_column_set_title(firstTreeViewColumn, "M");
- gtk_tree_view_append_column(GTK_TREE_VIEW(gParts->treeViewWidget), firstTreeViewColumn);
-
- gParts->middleTreeViewColumn = gtk_tree_view_column_new();
- gtk_tree_view_column_set_title(gParts->middleTreeViewColumn, "M");
- gtk_tree_view_append_column(GTK_TREE_VIEW(gParts->treeViewWidget),
- gParts->middleTreeViewColumn);
-
- lastTreeViewColumn = gtk_tree_view_column_new();
- gtk_tree_view_column_set_title(lastTreeViewColumn, "M");
- gtk_tree_view_append_column(GTK_TREE_VIEW(gParts->treeViewWidget), lastTreeViewColumn);
-
-#ifdef GTK_API_VERSION_2
- /* Use the middle column's header for our button */
- gParts->treeHeaderCellWidget = gParts->middleTreeViewColumn->button;
- gParts->treeHeaderSortArrowWidget = gParts->middleTreeViewColumn->arrow;
-#else
- gParts->treeHeaderCellWidget = gtk_button_new();
- gParts->treeHeaderSortArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
-#endif
- g_object_set_data(G_OBJECT(gParts->treeHeaderCellWidget),
- "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- g_object_set_data(G_OBJECT(gParts->treeHeaderSortArrowWidget),
- "transparent-bg-hint", GINT_TO_POINTER(TRUE));
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_expander_widget()
-{
- if (!gParts->expanderWidget) {
- gParts->expanderWidget = gtk_expander_new("M");
- setup_widget_prototype(gParts->expanderWidget);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
ensure_scrolled_window_widget()
{
if (!gParts->scrolledWindowWidget) {
@@ -729,7 +344,6 @@ ConvertGtkState(GtkWidgetState* state)
return GTK_STATE_NORMAL;
}
-#ifdef GTK_API_VERSION_2
static gint
TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin)
{
@@ -739,12 +353,10 @@ TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin)
gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin);
return MOZ_GTK_SUCCESS;
}
-#endif
static gint
TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin)
{
-#ifdef GTK_API_VERSION_2
TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin);
TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin);
TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin);
@@ -754,7 +366,6 @@ TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin)
TSOffsetStyleGCArray(style->base_gc, xorigin, yorigin);
gdk_gc_set_ts_origin(style->black_gc, xorigin, yorigin);
gdk_gc_set_ts_origin(style->white_gc, xorigin, yorigin);
-#endif
return MOZ_GTK_SUCCESS;
}
@@ -774,28 +385,18 @@ moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad);
- if (WINDOW_IS_MAPPED(drawable)) {
- gdk_window_set_back_pixmap(drawable, NULL, TRUE);
- gdk_window_clear_area(drawable, cliprect->x, cliprect->y,
- cliprect->width, cliprect->height);
- }
-
gtk_widget_set_state(widget, button_state);
gtk_widget_set_direction(widget, direction);
-#ifdef GTK_API_VERSION_2
if (state->isDefault)
GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_DEFAULT);
-#endif
gtk_button_set_relief(GTK_BUTTON(widget), relief);
/* Some theme engines love to cause us pain in that gtk_paint_focus is a
no-op on buttons and button-like widgets. They only listen to this flag. */
-#ifdef GTK_API_VERSION_2
if (state->focused && !state->disabled)
GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
-#endif
if (!interior_focus && state->focused) {
x += focus_width + focus_pad;
@@ -842,10 +443,8 @@ moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
widget, "button", x, y, width, height);
}
-#ifdef GTK_API_VERSION_2
GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_DEFAULT);
GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
-#endif
return MOZ_GTK_SUCCESS;
}
@@ -912,19 +511,6 @@ moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus,
}
gint
-moz_gtk_splitter_get_metrics(gint orientation, gint* size)
-{
- if (orientation == GTK_ORIENTATION_HORIZONTAL) {
- ensure_hpaned_widget();
- gtk_widget_style_get(gParts->hpanedWidget, "handle_size", size, NULL);
- } else {
- ensure_vpaned_widget();
- gtk_widget_style_get(gParts->vpanedWidget, "handle_size", size, NULL);
- }
- return MOZ_GTK_SUCCESS;
-}
-
-gint
moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border)
{
static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
@@ -1098,8 +684,6 @@ static gint
moz_gtk_scrolled_window_paint(GdkDrawable* drawable, GdkRectangle* rect,
GdkRectangle* cliprect, GtkWidgetState* state)
{
- GtkStateType state_type = ConvertGtkState(state);
- GtkShadowType shadow_type = (state->active) ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
GtkStyle* style;
GtkAllocation allocation;
GtkWidget* widget;
@@ -1116,9 +700,9 @@ moz_gtk_scrolled_window_paint(GdkDrawable* drawable, GdkRectangle* rect,
style = gtk_widget_get_style(widget);
TSOffsetStyleGCs(style, rect->x - 1, rect->y - 1);
- gtk_paint_box(style, drawable, state_type, shadow_type, cliprect,
- widget, "scrolled_window", rect->x - 1, rect->y - 1,
- rect->width + 2, rect->height + 2);
+ gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ cliprect, gParts->scrolledWindowWidget, "scrolled_window",
+ rect->x, rect->y, rect->width, rect->height);
return MOZ_GTK_SUCCESS;
}
@@ -1265,9 +849,7 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
GtkStyle* style;
GtkScrollbar *scrollbar;
GtkAdjustment *adj;
-#ifdef GTK_API_VERSION_2
gboolean activate_slider;
-#endif
ensure_scrollbar_widget();
@@ -1319,7 +901,6 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
style = gtk_widget_get_style(GTK_WIDGET(scrollbar));
-#ifdef GTK_API_VERSION_2
gtk_widget_style_get(GTK_WIDGET(scrollbar), "activate-slider",
&activate_slider, NULL);
@@ -1327,7 +908,6 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
shadow_type = GTK_SHADOW_IN;
state_type = GTK_STATE_ACTIVE;
}
-#endif
TSOffsetStyleGCs(style, rect->x, rect->y);
@@ -1341,59 +921,6 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
}
static gint
-moz_gtk_spin_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GtkTextDirection direction)
-{
- GtkStyle* style;
-
- ensure_spin_widget();
- gtk_widget_set_direction(gParts->spinWidget, direction);
- style = gtk_widget_get_style(gParts->spinWidget);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL,
- gParts->spinWidget, "spinbutton",
- rect->x, rect->y, rect->width, rect->height);
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_spin_updown_paint(GdkDrawable* drawable, GdkRectangle* rect,
- gboolean isDown, GtkWidgetState* state,
- GtkTextDirection direction)
-{
- GdkRectangle arrow_rect;
- GtkStateType state_type = ConvertGtkState(state);
- GtkShadowType shadow_type = state_type == GTK_STATE_ACTIVE ?
- GTK_SHADOW_IN : GTK_SHADOW_OUT;
- GtkStyle* style;
-
- ensure_spin_widget();
- style = gtk_widget_get_style(gParts->spinWidget);
- gtk_widget_set_direction(gParts->spinWidget, direction);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_paint_box(style, drawable, state_type, shadow_type, NULL, gParts->spinWidget,
- isDown ? "spinbutton_down" : "spinbutton_up",
- rect->x, rect->y, rect->width, rect->height);
-
- /* hard code these values */
- arrow_rect.width = 6;
- arrow_rect.height = 6;
- arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
- arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
- arrow_rect.y += isDown ? -1 : 1;
-
- gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL,
- gParts->spinWidget, "spinbutton",
- isDown ? GTK_ARROW_DOWN : GTK_ARROW_UP, TRUE,
- arrow_rect.x, arrow_rect.y,
- arrow_rect.width, arrow_rect.height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
moz_gtk_scale_paint(GdkDrawable* drawable, GdkRectangle* rect,
GdkRectangle* cliprect, GtkWidgetState* state,
GtkOrientation flags, GtkTextDirection direction)
@@ -1471,76 +998,6 @@ moz_gtk_scale_thumb_paint(GdkDrawable* drawable, GdkRectangle* rect,
}
static gint
-moz_gtk_gripper_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- GtkTextDirection direction)
-{
- GtkStateType state_type = ConvertGtkState(state);
- GtkShadowType shadow_type;
- GtkStyle* style;
-
- ensure_handlebox_widget();
- gtk_widget_set_direction(gParts->handleBoxWidget, direction);
-
- style = gtk_widget_get_style(gParts->handleBoxWidget);
- shadow_type = gtk_handle_box_get_shadow_type(GTK_HANDLE_BOX(gParts->handleBoxWidget));
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_paint_box(style, drawable, state_type, shadow_type, cliprect,
- gParts->handleBoxWidget, "handlebox_bin", rect->x, rect->y,
- rect->width, rect->height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_hpaned_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state)
-{
- GtkStateType hpaned_state = ConvertGtkState(state);
-
- ensure_hpaned_widget();
- gtk_paint_handle(gtk_widget_get_style(gParts->hpanedWidget), drawable, hpaned_state,
- GTK_SHADOW_NONE, cliprect, gParts->hpanedWidget, "paned",
- rect->x, rect->y, rect->width, rect->height,
- GTK_ORIENTATION_VERTICAL);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_vpaned_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state)
-{
- GtkStateType vpaned_state = ConvertGtkState(state);
-
- ensure_vpaned_widget();
- gtk_paint_handle(gtk_widget_get_style(gParts->vpanedWidget), drawable, vpaned_state,
- GTK_SHADOW_NONE, cliprect, gParts->vpanedWidget, "paned",
- rect->x, rect->y, rect->width, rect->height,
- GTK_ORIENTATION_HORIZONTAL);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_caret_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTextDirection direction)
-{
- GdkRectangle location = *rect;
- if (direction == GTK_TEXT_DIR_RTL) {
- /* gtk_draw_insertion_cursor ignores location.width */
- location.x = rect->x + rect->width;
- }
-
- ensure_entry_widget();
- gtk_draw_insertion_cursor(gParts->entryWidget, drawable, cliprect,
- &location, TRUE, direction, FALSE);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect,
GdkRectangle* cliprect, GtkWidgetState* state,
GtkWidget* widget, GtkTextDirection direction)
@@ -1583,17 +1040,8 @@ moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect,
if (theme_honors_transparency) {
g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
} else {
-#ifndef GTK_API_VERSION_2
- cairo_t* cr = gdk_cairo_create(drawable);
- gdk_cairo_set_source_color(cr, (const GdkColor*)&style->base[bg_state]);
- cairo_pattern_set_extend (cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
- gdk_cairo_rectangle(cr, cliprect);
- cairo_fill(cr);
- cairo_destroy(cr);
-#else
gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE,
cliprect->x, cliprect->y, cliprect->width, cliprect->height);
-#endif
g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(FALSE));
}
@@ -1620,9 +1068,7 @@ moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect,
if (state->focused && !state->disabled) {
/* This will get us the lit borders that focused textboxes enjoy on
* some themes. */
-#ifdef GTK_API_VERSION_2
GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
-#endif
if (!interior_focus) {
/* Indent the border a little bit if we have exterior focus
@@ -1646,152 +1092,12 @@ moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect,
/* Now unset the focus flag. We don't want other entries to look
* like they're focused too! */
-#ifdef GTK_API_VERSION_2
GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
-#endif
}
return MOZ_GTK_SUCCESS;
}
-static gint
-moz_gtk_treeview_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- GtkTextDirection direction)
-{
- gint xthickness, ythickness;
-
- GtkStyle *style, *treeview_style;
- GtkStateType state_type;
-
- ensure_tree_view_widget();
- ensure_scrolled_window_widget();
-
- gtk_widget_set_direction(gParts->treeViewWidget, direction);
- gtk_widget_set_direction(gParts->scrolledWindowWidget, direction);
-
- /* only handle disabled and normal states, otherwise the whole background
- * area will be painted differently with other states */
- state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
-
- /* In GTK the treeview sets the background of the window
- * which contains the cells to the treeview base color.
- * If we don't set it here the background color will not be correct.*/
- gtk_widget_modify_bg(gParts->treeViewWidget, state_type,
- &gtk_widget_get_style(gParts->treeViewWidget)->base[state_type]);
-
- style = gtk_widget_get_style(gParts->scrolledWindowWidget);
- xthickness = XTHICKNESS(style);
- ythickness = YTHICKNESS(style);
-
- treeview_style = gtk_widget_get_style(gParts->treeViewWidget);
- TSOffsetStyleGCs(treeview_style, rect->x, rect->y);
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- gtk_paint_flat_box(treeview_style, drawable, state_type,
- GTK_SHADOW_NONE, cliprect, gParts->treeViewWidget, "treeview",
- rect->x + xthickness, rect->y + ythickness,
- rect->width - 2 * xthickness,
- rect->height - 2 * ythickness);
-
- gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
- cliprect, gParts->scrolledWindowWidget, "scrolled_window",
- rect->x, rect->y, rect->width, rect->height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_tree_header_cell_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- gboolean isSorted, GtkTextDirection direction)
-{
- gtk_tree_view_column_set_sort_indicator(gParts->middleTreeViewColumn,
- isSorted);
-
- moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL,
- gParts->treeHeaderCellWidget, direction);
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_tree_header_sort_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect,
- GtkWidgetState* state, GtkArrowType flags,
- GtkTextDirection direction)
-{
- GdkRectangle arrow_rect;
- GtkStateType state_type = ConvertGtkState(state);
- GtkShadowType shadow_type = GTK_SHADOW_IN;
- GtkArrowType arrow_type = flags;
- GtkStyle* style;
-
- ensure_tree_header_cell_widget();
- gtk_widget_set_direction(gParts->treeHeaderSortArrowWidget, direction);
-
- /* hard code these values */
- arrow_rect.width = 11;
- arrow_rect.height = 11;
- arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
- arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
-
- style = gtk_widget_get_style(gParts->treeHeaderSortArrowWidget);
- TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y);
-
- gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
- gParts->treeHeaderSortArrowWidget, "arrow", arrow_type, TRUE,
- arrow_rect.x, arrow_rect.y,
- arrow_rect.width, arrow_rect.height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_treeview_expander_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- GtkExpanderStyle expander_state,
- GtkTextDirection direction)
-{
- GtkStyle *style;
- GtkStateType state_type;
-
- ensure_tree_view_widget();
- gtk_widget_set_direction(gParts->treeViewWidget, direction);
-
- style = gtk_widget_get_style(gParts->treeViewWidget);
-
- /* Because the frame we get is of the entire treeview, we can't get the precise
- * event state of one expander, thus rendering hover and active feedback useless. */
- state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_paint_expander(style, drawable, state_type, cliprect, gParts->treeViewWidget, "treeview",
- rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_expander_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- GtkExpanderStyle expander_state,
- GtkTextDirection direction)
-{
- GtkStyle *style;
- GtkStateType state_type = ConvertGtkState(state);
-
- ensure_expander_widget();
- gtk_widget_set_direction(gParts->expanderWidget, direction);
-
- style = gtk_widget_get_style(gParts->expanderWidget);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_paint_expander(style, drawable, state_type, cliprect, gParts->expanderWidget, "expander",
- rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state);
-
- return MOZ_GTK_SUCCESS;
-}
-
static gint
moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect,
GdkRectangle* cliprect, GtkWidgetState* state,
@@ -1816,11 +1122,7 @@ moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect,
rect, &arrow_rect, direction, ishtml);
/* Now arrow_rect contains the inner rect ; we want to correct the width
* to what the arrow needs (see gtk_combo_box_size_allocate) */
-#ifdef GTK_API_VERSION_2
gtk_widget_size_request(gParts->comboBoxArrowWidget, &arrow_req);
-#else
- gtk_size_request_get_size(GTK_SIZE_REQUEST(gParts->comboBoxArrowWidget), &arrow_req, NULL);
-#endif
if (direction == GTK_TEXT_DIR_LTR)
arrow_rect.x += arrow_rect.width - arrow_req.width;
arrow_rect.width = arrow_req.width;
@@ -1878,323 +1180,6 @@ moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect,
}
static gint
-moz_gtk_downarrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state)
-{
- GtkStyle* style;
- GtkStateType state_type = ConvertGtkState(state);
- GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
- GdkRectangle arrow_rect;
-
- ensure_button_arrow_widget();
- style = gtk_widget_get_style(gParts->buttonArrowWidget);
-
- calculate_arrow_rect(gParts->buttonArrowWidget, rect, &arrow_rect,
- GTK_TEXT_DIR_LTR);
-
- TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y);
- gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
- gParts->buttonArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
- arrow_rect.x, arrow_rect.y, arrow_rect.width, arrow_rect.height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_combo_box_entry_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect,
- GtkWidgetState* state,
- gboolean input_focus,
- GtkTextDirection direction)
-{
- gint x_displacement, y_displacement;
- GdkRectangle arrow_rect, real_arrow_rect;
- GtkStateType state_type = ConvertGtkState(state);
- GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
- GtkStyle* style;
-
- ensure_combo_box_entry_widgets();
-
- if (input_focus) {
- /* Some themes draw a complementary focus ring for the dropdown button
- * when the dropdown entry has focus */
-#ifdef GTK_API_VERSION_2
- GTK_WIDGET_SET_FLAGS(gParts->comboBoxEntryTextareaWidget, GTK_HAS_FOCUS);
-#endif
- }
-
- moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL,
- gParts->comboBoxEntryButtonWidget, direction);
-
-#ifdef GTK_API_VERSION_2
- if (input_focus)
- GTK_WIDGET_UNSET_FLAGS(gParts->comboBoxEntryTextareaWidget, GTK_HAS_FOCUS);
-#endif
-
- calculate_button_inner_rect(gParts->comboBoxEntryButtonWidget,
- rect, &arrow_rect, direction, FALSE);
- if (state_type == GTK_STATE_ACTIVE) {
- gtk_widget_style_get(gParts->comboBoxEntryButtonWidget,
- "child-displacement-x", &x_displacement,
- "child-displacement-y", &y_displacement,
- NULL);
- arrow_rect.x += x_displacement;
- arrow_rect.y += y_displacement;
- }
-
- calculate_arrow_rect(gParts->comboBoxEntryArrowWidget,
- &arrow_rect, &real_arrow_rect, direction);
-
- style = gtk_widget_get_style(gParts->comboBoxEntryArrowWidget);
- TSOffsetStyleGCs(style, real_arrow_rect.x, real_arrow_rect.y);
-
- gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
- gParts->comboBoxEntryArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
- real_arrow_rect.x, real_arrow_rect.y,
- real_arrow_rect.width, real_arrow_rect.height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_container_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- gboolean isradio, GtkTextDirection direction)
-{
- GtkStateType state_type = ConvertGtkState(state);
- GtkStyle* style;
- GtkWidget *widget;
- gboolean interior_focus;
- gint focus_width, focus_pad;
-
- if (isradio) {
- ensure_radiobutton_widget();
- widget = gParts->radiobuttonWidget;
- } else {
- ensure_checkbox_widget();
- widget = gParts->checkboxWidget;
- }
- gtk_widget_set_direction(widget, direction);
-
- style = gtk_widget_get_style(widget);
- moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width,
- &focus_pad);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- /* The detail argument for the gtk_paint_* calls below are "checkbutton"
- even for radio buttons, to match what gtk does. */
-
- /* this is for drawing a prelight box */
- if (state_type == GTK_STATE_PRELIGHT || state_type == GTK_STATE_ACTIVE) {
- gtk_paint_flat_box(style, drawable, GTK_STATE_PRELIGHT,
- GTK_SHADOW_ETCHED_OUT, cliprect, widget,
- "checkbutton",
- rect->x, rect->y, rect->width, rect->height);
- }
-
- if (state_type != GTK_STATE_NORMAL && state_type != GTK_STATE_PRELIGHT)
- state_type = GTK_STATE_NORMAL;
-
- if (state->focused && !interior_focus) {
- gtk_paint_focus(style, drawable, state_type, cliprect, widget,
- "checkbutton",
- rect->x, rect->y, rect->width, rect->height);
- }
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_toggle_label_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- gboolean isradio, GtkTextDirection direction)
-{
- GtkStateType state_type;
- GtkStyle *style;
- GtkWidget *widget;
- gboolean interior_focus;
-
- if (!state->focused)
- return MOZ_GTK_SUCCESS;
-
- if (isradio) {
- ensure_radiobutton_widget();
- widget = gParts->radiobuttonWidget;
- } else {
- ensure_checkbox_widget();
- widget = gParts->checkboxWidget;
- }
- gtk_widget_set_direction(widget, direction);
-
- gtk_widget_style_get(widget, "interior-focus", &interior_focus, NULL);
- if (!interior_focus)
- return MOZ_GTK_SUCCESS;
-
- state_type = ConvertGtkState(state);
-
- style = gtk_widget_get_style(widget);
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- /* Always "checkbutton" to match gtkcheckbutton.c */
- gtk_paint_focus(style, drawable, state_type, cliprect, widget,
- "checkbutton",
- rect->x, rect->y, rect->width, rect->height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_toolbar_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTextDirection direction)
-{
- GtkStyle* style;
- GtkShadowType shadow_type;
-
- ensure_toolbar_widget();
- gtk_widget_set_direction(gParts->toolbarWidget, direction);
-
- style = gtk_widget_get_style(gParts->toolbarWidget);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- gtk_style_apply_default_background(style, drawable, TRUE,
- GTK_STATE_NORMAL,
- cliprect, rect->x, rect->y,
- rect->width, rect->height);
-
- gtk_widget_style_get(gParts->toolbarWidget, "shadow-type", &shadow_type, NULL);
-
- gtk_paint_box (style, drawable, GTK_STATE_NORMAL, shadow_type,
- cliprect, gParts->toolbarWidget, "toolbar",
- rect->x, rect->y, rect->width, rect->height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect,
- GtkTextDirection direction)
-{
- GtkStyle* style;
- gint separator_width;
- gint paint_width;
- gboolean wide_separators;
-
- /* Defined as constants in GTK+ 2.10.14 */
- const double start_fraction = 0.2;
- const double end_fraction = 0.8;
-
- ensure_toolbar_separator_widget();
- gtk_widget_set_direction(gParts->toolbarSeparatorWidget, direction);
-
- style = gtk_widget_get_style(gParts->toolbarSeparatorWidget);
-
- gtk_widget_style_get(gParts->toolbarWidget,
- "wide-separators", &wide_separators,
- "separator-width", &separator_width,
- NULL);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- if (wide_separators) {
- if (separator_width > rect->width)
- separator_width = rect->width;
-
- gtk_paint_box(style, drawable,
- GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
- cliprect, gParts->toolbarWidget, "vseparator",
- rect->x + (rect->width - separator_width) / 2,
- rect->y + rect->height * start_fraction,
- separator_width,
- rect->height * (end_fraction - start_fraction));
-
- } else {
- paint_width = style->xthickness;
-
- if (paint_width > rect->width)
- paint_width = rect->width;
-
- gtk_paint_vline(style, drawable,
- GTK_STATE_NORMAL, cliprect, gParts->toolbarSeparatorWidget,
- "toolbar",
- rect->y + rect->height * start_fraction,
- rect->y + rect->height * end_fraction,
- rect->x + (rect->width - paint_width) / 2);
- }
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_tooltip_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTextDirection direction)
-{
- GtkStyle* style;
-
- ensure_tooltip_widget();
- gtk_widget_set_direction(gParts->tooltipWidget, direction);
-
- style = gtk_rc_get_style_by_paths(gtk_settings_get_default(),
- "gtk-tooltips", "GtkWindow",
- GTK_TYPE_WINDOW);
-
- style = gtk_style_attach(style, gtk_widget_get_window(gParts->tooltipWidget));
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_paint_flat_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
- cliprect, gParts->tooltipWidget, "tooltip",
- rect->x, rect->y, rect->width, rect->height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_resizer_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- GtkTextDirection direction)
-{
- GtkStyle* style;
- GtkStateType state_type = ConvertGtkState(state);
-
- ensure_window_widget();
- gtk_widget_set_direction(gParts->protoWindow, direction);
-
- style = gtk_widget_get_style(gParts->protoWindow);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- gtk_paint_resize_grip(style, drawable, state_type, cliprect, gParts->protoWindow,
- NULL, (direction == GTK_TEXT_DIR_LTR) ?
- GDK_WINDOW_EDGE_SOUTH_EAST :
- GDK_WINDOW_EDGE_SOUTH_WEST,
- rect->x, rect->y, rect->width, rect->height);
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_frame_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTextDirection direction)
-{
- GtkStyle* style;
- GtkShadowType shadow_type;
-
- ensure_frame_widget();
- gtk_widget_set_direction(gParts->frameWidget, direction);
-
- style = gtk_widget_get_style(gParts->frameWidget);
-
- gtk_widget_style_get(gParts->statusbarWidget, "shadow-type", &shadow_type, NULL);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, shadow_type,
- cliprect, gParts->frameWidget, "frame", rect->x, rect->y,
- rect->width, rect->height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
moz_gtk_progressbar_paint(GdkDrawable* drawable, GdkRectangle* rect,
GdkRectangle* cliprect, GtkTextDirection direction)
{
@@ -2233,438 +1218,6 @@ moz_gtk_progress_chunk_paint(GdkDrawable* drawable, GdkRectangle* rect,
}
gint
-moz_gtk_get_tab_thickness(void)
-{
- GtkStyle* style;
-
- ensure_tab_widget();
- style = gtk_widget_get_style(gParts->tabWidget);
- if (YTHICKNESS(style) < 2)
- return 2; /* some themes don't set ythickness correctly */
-
- return YTHICKNESS(style);
-}
-
-static gint
-moz_gtk_tab_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTabFlags flags,
- GtkTextDirection direction)
-{
- /* When the tab isn't selected, we just draw a notebook extension.
- * When it is selected, we overwrite the adjacent border of the tabpanel
- * touching the tab with a pierced border (called "the gap") to make the
- * tab appear physically attached to the tabpanel; see details below. */
-
- GtkStyle* style;
-
- ensure_tab_widget();
- gtk_widget_set_direction(gParts->tabWidget, direction);
-
- style = gtk_widget_get_style(gParts->tabWidget);
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- if ((flags & MOZ_GTK_TAB_SELECTED) == 0) {
- /* Only draw the tab */
- gtk_paint_extension(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_OUT,
- cliprect, gParts->tabWidget, "tab",
- rect->x, rect->y, rect->width, rect->height,
- (flags & MOZ_GTK_TAB_BOTTOM) ?
- GTK_POS_TOP : GTK_POS_BOTTOM );
- } else {
- /* Draw the tab and the gap
- * We want the gap to be positionned exactly on the tabpanel top
- * border; since tabbox.css may set a negative margin so that the tab
- * frame rect already overlaps the tabpanel frame rect, we need to take
- * that into account when drawing. To that effect, nsNativeThemeGTK
- * passes us this negative margin (bmargin in the graphic below) in the
- * lowest bits of |flags|. We use it to set gap_voffset, the distance
- * between the top of the gap and the bottom of the tab (resp. the
- * bottom of the gap and the top of the tab when we draw a bottom tab),
- * while ensuring that the gap always touches the border of the tab,
- * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results
- * with big negative or positive margins.
- * Here is a graphical explanation in the case of top tabs:
- * ___________________________
- * / \
- * | T A B |
- * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel
- * : ^ bmargin : ^
- * : | (-negative margin, : |
- * bottom : v passed in flags) : | gap_height
- * of -> :.............................: | (the size of the
- * the tab . part of the gap . | tabpanel top border)
- * . outside of the tab . v
- * ----------------------------------------------
- *
- * To draw the gap, we use gtk_paint_box_gap(), see comment in
- * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall,
- * which should suffice to ensure that the only visible border is the
- * pierced one. If the tab is in the middle, we make the box_gap begin
- * a bit to the left of the tab and end a bit to the right, adjusting
- * the gap position so it still is under the tab, because we want the
- * rendering of a gap in the middle of a tabpanel. This is the role of
- * the gints gap_{l,r}_offset. On the contrary, if the tab is the
- * first, we align the start border of the box_gap with the start
- * border of the tab (left if LTR, right if RTL), by setting the
- * appropriate offset to 0.*/
- gint gap_loffset, gap_roffset, gap_voffset, gap_height;
-
- /* Get height needed by the gap */
- gap_height = moz_gtk_get_tab_thickness();
-
- /* Extract gap_voffset from the first bits of flags */
- gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
- if (gap_voffset > gap_height)
- gap_voffset = gap_height;
-
- /* Set gap_{l,r}_offset to appropriate values */
- gap_loffset = gap_roffset = 20; /* should be enough */
- if (flags & MOZ_GTK_TAB_FIRST) {
- if (direction == GTK_TEXT_DIR_RTL)
- gap_roffset = 0;
- else
- gap_loffset = 0;
- }
-
- if (flags & MOZ_GTK_TAB_BOTTOM) {
- /* Enlarge the cliprect to have room for the full gap height */
- cliprect->height += gap_height - gap_voffset;
- cliprect->y -= gap_height - gap_voffset;
-
- /* Draw the tab */
- gtk_paint_extension(style, drawable, GTK_STATE_NORMAL,
- GTK_SHADOW_OUT, cliprect, gParts->tabWidget, "tab",
- rect->x, rect->y + gap_voffset, rect->width,
- rect->height - gap_voffset, GTK_POS_TOP);
-
- /* Draw the gap; erase with background color before painting in
- * case theme does not */
- gtk_style_apply_default_background(style, drawable, TRUE,
- GTK_STATE_NORMAL, cliprect,
- rect->x,
- rect->y + gap_voffset
- - gap_height,
- rect->width, gap_height);
- gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
- cliprect, gParts->tabWidget, "notebook",
- rect->x - gap_loffset,
- rect->y + gap_voffset - 3 * gap_height,
- rect->width + gap_loffset + gap_roffset,
- 3 * gap_height, GTK_POS_BOTTOM,
- gap_loffset, rect->width);
- } else {
- /* Enlarge the cliprect to have room for the full gap height */
- cliprect->height += gap_height - gap_voffset;
-
- /* Draw the tab */
- gtk_paint_extension(style, drawable, GTK_STATE_NORMAL,
- GTK_SHADOW_OUT, cliprect, gParts->tabWidget, "tab",
- rect->x, rect->y, rect->width,
- rect->height - gap_voffset, GTK_POS_BOTTOM);
-
- /* Draw the gap; erase with background color before painting in
- * case theme does not */
- gtk_style_apply_default_background(style, drawable, TRUE,
- GTK_STATE_NORMAL, cliprect,
- rect->x,
- rect->y + rect->height
- - gap_voffset,
- rect->width, gap_height);
- gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
- cliprect, gParts->tabWidget, "notebook",
- rect->x - gap_loffset,
- rect->y + rect->height - gap_voffset,
- rect->width + gap_loffset + gap_roffset,
- 3 * gap_height, GTK_POS_TOP,
- gap_loffset, rect->width);
- }
-
- }
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_tabpanels_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTextDirection direction)
-{
- /* We use gtk_paint_box_gap() to draw the tabpanels widget. gtk_paint_box()
- * draws an all-purpose box, which a lot of themes render differently.
- * A zero-width gap is still visible in most themes, so we hide it to the
- * left (10px should be enough) */
- GtkStyle* style;
-
- ensure_tab_widget();
- gtk_widget_set_direction(gParts->tabWidget, direction);
-
- style = gtk_widget_get_style(gParts->tabWidget);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
- cliprect, gParts->tabWidget, "notebook", rect->x, rect->y,
- rect->width, rect->height,
- GTK_POS_TOP, -10, 0);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_tab_scroll_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- GtkArrowType arrow_type,
- GtkTextDirection direction)
-{
- GtkStateType state_type = ConvertGtkState(state);
- GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
- GtkStyle* style;
- gint arrow_size = MIN(rect->width, rect->height);
- gint x = rect->x + (rect->width - arrow_size) / 2;
- gint y = rect->y + (rect->height - arrow_size) / 2;
-
- ensure_tab_widget();
-
- style = gtk_widget_get_style(gParts->tabWidget);
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- if (direction == GTK_TEXT_DIR_RTL) {
- arrow_type = (arrow_type == GTK_ARROW_LEFT) ?
- GTK_ARROW_RIGHT : GTK_ARROW_LEFT;
- }
-
- gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL,
- gParts->tabWidget, "notebook", arrow_type, TRUE,
- x, y, arrow_size, arrow_size);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_menu_bar_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTextDirection direction)
-{
- GtkStyle* style;
- GtkShadowType shadow_type;
- ensure_menu_bar_widget();
- gtk_widget_set_direction(gParts->menuBarWidget, direction);
-
- gtk_widget_style_get(gParts->menuBarWidget, "shadow-type", &shadow_type, NULL);
-
- style = gtk_widget_get_style(gParts->menuBarWidget);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL,
- cliprect, rect->x, rect->y,
- rect->width, rect->height);
-
- gtk_paint_box(style, drawable, GTK_STATE_NORMAL, shadow_type,
- cliprect, gParts->menuBarWidget, "menubar", rect->x, rect->y,
- rect->width, rect->height);
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_menu_popup_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTextDirection direction)
-{
- GtkStyle* style;
- ensure_menu_popup_widget();
- gtk_widget_set_direction(gParts->menuPopupWidget, direction);
-
- style = gtk_widget_get_style(gParts->menuPopupWidget);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL,
- cliprect, rect->x, rect->y,
- rect->width, rect->height);
- gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
- cliprect, gParts->menuPopupWidget, "menu",
- rect->x, rect->y, rect->width, rect->height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTextDirection direction)
-{
- GtkStyle* style;
- gboolean wide_separators;
- gint separator_height;
- guint horizontal_padding;
- gint paint_height;
-
- ensure_menu_separator_widget();
- gtk_widget_set_direction(gParts->menuSeparatorWidget, direction);
-
- style = gtk_widget_get_style(gParts->menuSeparatorWidget);
-
- gtk_widget_style_get(gParts->menuSeparatorWidget,
- "wide-separators", &wide_separators,
- "separator-height", &separator_height,
- "horizontal-padding", &horizontal_padding,
- NULL);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- if (wide_separators) {
- if (separator_height > rect->height)
- separator_height = rect->height;
-
- gtk_paint_box(style, drawable,
- GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
- cliprect, gParts->menuSeparatorWidget, "hseparator",
- rect->x + horizontal_padding + style->xthickness,
- rect->y + (rect->height - separator_height - style->ythickness) / 2,
- rect->width - 2 * (horizontal_padding + style->xthickness),
- separator_height);
- } else {
- paint_height = style->ythickness;
- if (paint_height > rect->height)
- paint_height = rect->height;
-
- gtk_paint_hline(style, drawable,
- GTK_STATE_NORMAL, cliprect, gParts->menuSeparatorWidget,
- "menuitem",
- rect->x + horizontal_padding + style->xthickness,
- rect->x + rect->width - horizontal_padding - style->xthickness - 1,
- rect->y + (rect->height - style->ythickness) / 2);
- }
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- gint flags, GtkTextDirection direction)
-{
- GtkStyle* style;
- GtkShadowType shadow_type;
- GtkWidget* item_widget;
-
- if (state->inHover && !state->disabled) {
- if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
- ensure_menu_bar_item_widget();
- item_widget = gParts->menuBarItemWidget;
- } else {
- ensure_menu_item_widget();
- item_widget = gParts->menuItemWidget;
- }
- gtk_widget_set_direction(item_widget, direction);
-
- style = gtk_widget_get_style(item_widget);
- TSOffsetStyleGCs(style, rect->x, rect->y);
-
- gtk_widget_style_get(item_widget, "selected-shadow-type",
- &shadow_type, NULL);
-
- gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, shadow_type,
- cliprect, item_widget, "menuitem", rect->x, rect->y,
- rect->width, rect->height);
- }
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_menu_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- GtkTextDirection direction)
-{
- GtkStyle* style;
- GtkStateType state_type = ConvertGtkState(state);
-
- ensure_menu_item_widget();
- gtk_widget_set_direction(gParts->menuItemWidget, direction);
-
- style = gtk_widget_get_style(gParts->menuItemWidget);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_paint_arrow(style, drawable, state_type,
- (state_type == GTK_STATE_PRELIGHT) ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
- cliprect, gParts->menuItemWidget, "menuitem",
- (direction == GTK_TEXT_DIR_LTR) ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT,
- TRUE, rect->x, rect->y, rect->width, rect->height);
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_check_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkWidgetState* state,
- gboolean checked, gboolean isradio,
- GtkTextDirection direction)
-{
- GtkStateType state_type = ConvertGtkState(state);
- GtkStyle* style;
- GtkShadowType shadow_type = (checked)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
- gint offset;
- gint indicator_size;
- gint x, y;
-
- moz_gtk_menu_item_paint(drawable, rect, cliprect, state, FALSE, direction);
-
- ensure_check_menu_item_widget();
- gtk_widget_set_direction(gParts->checkMenuItemWidget, direction);
-
- gtk_widget_style_get (gParts->checkMenuItemWidget,
- "indicator-size", &indicator_size,
- NULL);
-
-#ifdef GTK_API_VERSION_2
- if (checked || GTK_CHECK_MENU_ITEM(gParts->checkMenuItemWidget)->always_show_toggle) {
-#else
- if (checked || FALSE) {
-#endif
- style = gtk_widget_get_style(gParts->checkMenuItemWidget);
-
- offset = gtk_container_get_border_width(GTK_CONTAINER(gParts->checkMenuItemWidget)) + style->xthickness + 2;
-
- /* while normally this "3" would be the horizontal-padding style value, passing it to Gecko
- as the value of menuitem padding causes problems with dropdowns (bug 406129), so in the menu.css
- file this is hardcoded as 3px. Yes it sucks, but we don't really have a choice. */
- x = (direction == GTK_TEXT_DIR_RTL) ?
- rect->width - indicator_size - offset - 3: rect->x + offset + 3;
- y = rect->y + (rect->height - indicator_size) / 2;
-
- TSOffsetStyleGCs(style, x, y);
- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gParts->checkMenuItemWidget),
- checked);
-
- if (isradio) {
- gtk_paint_option(style, drawable, state_type, shadow_type, cliprect,
- gParts->checkMenuItemWidget, "option",
- x, y, indicator_size, indicator_size);
- } else {
- gtk_paint_check(style, drawable, state_type, shadow_type, cliprect,
- gParts->checkMenuItemWidget, "check",
- x, y, indicator_size, indicator_size);
- }
- }
-
- return MOZ_GTK_SUCCESS;
-}
-
-static gint
-moz_gtk_window_paint(GdkDrawable* drawable, GdkRectangle* rect,
- GdkRectangle* cliprect, GtkTextDirection direction)
-{
- GtkStyle* style;
-
- ensure_window_widget();
- gtk_widget_set_direction(gParts->protoWindow, direction);
-
- style = gtk_widget_get_style(gParts->protoWindow);
-
- TSOffsetStyleGCs(style, rect->x, rect->y);
- gtk_style_apply_default_background(style, drawable, TRUE,
- GTK_STATE_NORMAL,
- cliprect, rect->x, rect->y,
- rect->width, rect->height);
- return MOZ_GTK_SUCCESS;
-}
-
-gint
moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
gint* right, gint* bottom, GtkTextDirection direction,
gboolean inhtml)
@@ -2705,52 +1258,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
ensure_entry_widget();
w = gParts->entryWidget;
break;
- case MOZ_GTK_TREEVIEW:
- ensure_tree_view_widget();
- w = gParts->treeViewWidget;
- break;
- case MOZ_GTK_TREE_HEADER_CELL:
- {
- /* A Tree Header in GTK is just a different styled button
- * It must be placed in a TreeView for getting the correct style
- * assigned.
- * That is why the following code is the same as for MOZ_GTK_BUTTON.
- * */
-
- GtkBorder inner_border;
- gboolean interior_focus;
- gint focus_width, focus_pad;
- GtkStyle* style;
-
- ensure_tree_header_cell_widget();
- *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gParts->treeHeaderCellWidget));
-
- moz_gtk_widget_get_focus(gParts->treeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad);
- moz_gtk_button_get_inner_border(gParts->treeHeaderCellWidget, &inner_border);
- *left += focus_width + focus_pad + inner_border.left;
- *right += focus_width + focus_pad + inner_border.right;
- *top += focus_width + focus_pad + inner_border.top;
- *bottom += focus_width + focus_pad + inner_border.bottom;
-
- style = gtk_widget_get_style(gParts->treeHeaderCellWidget);
- *left += style->xthickness;
- *right += style->xthickness;
- *top += style->ythickness;
- *bottom += style->ythickness;
- return MOZ_GTK_SUCCESS;
- }
- case MOZ_GTK_TREE_HEADER_SORTARROW:
- ensure_tree_header_cell_widget();
- w = gParts->treeHeaderSortArrowWidget;
- break;
- case MOZ_GTK_DROPDOWN_ENTRY:
- ensure_combo_box_entry_widgets();
- w = gParts->comboBoxEntryTextareaWidget;
- break;
- case MOZ_GTK_DROPDOWN_ARROW:
- ensure_combo_box_entry_widgets();
- w = gParts->comboBoxEntryButtonWidget;
- break;
case MOZ_GTK_DROPDOWN:
{
/* We need to account for the arrow on the dropdown, so text
@@ -2791,11 +1298,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
XTHICKNESS(style);
}
-#ifdef GTK_API_VERSION_2
gtk_widget_size_request(gParts->comboBoxArrowWidget, &arrow_req);
-#else
- gtk_size_request_get_size(GTK_SIZE_REQUEST(gParts->comboBoxArrowWidget), &arrow_req, NULL);
-#endif
if (direction == GTK_TEXT_DIR_RTL)
*left += separator_width + arrow_req.width;
else
@@ -2803,20 +1306,10 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
return MOZ_GTK_SUCCESS;
}
- case MOZ_GTK_TABPANELS:
- ensure_tab_widget();
- w = gParts->tabWidget;
- break;
case MOZ_GTK_PROGRESSBAR:
ensure_progress_widget();
w = gParts->progresWidget;
break;
- case MOZ_GTK_SPINBUTTON_ENTRY:
- case MOZ_GTK_SPINBUTTON_UP:
- case MOZ_GTK_SPINBUTTON_DOWN:
- ensure_spin_widget();
- w = gParts->spinWidget;
- break;
case MOZ_GTK_SCALE_HORIZONTAL:
ensure_scale_widget();
w = gParts->hScaleWidget;
@@ -2825,89 +1318,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
ensure_scale_widget();
w = gParts->vScaleWidget;
break;
- case MOZ_GTK_FRAME:
- ensure_frame_widget();
- w = gParts->frameWidget;
- break;
- case MOZ_GTK_CHECKBUTTON_LABEL:
- case MOZ_GTK_RADIOBUTTON_LABEL:
- {
- gboolean interior_focus;
- gint focus_width, focus_pad;
-
- /* If the focus is interior, then the label has a border of
- (focus_width + focus_pad). */
- if (widget == MOZ_GTK_CHECKBUTTON_LABEL) {
- ensure_checkbox_widget();
- moz_gtk_widget_get_focus(gParts->checkboxWidget, &interior_focus,
- &focus_width, &focus_pad);
- }
- else {
- ensure_radiobutton_widget();
- moz_gtk_widget_get_focus(gParts->radiobuttonWidget, &interior_focus,
- &focus_width, &focus_pad);
- }
-
- if (interior_focus)
- *left = *top = *right = *bottom = (focus_width + focus_pad);
- else
- *left = *top = *right = *bottom = 0;
-
- return MOZ_GTK_SUCCESS;
- }
-
- case MOZ_GTK_CHECKBUTTON_CONTAINER:
- case MOZ_GTK_RADIOBUTTON_CONTAINER:
- {
- gboolean interior_focus;
- gint focus_width, focus_pad;
-
- /* If the focus is _not_ interior, then the container has a border
- of (focus_width + focus_pad). */
- if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) {
- ensure_checkbox_widget();
- moz_gtk_widget_get_focus(gParts->checkboxWidget, &interior_focus,
- &focus_width, &focus_pad);
- w = gParts->checkboxWidget;
- } else {
- ensure_radiobutton_widget();
- moz_gtk_widget_get_focus(gParts->radiobuttonWidget, &interior_focus,
- &focus_width, &focus_pad);
- w = gParts->radiobuttonWidget;
- }
-
- *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(w));
-
- if (!interior_focus) {
- *left += (focus_width + focus_pad);
- *right += (focus_width + focus_pad);
- *top += (focus_width + focus_pad);
- *bottom += (focus_width + focus_pad);
- }
-
- return MOZ_GTK_SUCCESS;
- }
- case MOZ_GTK_MENUPOPUP:
- ensure_menu_popup_widget();
- w = gParts->menuPopupWidget;
- break;
- case MOZ_GTK_MENUITEM:
- ensure_menu_item_widget();
- ensure_menu_bar_item_widget();
- w = gParts->menuItemWidget;
- break;
- case MOZ_GTK_CHECKMENUITEM:
- case MOZ_GTK_RADIOMENUITEM:
- ensure_check_menu_item_widget();
- w = gParts->checkMenuItemWidget;
- break;
- case MOZ_GTK_TAB:
- ensure_tab_widget();
- w = gParts->tabWidget;
- break;
/* These widgets have no borders, since they are not containers. */
- case MOZ_GTK_SPLITTER_HORIZONTAL:
- case MOZ_GTK_SPLITTER_VERTICAL:
case MOZ_GTK_CHECKBUTTON:
case MOZ_GTK_RADIOBUTTON:
case MOZ_GTK_SCROLLBAR_BUTTON:
@@ -2917,23 +1328,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
case MOZ_GTK_SCALE_THUMB_VERTICAL:
- case MOZ_GTK_GRIPPER:
case MOZ_GTK_PROGRESS_CHUNK:
- case MOZ_GTK_EXPANDER:
- case MOZ_GTK_TREEVIEW_EXPANDER:
- case MOZ_GTK_TOOLBAR_SEPARATOR:
- case MOZ_GTK_MENUSEPARATOR:
- /* These widgets have no borders.*/
- case MOZ_GTK_SPINBUTTON:
- case MOZ_GTK_TOOLTIP:
- case MOZ_GTK_WINDOW:
- case MOZ_GTK_RESIZER:
- case MOZ_GTK_MENUARROW:
- case MOZ_GTK_TOOLBARBUTTON_ARROW:
- case MOZ_GTK_TOOLBAR:
- case MOZ_GTK_MENUBAR:
- case MOZ_GTK_TAB_SCROLLARROW:
- case MOZ_GTK_ENTRY_CARET:
*left = *top = *right = *bottom = 0;
return MOZ_GTK_SUCCESS;
default:
@@ -2949,131 +1344,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
}
gint
-moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height)
-{
- /*
- * We get the requisition of the drop down button, which includes
- * all padding, border and focus line widths the button uses,
- * as well as the minimum arrow size and its padding
- * */
- GtkRequisition requisition;
- ensure_combo_box_entry_widgets();
-
-#ifdef GTK_API_VERSION_2
- gtk_widget_size_request(gParts->comboBoxEntryButtonWidget, &requisition);
-#else
- gtk_size_request_get_size(GTK_SIZE_REQUEST(gParts->comboBoxEntryButtonWidget), &requisition, NULL);
-#endif
-
- *width = requisition.width;
- *height = requisition.height;
-
- return MOZ_GTK_SUCCESS;
-}
-
-gint
-moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height)
-{
- gint arrow_size;
-
- ensure_tab_widget();
- gtk_widget_style_get(gParts->tabWidget,
- "scroll-arrow-hlength", &arrow_size,
- NULL);
-
- *height = *width = arrow_size;
-
- return MOZ_GTK_SUCCESS;
-}
-
-gint
-moz_gtk_get_downarrow_size(gint* width, gint* height)
-{
- GtkRequisition requisition;
- ensure_button_arrow_widget();
-
-#ifdef GTK_API_VERSION_2
- gtk_widget_size_request(gParts->buttonArrowWidget, &requisition);
-#else
- gtk_size_request_get_size(GTK_SIZE_REQUEST(gParts->buttonArrowWidget), &requisition, NULL);
-#endif
-
- *width = requisition.width;
- *height = requisition.height;
-
- return MOZ_GTK_SUCCESS;
-}
-
-gint
-moz_gtk_get_toolbar_separator_width(gint* size)
-{
- gboolean wide_separators;
- gint separator_width;
- GtkStyle* style;
-
- ensure_toolbar_widget();
-
- style = gtk_widget_get_style(gParts->toolbarWidget);
-
- gtk_widget_style_get(gParts->toolbarWidget,
- "space-size", size,
- "wide-separators", &wide_separators,
- "separator-width", &separator_width,
- NULL);
-
- /* Just in case... */
- *size = MAX(*size, (wide_separators ? separator_width : style->xthickness));
-
- return MOZ_GTK_SUCCESS;
-}
-
-gint
-moz_gtk_get_expander_size(gint* size)
-{
- ensure_expander_widget();
- gtk_widget_style_get(gParts->expanderWidget,
- "expander-size", size,
- NULL);
-
- return MOZ_GTK_SUCCESS;
-}
-
-gint
-moz_gtk_get_treeview_expander_size(gint* size)
-{
- ensure_tree_view_widget();
- gtk_widget_style_get(gParts->treeViewWidget,
- "expander-size", size,
- NULL);
-
- return MOZ_GTK_SUCCESS;
-}
-
-gint
-moz_gtk_get_menu_separator_height(gint *size)
-{
- gboolean wide_separators;
- gint separator_height;
- GtkStyle *style;
-
- ensure_menu_separator_widget();
-
- gtk_widget_style_get(gParts->menuSeparatorWidget,
- "wide-separators", &wide_separators,
- "separator-height", &separator_height,
- NULL);
-
- style = gtk_widget_get_style(gParts->menuSeparatorWidget);
-
- if (wide_separators)
- *size = separator_height + style->ythickness;
- else
- *size = style->ythickness * 2;
-
- return MOZ_GTK_SUCCESS;
-}
-
-gint
moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height)
{
GtkWidget* widget;
@@ -3109,19 +1379,6 @@ moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
return MOZ_GTK_SUCCESS;
}
-gboolean
-moz_gtk_images_in_menus()
-{
- gboolean result;
- GtkSettings* settings;
-
- ensure_image_menu_item_widget();
- settings = gtk_widget_get_settings(gParts->imageMenuItemWidget);
-
- g_object_get(settings, "gtk-menu-images", &result, NULL);
- return result;
-}
-
gint
moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
GdkRectangle* rect, GdkRectangle* cliprect,
@@ -3177,96 +1434,15 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
return moz_gtk_scale_thumb_paint(drawable, rect, cliprect, state,
(GtkOrientation) flags, direction);
break;
- case MOZ_GTK_SPINBUTTON:
- return moz_gtk_spin_paint(drawable, rect, direction);
- break;
- case MOZ_GTK_SPINBUTTON_UP:
- case MOZ_GTK_SPINBUTTON_DOWN:
- return moz_gtk_spin_updown_paint(drawable, rect,
- (widget == MOZ_GTK_SPINBUTTON_DOWN),
- state, direction);
- break;
- case MOZ_GTK_SPINBUTTON_ENTRY:
- ensure_spin_widget();
- return moz_gtk_entry_paint(drawable, rect, cliprect, state,
- gParts->spinWidget, direction);
- break;
- case MOZ_GTK_GRIPPER:
- return moz_gtk_gripper_paint(drawable, rect, cliprect, state,
- direction);
- break;
- case MOZ_GTK_TREEVIEW:
- return moz_gtk_treeview_paint(drawable, rect, cliprect, state,
- direction);
- break;
- case MOZ_GTK_TREE_HEADER_CELL:
- return moz_gtk_tree_header_cell_paint(drawable, rect, cliprect, state,
- flags, direction);
- break;
- case MOZ_GTK_TREE_HEADER_SORTARROW:
- return moz_gtk_tree_header_sort_arrow_paint(drawable, rect, cliprect,
- state,
- (GtkArrowType) flags,
- direction);
- break;
- case MOZ_GTK_TREEVIEW_EXPANDER:
- return moz_gtk_treeview_expander_paint(drawable, rect, cliprect, state,
- (GtkExpanderStyle) flags, direction);
- break;
- case MOZ_GTK_EXPANDER:
- return moz_gtk_expander_paint(drawable, rect, cliprect, state,
- (GtkExpanderStyle) flags, direction);
- break;
case MOZ_GTK_ENTRY:
ensure_entry_widget();
return moz_gtk_entry_paint(drawable, rect, cliprect, state,
gParts->entryWidget, direction);
break;
- case MOZ_GTK_ENTRY_CARET:
- return moz_gtk_caret_paint(drawable, rect, cliprect, direction);
- break;
case MOZ_GTK_DROPDOWN:
return moz_gtk_combo_box_paint(drawable, rect, cliprect, state,
(gboolean) flags, direction);
break;
- case MOZ_GTK_DROPDOWN_ARROW:
- return moz_gtk_combo_box_entry_button_paint(drawable, rect, cliprect,
- state, flags, direction);
- break;
- case MOZ_GTK_DROPDOWN_ENTRY:
- ensure_combo_box_entry_widgets();
- return moz_gtk_entry_paint(drawable, rect, cliprect, state,
- gParts->comboBoxEntryTextareaWidget, direction);
- break;
- case MOZ_GTK_CHECKBUTTON_CONTAINER:
- case MOZ_GTK_RADIOBUTTON_CONTAINER:
- return moz_gtk_container_paint(drawable, rect, cliprect, state,
- (widget == MOZ_GTK_RADIOBUTTON_CONTAINER),
- direction);
- break;
- case MOZ_GTK_CHECKBUTTON_LABEL:
- case MOZ_GTK_RADIOBUTTON_LABEL:
- return moz_gtk_toggle_label_paint(drawable, rect, cliprect, state,
- (widget == MOZ_GTK_RADIOBUTTON_LABEL),
- direction);
- break;
- case MOZ_GTK_TOOLBAR:
- return moz_gtk_toolbar_paint(drawable, rect, cliprect, direction);
- break;
- case MOZ_GTK_TOOLBAR_SEPARATOR:
- return moz_gtk_toolbar_separator_paint(drawable, rect, cliprect,
- direction);
- break;
- case MOZ_GTK_TOOLTIP:
- return moz_gtk_tooltip_paint(drawable, rect, cliprect, direction);
- break;
- case MOZ_GTK_FRAME:
- return moz_gtk_frame_paint(drawable, rect, cliprect, direction);
- break;
- case MOZ_GTK_RESIZER:
- return moz_gtk_resizer_paint(drawable, rect, cliprect, state,
- direction);
- break;
case MOZ_GTK_PROGRESSBAR:
return moz_gtk_progressbar_paint(drawable, rect, cliprect, direction);
break;
@@ -3274,54 +1450,6 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
return moz_gtk_progress_chunk_paint(drawable, rect, cliprect,
direction);
break;
- case MOZ_GTK_TAB:
- return moz_gtk_tab_paint(drawable, rect, cliprect,
- (GtkTabFlags) flags, direction);
- break;
- case MOZ_GTK_TABPANELS:
- return moz_gtk_tabpanels_paint(drawable, rect, cliprect, direction);
- break;
- case MOZ_GTK_TAB_SCROLLARROW:
- return moz_gtk_tab_scroll_arrow_paint(drawable, rect, cliprect, state,
- (GtkArrowType) flags, direction);
- break;
- case MOZ_GTK_MENUBAR:
- return moz_gtk_menu_bar_paint(drawable, rect, cliprect, direction);
- break;
- case MOZ_GTK_MENUPOPUP:
- return moz_gtk_menu_popup_paint(drawable, rect, cliprect, direction);
- break;
- case MOZ_GTK_MENUSEPARATOR:
- return moz_gtk_menu_separator_paint(drawable, rect, cliprect,
- direction);
- break;
- case MOZ_GTK_MENUITEM:
- return moz_gtk_menu_item_paint(drawable, rect, cliprect, state, flags,
- direction);
- break;
- case MOZ_GTK_MENUARROW:
- return moz_gtk_menu_arrow_paint(drawable, rect, cliprect, state,
- direction);
- break;
- case MOZ_GTK_TOOLBARBUTTON_ARROW:
- return moz_gtk_downarrow_paint(drawable, rect, cliprect, state);
- break;
- case MOZ_GTK_CHECKMENUITEM:
- case MOZ_GTK_RADIOMENUITEM:
- return moz_gtk_check_menu_item_paint(drawable, rect, cliprect, state,
- (gboolean) flags,
- (widget == MOZ_GTK_RADIOMENUITEM),
- direction);
- break;
- case MOZ_GTK_SPLITTER_HORIZONTAL:
- return moz_gtk_vpaned_paint(drawable, rect, cliprect, state);
- break;
- case MOZ_GTK_SPLITTER_VERTICAL:
- return moz_gtk_hpaned_paint(drawable, rect, cliprect, state);
- break;
- case MOZ_GTK_WINDOW:
- return moz_gtk_window_paint(drawable, rect, cliprect, direction);
- break;
default:
g_warning("Unknown widget type: %d", widget);
}
@@ -3354,11 +1482,6 @@ void moz_gtk_destroy_theme_parts_widgets(GtkThemeParts* parts)
if (!parts)
return;
- if (parts->tooltipWidget) {
- gtk_widget_destroy(parts->tooltipWidget);
- parts->tooltipWidget = NULL;
- }
-
if (parts->protoWindow) {
gtk_widget_destroy(parts->protoWindow);
parts->protoWindow = NULL;
@@ -3372,3 +1495,5 @@ GtkWidget* moz_gtk_get_progress_widget()
ensure_progress_widget();
return gParts->progresWidget;
}
+
+#endif // GTK_API_VERSION_2
diff --git a/WebCore/platform/gtk/gtk3drawing.c b/WebCore/platform/gtk/gtk3drawing.c
new file mode 100644
index 0000000..dda110d
--- /dev/null
+++ b/WebCore/platform/gtk/gtk3drawing.c
@@ -0,0 +1,1416 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brian Ryner <bryner@brianryner.com> (Original Author)
+ * Pierre Chanial <p_ch@verizon.net>
+ * Michael Ventnor <m.ventnor@gmail.com>
+ * Alp Toker <alp@nuanti.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * This file contains painting functions for each of the gtk2 widgets.
+ * Adapted from the gtkdrawing.c, and gtk+2.0 source.
+ */
+
+#ifndef GTK_API_VERSION_2
+
+#include <gdk/gdkprivate.h>
+#include "gtkdrawing.h"
+#include "GtkVersioning.h"
+#include <math.h>
+#include <string.h>
+
+#define XTHICKNESS(style) (style->xthickness)
+#define YTHICKNESS(style) (style->ythickness)
+
+static GtkThemeParts *gParts = NULL;
+static style_prop_t style_prop_func;
+static gboolean have_arrow_scaling;
+static gboolean is_initialized;
+
+void
+moz_gtk_use_theme_parts(GtkThemeParts* parts)
+{
+ gParts = parts;
+}
+
+/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine
+ that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific
+ things they may want to do. */
+static void
+moz_gtk_set_widget_name(GtkWidget* widget)
+{
+ gtk_widget_set_name(widget, "MozillaGtkWidget");
+}
+
+gint
+moz_gtk_enable_style_props(style_prop_t styleGetProp)
+{
+ style_prop_func = styleGetProp;
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_window_widget()
+{
+ if (!gParts->protoWindow) {
+ gParts->protoWindow = gtk_window_new(GTK_WINDOW_POPUP);
+ gtk_widget_realize(gParts->protoWindow);
+ moz_gtk_set_widget_name(gParts->protoWindow);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+setup_widget_prototype(GtkWidget* widget)
+{
+ ensure_window_widget();
+ if (!gParts->protoLayout) {
+ gParts->protoLayout = gtk_fixed_new();
+ gtk_container_add(GTK_CONTAINER(gParts->protoWindow), gParts->protoLayout);
+ }
+
+ gtk_container_add(GTK_CONTAINER(gParts->protoLayout), widget);
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_button_widget()
+{
+ if (!gParts->buttonWidget) {
+ gParts->buttonWidget = gtk_button_new_with_label("M");
+ setup_widget_prototype(gParts->buttonWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_toggle_button_widget()
+{
+ if (!gParts->toggleButtonWidget) {
+ gParts->toggleButtonWidget = gtk_toggle_button_new();
+ setup_widget_prototype(gParts->toggleButtonWidget);
+ /* toggle button must be set active to get the right style on hover. */
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gParts->toggleButtonWidget), TRUE);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_button_arrow_widget()
+{
+ if (!gParts->buttonArrowWidget) {
+ ensure_toggle_button_widget();
+
+ gParts->buttonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+ gtk_container_add(GTK_CONTAINER(gParts->toggleButtonWidget), gParts->buttonArrowWidget);
+ gtk_widget_realize(gParts->buttonArrowWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_checkbox_widget()
+{
+ if (!gParts->checkboxWidget) {
+ gParts->checkboxWidget = gtk_check_button_new_with_label("M");
+ setup_widget_prototype(gParts->checkboxWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_radiobutton_widget()
+{
+ if (!gParts->radiobuttonWidget) {
+ gParts->radiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M");
+ setup_widget_prototype(gParts->radiobuttonWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_scrollbar_widget()
+{
+ if (!gParts->vertScrollbarWidget) {
+ gParts->vertScrollbarWidget = gtk_vscrollbar_new(NULL);
+ setup_widget_prototype(gParts->vertScrollbarWidget);
+ }
+ if (!gParts->horizScrollbarWidget) {
+ gParts->horizScrollbarWidget = gtk_hscrollbar_new(NULL);
+ setup_widget_prototype(gParts->horizScrollbarWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_scale_widget()
+{
+ if (!gParts->hScaleWidget) {
+ gParts->hScaleWidget = gtk_hscale_new(NULL);
+ setup_widget_prototype(gParts->hScaleWidget);
+ }
+ if (!gParts->vScaleWidget) {
+ gParts->vScaleWidget = gtk_vscale_new(NULL);
+ setup_widget_prototype(gParts->vScaleWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_entry_widget()
+{
+ if (!gParts->entryWidget) {
+ gParts->entryWidget = gtk_entry_new();
+ setup_widget_prototype(gParts->entryWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+/* We need to have pointers to the inner widgets (button, separator, arrow)
+ * of the ComboBox to get the correct rendering from theme engines which
+ * special cases their look. Since the inner layout can change, we ask GTK
+ * to NULL our pointers when they are about to become invalid because the
+ * corresponding widgets don't exist anymore. It's the role of
+ * g_object_add_weak_pointer().
+ * Note that if we don't find the inner widgets (which shouldn't happen), we
+ * fallback to use generic "non-inner" widgets, and they don't need that kind
+ * of weak pointer since they are explicit children of gParts->protoWindow and as
+ * such GTK holds a strong reference to them. */
+static void
+moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data)
+{
+ if (GTK_IS_TOGGLE_BUTTON(widget)) {
+ gParts->comboBoxButtonWidget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gParts->comboBoxButtonWidget);
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ }
+}
+
+static void
+moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget,
+ gpointer client_data)
+{
+ if (GTK_IS_SEPARATOR(widget)) {
+ gParts->comboBoxSeparatorWidget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gParts->comboBoxSeparatorWidget);
+ } else if (GTK_IS_ARROW(widget)) {
+ gParts->comboBoxArrowWidget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gParts->comboBoxArrowWidget);
+ } else
+ return;
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+}
+
+static gint
+ensure_combo_box_widgets()
+{
+ GtkWidget* buttonChild;
+
+ if (gParts->comboBoxButtonWidget && gParts->comboBoxArrowWidget)
+ return MOZ_GTK_SUCCESS;
+
+ /* Create a ComboBox if needed */
+ if (!gParts->comboBoxWidget) {
+ gParts->comboBoxWidget = gtk_combo_box_new();
+ setup_widget_prototype(gParts->comboBoxWidget);
+ }
+
+ /* Get its inner Button */
+ gtk_container_forall(GTK_CONTAINER(gParts->comboBoxWidget),
+ moz_gtk_get_combo_box_inner_button,
+ NULL);
+
+ if (gParts->comboBoxButtonWidget) {
+ /* Get the widgets inside the Button */
+ buttonChild = gtk_bin_get_child(GTK_BIN(gParts->comboBoxButtonWidget));
+ if (GTK_IS_HBOX(buttonChild)) {
+ /* appears-as-list = FALSE, cell-view = TRUE; the button
+ * contains an hbox. This hbox is there because the ComboBox
+ * needs to place a cell renderer, a separator, and an arrow in
+ * the button when appears-as-list is FALSE. */
+ gtk_container_forall(GTK_CONTAINER(buttonChild),
+ moz_gtk_get_combo_box_button_inner_widgets,
+ NULL);
+ } else if(GTK_IS_ARROW(buttonChild)) {
+ /* appears-as-list = TRUE, or cell-view = FALSE;
+ * the button only contains an arrow */
+ gParts->comboBoxArrowWidget = buttonChild;
+ g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
+ &gParts->comboBoxArrowWidget);
+ gtk_widget_realize(gParts->comboBoxArrowWidget);
+ g_object_set_data(G_OBJECT(gParts->comboBoxArrowWidget),
+ "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ }
+ } else {
+ /* Shouldn't be reached with current internal gtk implementation; we
+ * use a generic toggle button as last resort fallback to avoid
+ * crashing. */
+ ensure_toggle_button_widget();
+ gParts->comboBoxButtonWidget = gParts->toggleButtonWidget;
+ }
+
+ if (!gParts->comboBoxArrowWidget) {
+ /* Shouldn't be reached with current internal gtk implementation;
+ * we gParts->buttonArrowWidget as last resort fallback to avoid
+ * crashing. */
+ ensure_button_arrow_widget();
+ gParts->comboBoxArrowWidget = gParts->buttonArrowWidget;
+ }
+
+ /* We don't test the validity of gParts->comboBoxSeparatorWidget since there
+ * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it
+ * is invalid we just won't paint it. */
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_progress_widget()
+{
+ if (!gParts->progresWidget) {
+ gParts->progresWidget = gtk_progress_bar_new();
+ setup_widget_prototype(gParts->progresWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_scrolled_window_widget()
+{
+ if (!gParts->scrolledWindowWidget) {
+ gParts->scrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL);
+ setup_widget_prototype(gParts->scrolledWindowWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static GtkStateType
+ConvertGtkState(GtkWidgetState* state)
+{
+ if (state->disabled)
+ return GTK_STATE_INSENSITIVE;
+ else if (state->depressed)
+ return (state->inHover ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
+ else if (state->inHover)
+ return (state->active ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
+ else
+ return GTK_STATE_NORMAL;
+}
+
+static gint
+moz_gtk_button_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, GtkReliefStyle relief,
+ GtkWidget* widget, GtkTextDirection direction)
+{
+ GtkShadowType shadow_type;
+ GtkStyle* style = gtk_widget_get_style(widget);
+ GtkStateType button_state = ConvertGtkState(state);
+ gint x = rect->x, y=rect->y, width=rect->width, height=rect->height;
+ GdkWindow* window = gtk_widget_get_window(widget);
+
+ gboolean interior_focus;
+ gint focus_width, focus_pad;
+
+ moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad);
+
+ if (window && gdk_window_is_visible(window)) {
+ gdk_window_set_background_pattern(window, NULL);
+ }
+
+ gtk_widget_set_state(widget, button_state);
+ gtk_widget_set_direction(widget, direction);
+ gtk_button_set_relief(GTK_BUTTON(widget), relief);
+
+ if (!interior_focus && state->focused) {
+ x += focus_width + focus_pad;
+ y += focus_width + focus_pad;
+ width -= 2 * (focus_width + focus_pad);
+ height -= 2 * (focus_width + focus_pad);
+ }
+
+ shadow_type = button_state == GTK_STATE_ACTIVE ||
+ state->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+
+ if (state->isDefault && relief == GTK_RELIEF_NORMAL) {
+ gtk_paint_box(style, cr, button_state, shadow_type,
+ widget, "buttondefault", x, y, width, height);
+ }
+
+ if (relief != GTK_RELIEF_NONE || state->depressed ||
+ (button_state != GTK_STATE_NORMAL &&
+ button_state != GTK_STATE_INSENSITIVE)) {
+ /* the following line can trigger an assertion (Crux theme)
+ file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area):
+ assertion `GDK_IS_WINDOW (window)' failed */
+ gtk_paint_box(style, cr, button_state, shadow_type,
+ widget, "button", x, y, width, height);
+ }
+
+ if (state->focused) {
+ if (interior_focus) {
+ GtkStyle* style = gtk_widget_get_style(widget);
+ x += style->xthickness + focus_pad;
+ y += style->ythickness + focus_pad;
+ width -= 2 * (style->xthickness + focus_pad);
+ height -= 2 * (style->ythickness + focus_pad);
+ } else {
+ x -= focus_width + focus_pad;
+ y -= focus_width + focus_pad;
+ width += 2 * (focus_width + focus_pad);
+ height += 2 * (focus_width + focus_pad);
+ }
+
+ gtk_paint_focus(style, cr, button_state,
+ widget, "button", x, y, width, height);
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_init()
+{
+ GtkWidgetClass *entry_class;
+
+ is_initialized = TRUE;
+ have_arrow_scaling = (gtk_major_version > 2 ||
+ (gtk_major_version == 2 && gtk_minor_version >= 12));
+
+ /* Add style property to GtkEntry.
+ * Adding the style property to the normal GtkEntry class means that it
+ * will work without issues inside GtkComboBox and for Spinbuttons. */
+ entry_class = g_type_class_ref(GTK_TYPE_ENTRY);
+ gtk_widget_class_install_style_property(entry_class,
+ g_param_spec_boolean("honors-transparent-bg-hint",
+ "Transparent BG enabling flag",
+ "If TRUE, the theme is able to draw the GtkEntry on non-prefilled background.",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
+{
+ ensure_checkbox_widget();
+
+ gtk_widget_style_get (gParts->checkboxWidget,
+ "indicator_size", indicator_size,
+ "indicator_spacing", indicator_spacing,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
+{
+ ensure_radiobutton_widget();
+
+ gtk_widget_style_get (gParts->radiobuttonWidget,
+ "indicator_size", indicator_size,
+ "indicator_spacing", indicator_spacing,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus,
+ gint* focus_width, gint* focus_pad)
+{
+ gtk_widget_style_get (widget,
+ "interior-focus", interior_focus,
+ "focus-line-width", focus_width,
+ "focus-padding", focus_pad,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border)
+{
+ static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
+ GtkBorder *tmp_border;
+
+ gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL);
+
+ if (tmp_border) {
+ *inner_border = *tmp_border;
+ gtk_border_free(tmp_border);
+ }
+ else
+ *inner_border = default_inner_border;
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_toggle_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, gboolean selected,
+ gboolean inconsistent, gboolean isradio,
+ GtkTextDirection direction)
+{
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
+ gint indicator_size, indicator_spacing;
+ gint x, y, width, height;
+ gint focus_x, focus_y, focus_width, focus_height;
+ GtkWidget *w;
+ GtkStyle *style;
+
+ if (isradio) {
+ moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
+ w = gParts->radiobuttonWidget;
+ } else {
+ moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
+ w = gParts->checkboxWidget;
+ }
+
+ // "GetMinimumWidgetSize was ignored"
+ // FIXME: This assert causes a build failure in WebKitGTK+ debug
+ // builds, because it uses 'false' in its definition. We may want
+ // to force this file to be built with g++, by renaming it.
+ // ASSERT(rect->width == indicator_size);
+
+ /*
+ * vertically center in the box, since XUL sometimes ignores our
+ * GetMinimumWidgetSize in the vertical dimension
+ */
+ x = rect->x;
+ y = rect->y + (rect->height - indicator_size) / 2;
+ width = indicator_size;
+ height = indicator_size;
+
+ focus_x = x - indicator_spacing;
+ focus_y = y - indicator_spacing;
+ focus_width = width + 2 * indicator_spacing;
+ focus_height = height + 2 * indicator_spacing;
+
+ style = gtk_widget_get_style(w);
+
+ gtk_widget_set_sensitive(w, !state->disabled);
+ gtk_widget_set_direction(w, direction);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), selected);
+
+ if (isradio) {
+ gtk_paint_option(style, cr, state_type, shadow_type,
+ gParts->radiobuttonWidget, "radiobutton", x, y,
+ width, height);
+ if (state->focused) {
+ gtk_paint_focus(style, cr, GTK_STATE_ACTIVE,
+ gParts->radiobuttonWidget, "radiobutton", focus_x, focus_y,
+ focus_width, focus_height);
+ }
+ }
+ else {
+ /*
+ * 'indeterminate' type on checkboxes. In GTK, the shadow type
+ * must also be changed for the state to be drawn.
+ */
+ if (inconsistent) {
+ gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), TRUE);
+ shadow_type = GTK_SHADOW_ETCHED_IN;
+ } else {
+ gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), FALSE);
+ }
+
+ gtk_paint_check(style, cr, state_type, shadow_type,
+ gParts->checkboxWidget, "checkbutton", x, y, width, height);
+ if (state->focused) {
+ gtk_paint_focus(style, cr, GTK_STATE_ACTIVE,
+ gParts->checkboxWidget, "checkbutton", focus_x, focus_y,
+ focus_width, focus_height);
+ }
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect,
+ GdkRectangle* inner_rect,
+ GtkTextDirection direction,
+ gboolean ignore_focus)
+{
+ GtkBorder inner_border;
+ gboolean interior_focus;
+ gint focus_width, focus_pad;
+ GtkStyle* style;
+
+ style = gtk_widget_get_style(button);
+
+ /* This mirrors gtkbutton's child positioning */
+ moz_gtk_button_get_inner_border(button, &inner_border);
+ moz_gtk_widget_get_focus(button, &interior_focus,
+ &focus_width, &focus_pad);
+
+ if (ignore_focus)
+ focus_width = focus_pad = 0;
+
+ inner_rect->x = rect->x + XTHICKNESS(style) + focus_width + focus_pad;
+ inner_rect->x += direction == GTK_TEXT_DIR_LTR ?
+ inner_border.left : inner_border.right;
+ inner_rect->y = rect->y + inner_border.top + YTHICKNESS(style) +
+ focus_width + focus_pad;
+ inner_rect->width = MAX(1, rect->width - inner_border.left -
+ inner_border.right - (XTHICKNESS(style) + focus_pad + focus_width) * 2);
+ inner_rect->height = MAX(1, rect->height - inner_border.top -
+ inner_border.bottom - (YTHICKNESS(style) + focus_pad + focus_width) * 2);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+
+static gint
+calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect,
+ GdkRectangle* arrow_rect, GtkTextDirection direction)
+{
+ /* defined in gtkarrow.c */
+ gfloat arrow_scaling = 0.7;
+ gfloat xalign, xpad;
+ gint extent;
+ GtkMisc* misc = GTK_MISC(arrow);
+ gfloat misc_xalign, misc_yalign;
+ gint misc_xpad, misc_ypad;
+
+ if (have_arrow_scaling)
+ gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL);
+
+ gtk_misc_get_padding(misc, &misc_xpad, &misc_ypad);
+ gtk_misc_get_alignment(misc, &misc_xalign, &misc_yalign);
+
+ extent = MIN((rect->width - misc_xpad * 2),
+ (rect->height - misc_ypad * 2)) * arrow_scaling;
+
+ xalign = direction == GTK_TEXT_DIR_LTR ? misc_xalign : 1.0 - misc_xalign;
+ xpad = misc_xpad + (rect->width - extent) * xalign;
+
+ arrow_rect->x = direction == GTK_TEXT_DIR_LTR ?
+ floor(rect->x + xpad) : ceil(rect->x + xpad);
+ arrow_rect->y = floor(rect->y + misc_ypad +
+ ((rect->height - extent) * misc_yalign));
+
+ arrow_rect->width = arrow_rect->height = extent;
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrolled_window_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state)
+{
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = (state->active) ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ GtkStyle* style;
+ GtkAllocation allocation;
+ GtkWidget* widget;
+
+ ensure_scrolled_window_widget();
+ widget = gParts->scrolledWindowWidget;
+
+ gtk_widget_get_allocation(widget, &allocation);
+ allocation.x = rect->x;
+ allocation.y = rect->y;
+ allocation.width = rect->width;
+ allocation.height = rect->height;
+ gtk_widget_set_allocation(widget, &allocation);
+
+ style = gtk_widget_get_style(widget);
+ gtk_paint_box(style, cr, state_type, shadow_type,
+ widget, "scrolled_window", rect->x - 1, rect->y - 1,
+ rect->width + 2, rect->height + 2);
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrollbar_button_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+ GtkScrollbarButtonFlags flags,
+ GtkTextDirection direction)
+{
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = (state->active) ?
+ GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ GdkRectangle arrow_rect;
+ GtkStyle* style;
+ GtkWidget *scrollbar;
+ GtkAllocation allocation;
+ GtkArrowType arrow_type;
+ gint arrow_displacement_x, arrow_displacement_y;
+ const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ?
+ "vscrollbar" : "hscrollbar";
+
+ ensure_scrollbar_widget();
+
+ if (flags & MOZ_GTK_STEPPER_VERTICAL)
+ scrollbar = gParts->vertScrollbarWidget;
+ else
+ scrollbar = gParts->horizScrollbarWidget;
+
+ gtk_widget_set_direction(scrollbar, direction);
+
+ /* Some theme engines (i.e., ClearLooks) check the scrollbar's allocation
+ to determine where it should paint rounded corners on the buttons.
+ We need to trick them into drawing the buttons the way we want them. */
+
+ gtk_widget_get_allocation(scrollbar, &allocation);
+ allocation.x = rect->x;
+ allocation.y = rect->y;
+ allocation.width = rect->width;
+ allocation.height = rect->height;
+
+ if (flags & MOZ_GTK_STEPPER_VERTICAL) {
+ allocation.height *= 5;
+ if (flags & MOZ_GTK_STEPPER_DOWN) {
+ arrow_type = GTK_ARROW_DOWN;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.y -= 4 * rect->height;
+ else
+ allocation.y -= rect->height;
+
+ } else {
+ arrow_type = GTK_ARROW_UP;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.y -= 3 * rect->height;
+ }
+ } else {
+ allocation.width *= 5;
+ if (flags & MOZ_GTK_STEPPER_DOWN) {
+ arrow_type = GTK_ARROW_RIGHT;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.x -= 4 * rect->width;
+ else
+ allocation.x -= rect->width;
+ } else {
+ arrow_type = GTK_ARROW_LEFT;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.x -= 3 * rect->width;
+ }
+ }
+
+ gtk_widget_set_allocation(scrollbar, &allocation);
+ style = gtk_widget_get_style(scrollbar);
+
+ gtk_paint_box(style, cr, state_type, shadow_type,
+ scrollbar, detail, rect->x, rect->y,
+ rect->width, rect->height);
+
+ arrow_rect.width = rect->width / 2;
+ arrow_rect.height = rect->height / 2;
+ arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
+ arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
+
+ if (state_type == GTK_STATE_ACTIVE) {
+ gtk_widget_style_get(scrollbar,
+ "arrow-displacement-x", &arrow_displacement_x,
+ "arrow-displacement-y", &arrow_displacement_y,
+ NULL);
+
+ arrow_rect.x += arrow_displacement_x;
+ arrow_rect.y += arrow_displacement_y;
+ }
+
+ gtk_paint_arrow(style, cr, state_type, shadow_type,
+ scrollbar, detail, arrow_type, TRUE, arrow_rect.x,
+ arrow_rect.y, arrow_rect.width, arrow_rect.height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget,
+ cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+ GtkTextDirection direction)
+{
+ GtkStyle* style;
+ GtkScrollbar *scrollbar;
+
+ ensure_scrollbar_widget();
+
+ if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL)
+ scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget);
+ else
+ scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget);
+
+ gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
+
+ style = gtk_widget_get_style(GTK_WIDGET(scrollbar));
+
+ gtk_paint_box(style, cr, GTK_STATE_ACTIVE, GTK_SHADOW_IN,
+ GTK_WIDGET(scrollbar), "trough", rect->x, rect->y,
+ rect->width, rect->height);
+
+ if (state->focused) {
+ gtk_paint_focus(style, cr, GTK_STATE_ACTIVE,
+ GTK_WIDGET(scrollbar), "trough",
+ rect->x, rect->y, rect->width, rect->height);
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
+ cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+ GtkTextDirection direction)
+{
+ GtkStateType state_type = (state->inHover || state->active) ?
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
+ GtkShadowType shadow_type = GTK_SHADOW_OUT;
+ GtkStyle* style;
+ GtkScrollbar *scrollbar;
+ GtkAdjustment *adj;
+
+ ensure_scrollbar_widget();
+
+ if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL)
+ scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget);
+ else
+ scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget);
+
+ gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
+
+ /* Make sure to set the scrollbar range before painting so that
+ everything is drawn properly. At least the bluecurve (and
+ maybe other) themes don't draw the top or bottom black line
+ surrounding the scrollbar if the theme thinks that it's butted
+ up against the scrollbar arrows. Note the increases of the
+ clip rect below. */
+ adj = gtk_range_get_adjustment(GTK_RANGE(scrollbar));
+
+ if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) {
+ gtk_adjustment_set_page_size(adj, rect->width);
+ }
+ else {
+ gtk_adjustment_set_page_size(adj, rect->height);
+ }
+
+ gtk_adjustment_configure(adj,
+ state->curpos,
+ 0,
+ state->maxpos,
+ gtk_adjustment_get_step_increment(adj),
+ gtk_adjustment_get_page_increment(adj),
+ gtk_adjustment_get_page_size(adj));
+
+ style = gtk_widget_get_style(GTK_WIDGET(scrollbar));
+
+ gtk_paint_slider(style, cr, state_type, shadow_type,
+ GTK_WIDGET(scrollbar), "slider", rect->x, rect->y,
+ rect->width, rect->height,
+ (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
+ GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scale_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, GtkOrientation flags,
+ GtkTextDirection direction)
+{
+ gint x = 0, y = 0;
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkStyle* style;
+ GtkWidget* widget;
+
+ ensure_scale_widget();
+ widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget);
+ gtk_widget_set_direction(widget, direction);
+
+ style = gtk_widget_get_style(widget);
+
+ if (flags == GTK_ORIENTATION_HORIZONTAL) {
+ x = XTHICKNESS(style);
+ y++;
+ }
+ else {
+ x++;
+ y = YTHICKNESS(style);
+ }
+
+ gtk_style_apply_default_background(style, cr, gtk_widget_get_window (widget),
+ GTK_STATE_NORMAL,
+ rect->x, rect->y,
+ rect->width, rect->height);
+
+ gtk_paint_box(style, cr, GTK_STATE_ACTIVE, GTK_SHADOW_IN,
+ widget, "trough", rect->x + x, rect->y + y,
+ rect->width - 2*x, rect->height - 2*y);
+
+ if (state->focused)
+ gtk_paint_focus(style, cr, state_type, widget, "trough",
+ rect->x, rect->y, rect->width, rect->height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scale_thumb_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, GtkOrientation flags,
+ GtkTextDirection direction)
+{
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkStyle* style;
+ GtkWidget* widget;
+ gint thumb_width, thumb_height, x, y;
+
+ ensure_scale_widget();
+ widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget);
+ gtk_widget_set_direction(widget, direction);
+
+ style = gtk_widget_get_style(widget);
+
+ /* determine the thumb size, and position the thumb in the center in the opposite axis */
+ if (flags == GTK_ORIENTATION_HORIZONTAL) {
+ moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height);
+ x = rect->x;
+ y = rect->y + (rect->height - thumb_height) / 2;
+ }
+ else {
+ moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width);
+ x = rect->x + (rect->width - thumb_width) / 2;
+ y = rect->y;
+ }
+
+ gtk_paint_slider(style, cr, state_type, GTK_SHADOW_OUT,
+ widget, (flags == GTK_ORIENTATION_HORIZONTAL) ? "hscale" : "vscale",
+ x, y, thumb_width, thumb_height, flags);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_entry_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, GtkWidget* widget,
+ GtkTextDirection direction)
+{
+ GtkStateType bg_state = state->disabled ?
+ GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
+ gint x, y, width = rect->width, height = rect->height;
+ GtkStyle* style;
+ gboolean interior_focus;
+ gboolean theme_honors_transparency = FALSE;
+ gint focus_width;
+
+ gtk_widget_set_direction(widget, direction);
+
+ style = gtk_widget_get_style(widget);
+
+ gtk_widget_style_get(widget,
+ "interior-focus", &interior_focus,
+ "focus-line-width", &focus_width,
+ "honors-transparent-bg-hint", &theme_honors_transparency,
+ NULL);
+
+ /* gtkentry.c uses two windows, one for the entire widget and one for the
+ * text area inside it. The background of both windows is set to the "base"
+ * color of the new state in gtk_entry_state_changed, but only the inner
+ * textarea window uses gtk_paint_flat_box when exposed */
+
+ /* This gets us a lovely greyish disabledish look */
+ gtk_widget_set_sensitive(widget, !state->disabled);
+
+ /* GTK fills the outer widget window with the base color before drawing the widget.
+ * Some older themes rely on this behavior, but many themes nowadays use rounded
+ * corners on their widgets. While most GTK apps are blissfully unaware of this
+ * problem due to their use of the default window background, we render widgets on
+ * many kinds of backgrounds on the web.
+ * If the theme is able to cope with transparency, then we can skip pre-filling
+ * and notify the theme it will paint directly on the canvas. */
+ if (theme_honors_transparency) {
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ } else {
+ cairo_save(cr);
+ gdk_cairo_set_source_color(cr, (const GdkColor*)&style->base[bg_state]);
+ cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
+ cairo_fill(cr);
+ cairo_restore(cr);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(FALSE));
+ }
+
+ /* Get the position of the inner window, see _gtk_entry_get_borders */
+ x = XTHICKNESS(style);
+ y = YTHICKNESS(style);
+
+ if (!interior_focus) {
+ x += focus_width;
+ y += focus_width;
+ }
+
+ /* Simulate an expose of the inner window */
+ gtk_paint_flat_box(style, cr, bg_state, GTK_SHADOW_NONE,
+ widget, "entry_bg", rect->x + x,
+ rect->y + y, rect->width - 2*x, rect->height - 2*y);
+
+ /* Now paint the shadow and focus border.
+ * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad
+ * smaller when focused if the focus is not interior, then the focus. */
+ x = rect->x;
+ y = rect->y;
+
+ if (state->focused && !state->disabled) {
+ /* This will get us the lit borders that focused textboxes enjoy on
+ * some themes. */
+ if (!interior_focus) {
+ /* Indent the border a little bit if we have exterior focus
+ (this is what GTK does to draw native entries) */
+ x += focus_width;
+ y += focus_width;
+ width -= 2 * focus_width;
+ height -= 2 * focus_width;
+ }
+ }
+
+ gtk_paint_shadow(style, cr, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ widget, "entry", x, y, width, height);
+
+ if (state->focused && !state->disabled) {
+ if (!interior_focus) {
+ gtk_paint_focus(style, cr, GTK_STATE_NORMAL,
+ widget, "entry",
+ rect->x, rect->y, rect->width, rect->height);
+ }
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_combo_box_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, gboolean ishtml,
+ GtkTextDirection direction)
+{
+ GdkRectangle arrow_rect, real_arrow_rect;
+ gint /* arrow_size, */ separator_width;
+ gboolean wide_separators;
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ GtkStyle* style;
+ GtkRequisition arrow_req;
+
+ ensure_combo_box_widgets();
+
+ /* Also sets the direction on gParts->comboBoxButtonWidget, which is then
+ * inherited by the separator and arrow */
+ moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
+ gParts->comboBoxButtonWidget, direction);
+
+ calculate_button_inner_rect(gParts->comboBoxButtonWidget,
+ rect, &arrow_rect, direction, ishtml);
+ /* Now arrow_rect contains the inner rect ; we want to correct the width
+ * to what the arrow needs (see gtk_combo_box_size_allocate) */
+ gtk_widget_get_preferred_size(gParts->comboBoxArrowWidget, &arrow_req, NULL);
+ if (direction == GTK_TEXT_DIR_LTR)
+ arrow_rect.x += arrow_rect.width - arrow_req.width;
+ arrow_rect.width = arrow_req.width;
+
+ calculate_arrow_rect(gParts->comboBoxArrowWidget,
+ &arrow_rect, &real_arrow_rect, direction);
+
+ style = gtk_widget_get_style(gParts->comboBoxArrowWidget);
+
+ gtk_widget_size_allocate(gParts->comboBoxWidget, rect);
+
+ gtk_paint_arrow(style, cr, state_type, shadow_type,
+ gParts->comboBoxArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
+ real_arrow_rect.x, real_arrow_rect.y,
+ real_arrow_rect.width, real_arrow_rect.height);
+
+
+ /* If there is no separator in the theme, there's nothing left to do. */
+ if (!gParts->comboBoxSeparatorWidget)
+ return MOZ_GTK_SUCCESS;
+
+ style = gtk_widget_get_style(gParts->comboBoxSeparatorWidget);
+
+ gtk_widget_style_get(gParts->comboBoxSeparatorWidget,
+ "wide-separators", &wide_separators,
+ "separator-width", &separator_width,
+ NULL);
+
+ if (wide_separators) {
+ if (direction == GTK_TEXT_DIR_LTR)
+ arrow_rect.x -= separator_width;
+ else
+ arrow_rect.x += arrow_rect.width;
+
+ gtk_paint_box(style, cr,
+ GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
+ gParts->comboBoxSeparatorWidget, "vseparator",
+ arrow_rect.x, arrow_rect.y,
+ separator_width, arrow_rect.height);
+ } else {
+ if (direction == GTK_TEXT_DIR_LTR)
+ arrow_rect.x -= XTHICKNESS(style);
+ else
+ arrow_rect.x += arrow_rect.width;
+
+ gtk_paint_vline(style, cr, GTK_STATE_NORMAL,
+ gParts->comboBoxSeparatorWidget, "vseparator",
+ arrow_rect.y, arrow_rect.y + arrow_rect.height,
+ arrow_rect.x);
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_progressbar_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+{
+ GtkStyle* style;
+
+ ensure_progress_widget();
+ gtk_widget_set_direction(gParts->progresWidget, direction);
+
+ style = gtk_widget_get_style(gParts->progresWidget);
+
+ gtk_paint_box(style, cr, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ gParts->progresWidget, "trough", rect->x, rect->y,
+ rect->width, rect->height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_progress_chunk_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+{
+ GtkStyle* style;
+
+ ensure_progress_widget();
+ gtk_widget_set_direction(gParts->progresWidget, direction);
+
+ style = gtk_widget_get_style(gParts->progresWidget);
+
+ gtk_paint_box(style, cr, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ gParts->progresWidget, "bar", rect->x, rect->y,
+ rect->width, rect->height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+ gint* right, gint* bottom, GtkTextDirection direction,
+ gboolean inhtml)
+{
+ GtkWidget* w;
+ GtkStyle *style;
+
+ switch (widget) {
+ case MOZ_GTK_BUTTON:
+ {
+ GtkBorder inner_border;
+ gboolean interior_focus;
+ gint focus_width, focus_pad;
+ GtkStyle *style;
+
+ ensure_button_widget();
+ *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gParts->buttonWidget));
+
+ /* Don't add this padding in HTML, otherwise the buttons will
+ become too big and stuff the layout. */
+ if (!inhtml) {
+ moz_gtk_widget_get_focus(gParts->buttonWidget, &interior_focus, &focus_width, &focus_pad);
+ moz_gtk_button_get_inner_border(gParts->buttonWidget, &inner_border);
+ *left += focus_width + focus_pad + inner_border.left;
+ *right += focus_width + focus_pad + inner_border.right;
+ *top += focus_width + focus_pad + inner_border.top;
+ *bottom += focus_width + focus_pad + inner_border.bottom;
+ }
+
+ style = gtk_widget_get_style(gParts->buttonWidget);
+ *left += style->xthickness;
+ *right += style->xthickness;
+ *top += style->ythickness;
+ *bottom += style->ythickness;
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_ENTRY:
+ ensure_entry_widget();
+ w = gParts->entryWidget;
+ break;
+ case MOZ_GTK_DROPDOWN:
+ {
+ /* We need to account for the arrow on the dropdown, so text
+ * doesn't come too close to the arrow, or in some cases spill
+ * into the arrow. */
+ gboolean ignored_interior_focus, wide_separators;
+ gint focus_width, focus_pad, separator_width;
+ GtkRequisition arrow_req;
+ GtkStyle* style;
+
+ ensure_combo_box_widgets();
+
+ *left = gtk_container_get_border_width(GTK_CONTAINER(gParts->comboBoxButtonWidget));
+
+ if (!inhtml) {
+ moz_gtk_widget_get_focus(gParts->comboBoxButtonWidget,
+ &ignored_interior_focus,
+ &focus_width, &focus_pad);
+ *left += focus_width + focus_pad;
+ }
+
+ style = gtk_widget_get_style(gParts->comboBoxButtonWidget);
+ *top = *left + style->ythickness;
+ *left += style->xthickness;
+
+ *right = *left; *bottom = *top;
+
+ /* If there is no separator, don't try to count its width. */
+ separator_width = 0;
+ if (gParts->comboBoxSeparatorWidget) {
+ gtk_widget_style_get(gParts->comboBoxSeparatorWidget,
+ "wide-separators", &wide_separators,
+ "separator-width", &separator_width,
+ NULL);
+
+ if (!wide_separators)
+ separator_width =
+ XTHICKNESS(style);
+ }
+
+ gtk_widget_get_preferred_size(gParts->comboBoxArrowWidget, &arrow_req, NULL);
+ if (direction == GTK_TEXT_DIR_RTL)
+ *left += separator_width + arrow_req.width;
+ else
+ *right += separator_width + arrow_req.width;
+
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_PROGRESSBAR:
+ ensure_progress_widget();
+ w = gParts->progresWidget;
+ break;
+ case MOZ_GTK_SCALE_HORIZONTAL:
+ ensure_scale_widget();
+ w = gParts->hScaleWidget;
+ break;
+ case MOZ_GTK_SCALE_VERTICAL:
+ ensure_scale_widget();
+ w = gParts->vScaleWidget;
+ break;
+ /* These widgets have no borders, since they are not containers. */
+ case MOZ_GTK_CHECKBUTTON:
+ case MOZ_GTK_RADIOBUTTON:
+ case MOZ_GTK_SCROLLBAR_BUTTON:
+ case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
+ case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
+ case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
+ case MOZ_GTK_SCALE_THUMB_VERTICAL:
+ case MOZ_GTK_PROGRESS_CHUNK:
+ *left = *top = *right = *bottom = 0;
+ return MOZ_GTK_SUCCESS;
+ default:
+ g_warning("Unsupported widget type: %d", widget);
+ return MOZ_GTK_UNKNOWN_WIDGET;
+ }
+
+ style = gtk_widget_get_style(w);
+ *right = *left = XTHICKNESS(style);
+ *bottom = *top = YTHICKNESS(style);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height)
+{
+ GtkWidget* widget;
+
+ ensure_scale_widget();
+ widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget);
+
+ gtk_widget_style_get (widget,
+ "slider_length", thumb_length,
+ "slider_width", thumb_height,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
+{
+ ensure_scrollbar_widget();
+
+ gtk_widget_style_get (gParts->horizScrollbarWidget,
+ "slider_width", &metrics->slider_width,
+ "trough_border", &metrics->trough_border,
+ "stepper_size", &metrics->stepper_size,
+ "stepper_spacing", &metrics->stepper_spacing,
+ "trough_under_steppers", &metrics->trough_under_steppers,
+ "has_secondary_forward_stepper", &metrics->has_secondary_forward_stepper,
+ "has_secondary_backward_stepper", &metrics->has_secondary_backward_stepper,
+ NULL);
+
+ metrics->min_slider_size = gtk_range_get_min_slider_size(GTK_RANGE(gParts->horizScrollbarWidget));
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t* cr,
+ GdkRectangle* rect, GtkWidgetState* state,
+ gint flags, GtkTextDirection direction)
+{
+ switch (widget) {
+ case MOZ_GTK_BUTTON:
+ if (state->depressed) {
+ ensure_toggle_button_widget();
+ return moz_gtk_button_paint(cr, rect, state,
+ (GtkReliefStyle) flags,
+ gParts->toggleButtonWidget, direction);
+ }
+ ensure_button_widget();
+ return moz_gtk_button_paint(cr, rect, state,
+ (GtkReliefStyle) flags, gParts->buttonWidget,
+ direction);
+ break;
+ case MOZ_GTK_CHECKBUTTON:
+ case MOZ_GTK_RADIOBUTTON:
+ return moz_gtk_toggle_paint(cr, rect, state,
+ !!(flags & MOZ_GTK_WIDGET_CHECKED),
+ !!(flags & MOZ_GTK_WIDGET_INCONSISTENT),
+ (widget == MOZ_GTK_RADIOBUTTON),
+ direction);
+ break;
+ case MOZ_GTK_SCROLLBAR_BUTTON:
+ return moz_gtk_scrollbar_button_paint(cr, rect, state,
+ (GtkScrollbarButtonFlags) flags,
+ direction);
+ break;
+ case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
+ return moz_gtk_scrollbar_trough_paint(widget, cr, rect,
+ state, direction);
+ break;
+ case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
+ return moz_gtk_scrollbar_thumb_paint(widget, cr, rect,
+ state, direction);
+ break;
+ case MOZ_GTK_SCROLLED_WINDOW:
+ return moz_gtk_scrolled_window_paint(cr, rect, state);
+ break;
+ case MOZ_GTK_SCALE_HORIZONTAL:
+ case MOZ_GTK_SCALE_VERTICAL:
+ return moz_gtk_scale_paint(cr, rect, state,
+ (GtkOrientation) flags, direction);
+ break;
+ case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
+ case MOZ_GTK_SCALE_THUMB_VERTICAL:
+ return moz_gtk_scale_thumb_paint(cr, rect, state,
+ (GtkOrientation) flags, direction);
+ break;
+ case MOZ_GTK_ENTRY:
+ ensure_entry_widget();
+ return moz_gtk_entry_paint(cr, rect, state,
+ gParts->entryWidget, direction);
+ break;
+ case MOZ_GTK_DROPDOWN:
+ return moz_gtk_combo_box_paint(cr, rect, state,
+ (gboolean) flags, direction);
+ break;
+ case MOZ_GTK_PROGRESSBAR:
+ return moz_gtk_progressbar_paint(cr, rect, direction);
+ break;
+ case MOZ_GTK_PROGRESS_CHUNK:
+ return moz_gtk_progress_chunk_paint(cr, rect, direction);
+ break;
+ default:
+ g_warning("Unknown widget type: %d", widget);
+ }
+
+ return MOZ_GTK_UNKNOWN_WIDGET;
+}
+
+GtkWidget* moz_gtk_get_scrollbar_widget(void)
+{
+ if (!is_initialized)
+ return NULL;
+ ensure_scrollbar_widget();
+ return gParts->horizScrollbarWidget;
+}
+
+gint
+moz_gtk_shutdown()
+{
+ GtkWidgetClass *entry_class;
+ entry_class = g_type_class_peek(GTK_TYPE_ENTRY);
+ g_type_class_unref(entry_class);
+
+ is_initialized = FALSE;
+
+ return MOZ_GTK_SUCCESS;
+}
+
+void moz_gtk_destroy_theme_parts_widgets(GtkThemeParts* parts)
+{
+ if (!parts)
+ return;
+
+ if (parts->protoWindow) {
+ gtk_widget_destroy(parts->protoWindow);
+ parts->protoWindow = NULL;
+ }
+}
+
+GtkWidget* moz_gtk_get_progress_widget()
+{
+ if (!is_initialized)
+ return NULL;
+ ensure_progress_widget();
+ return gParts->progresWidget;
+}
+
+#endif // GTK_API_VERSION_2
diff --git a/WebCore/platform/gtk/gtkdrawing.h b/WebCore/platform/gtk/gtkdrawing.h
index c00da97..a981543 100644
--- a/WebCore/platform/gtk/gtkdrawing.h
+++ b/WebCore/platform/gtk/gtkdrawing.h
@@ -81,7 +81,9 @@ typedef struct {
} MozGtkScrollbarMetrics;
typedef struct _GtkThemeParts {
+#ifdef GTK_API_VERSION_2
GdkColormap* colormap;
+#endif // GTK_API_VERSION_2
GtkWidget* protoWindow;
GtkWidget* protoLayout;
GtkWidget* buttonWidget;
@@ -91,7 +93,6 @@ typedef struct _GtkThemeParts {
GtkWidget* radiobuttonWidget;
GtkWidget* horizScrollbarWidget;
GtkWidget* vertScrollbarWidget;
- GtkWidget* spinWidget;
GtkWidget* hScaleWidget;
GtkWidget* vScaleWidget;
GtkWidget* entryWidget;
@@ -103,28 +104,7 @@ typedef struct _GtkThemeParts {
GtkWidget* comboBoxEntryTextareaWidget;
GtkWidget* comboBoxEntryButtonWidget;
GtkWidget* comboBoxEntryArrowWidget;
- GtkWidget* handleBoxWidget;
- GtkWidget* toolbarWidget;
- GtkWidget* frameWidget;
- GtkWidget* statusbarWidget;
GtkWidget* progresWidget;
- GtkWidget* tabWidget;
- GtkWidget* tooltipWidget;
- GtkWidget* menuBarWidget;
- GtkWidget* menuBarItemWidget;
- GtkWidget* menuPopupWidget;
- GtkWidget* menuItemWidget;
- GtkWidget* imageMenuItemWidget;
- GtkWidget* checkMenuItemWidget;
- GtkWidget* treeViewWidget;
- GtkTreeViewColumn* middleTreeViewColumn;
- GtkWidget* treeHeaderCellWidget;
- GtkWidget* treeHeaderSortArrowWidget;
- GtkWidget* expanderWidget;
- GtkWidget* toolbarSeparatorWidget;
- GtkWidget* menuSeparatorWidget;
- GtkWidget* hpanedWidget;
- GtkWidget* vpanedWidget;
GtkWidget* scrolledWindowWidget;
} GtkThemeParts;
@@ -134,24 +114,6 @@ typedef enum {
MOZ_GTK_STEPPER_VERTICAL = 1 << 2
} GtkScrollbarButtonFlags;
-/** flags for tab state **/
-typedef enum {
- /* first eight bits are used to pass a margin */
- MOZ_GTK_TAB_MARGIN_MASK = 0xFF,
- /* bottom tabs */
- MOZ_GTK_TAB_BOTTOM = 1 << 8,
- /* the first tab in the group */
- MOZ_GTK_TAB_FIRST = 1 << 9,
- /* the selected tab */
- MOZ_GTK_TAB_SELECTED = 1 << 10
-} GtkTabFlags;
-
-/** flags for menuitems **/
-typedef enum {
- /* menuitem is part of the menubar */
- MOZ_TOPLEVEL_MENU_ITEM = 1 << 0
-} GtkMenuItemFlags;
-
/* function type for moz_gtk_enable_style_props */
typedef gint (*style_prop_t)(GtkStyle*, const gchar*, gint);
@@ -191,80 +153,13 @@ typedef enum {
/* Paints a GtkScale thumb. */
MOZ_GTK_SCALE_THUMB_HORIZONTAL,
MOZ_GTK_SCALE_THUMB_VERTICAL,
- /* Paints a GtkSpinButton */
- MOZ_GTK_SPINBUTTON,
- MOZ_GTK_SPINBUTTON_UP,
- MOZ_GTK_SPINBUTTON_DOWN,
- MOZ_GTK_SPINBUTTON_ENTRY,
- /* Paints the gripper of a GtkHandleBox. */
- MOZ_GTK_GRIPPER,
- /* Paints a GtkEntry. */
MOZ_GTK_ENTRY,
- /* Paints the native caret (or in GTK-speak: insertion cursor) */
- MOZ_GTK_ENTRY_CARET,
/* Paints a GtkOptionMenu. */
MOZ_GTK_DROPDOWN,
- /* Paints a dropdown arrow (a GtkButton containing a down GtkArrow). */
- MOZ_GTK_DROPDOWN_ARROW,
- /* Paints an entry in an editable option menu */
- MOZ_GTK_DROPDOWN_ENTRY,
- /* Paints the container part of a GtkCheckButton. */
- MOZ_GTK_CHECKBUTTON_CONTAINER,
- /* Paints the container part of a GtkRadioButton. */
- MOZ_GTK_RADIOBUTTON_CONTAINER,
- /* Paints the label of a GtkCheckButton (focus outline) */
- MOZ_GTK_CHECKBUTTON_LABEL,
- /* Paints the label of a GtkRadioButton (focus outline) */
- MOZ_GTK_RADIOBUTTON_LABEL,
- /* Paints the background of a GtkHandleBox. */
- MOZ_GTK_TOOLBAR,
- /* Paints a toolbar separator */
- MOZ_GTK_TOOLBAR_SEPARATOR,
- /* Paints a GtkToolTip */
- MOZ_GTK_TOOLTIP,
- /* Paints a GtkFrame (e.g. a status bar panel). */
- MOZ_GTK_FRAME,
- /* Paints a resize grip for a GtkWindow */
- MOZ_GTK_RESIZER,
/* Paints a GtkProgressBar. */
MOZ_GTK_PROGRESSBAR,
/* Paints a progress chunk of a GtkProgressBar. */
- MOZ_GTK_PROGRESS_CHUNK,
- /* Paints a tab of a GtkNotebook. flags is a GtkTabFlags, defined above. */
- MOZ_GTK_TAB,
- /* Paints the background and border of a GtkNotebook. */
- MOZ_GTK_TABPANELS,
- /* Paints a GtkArrow for a GtkNotebook. flags is a GtkArrowType. */
- MOZ_GTK_TAB_SCROLLARROW,
- /* Paints the background and border of a GtkTreeView */
- MOZ_GTK_TREEVIEW,
- /* Paints treeheader cells */
- MOZ_GTK_TREE_HEADER_CELL,
- /* Paints sort arrows in treeheader cells */
- MOZ_GTK_TREE_HEADER_SORTARROW,
- /* Paints an expander for a GtkTreeView */
- MOZ_GTK_TREEVIEW_EXPANDER,
- /* Paints a GtkExpander */
- MOZ_GTK_EXPANDER,
- /* Paints the background of the menu bar. */
- MOZ_GTK_MENUBAR,
- /* Paints the background of menus, context menus. */
- MOZ_GTK_MENUPOPUP,
- /* Paints the arrow of menuitems that contain submenus */
- MOZ_GTK_MENUARROW,
- /* Paints an arrow that points down */
- MOZ_GTK_TOOLBARBUTTON_ARROW,
- /* Paints items of menubar and popups. */
- MOZ_GTK_MENUITEM,
- MOZ_GTK_CHECKMENUITEM,
- MOZ_GTK_RADIOMENUITEM,
- MOZ_GTK_MENUSEPARATOR,
- /* Paints a GtkVPaned separator */
- MOZ_GTK_SPLITTER_HORIZONTAL,
- /* Paints a GtkHPaned separator */
- MOZ_GTK_SPLITTER_VERTICAL,
- /* Paints the background of a window, dialog or page. */
- MOZ_GTK_WINDOW
+ MOZ_GTK_PROGRESS_CHUNK
} GtkThemeWidgetType;
/*** General library functions ***/
@@ -318,12 +213,18 @@ void moz_gtk_destroy_theme_parts_widgets(GtkThemeParts* parts);
* flags: widget-dependant flags; see the GtkThemeWidgetType definition.
* direction: the text direction, to draw the widget correctly LTR and RTL.
*/
+#ifdef GTK_API_VERSION_2
gint
moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
GdkRectangle* rect, GdkRectangle* cliprect,
GtkWidgetState* state, gint flags,
GtkTextDirection direction);
-
+#else
+gint
+moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t* cr,
+ GdkRectangle* rect, GtkWidgetState* state,
+ gint flags, GtkTextDirection direction);
+#endif
/*** Widget metrics ***/
/**
@@ -362,16 +263,6 @@ moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing);
gint
moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing);
-/**
- * Get the inner-border value for a GtkButton widget (button or tree header)
- * widget: [IN] the widget to get the border value for
- * inner_border: [OUT] the inner border
- *
- * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
- */
-gint
-moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border);
-
/** Get the focus metrics for a treeheadercell, button, checkbox, or radio button.
* widget: [IN] the widget to get the focus metrics for
* interior_focus: [OUT] whether the focus is drawn around the
@@ -406,91 +297,12 @@ gint
moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics* metrics);
/**
- * Get the desired size of a dropdown arrow button
- * width: [OUT] the desired width
- * height: [OUT] the desired height
- *
- * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
- */
-gint moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height);
-
-/**
- * Get the desired size of a scroll arrow widget
- * width: [OUT] the desired width
- * height: [OUT] the desired height
- *
- * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
- */
-gint moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height);
-
-/**
- * Get the desired size of a toolbar button dropdown arrow
- * width: [OUT] the desired width
- * height: [OUT] the desired height
- *
- * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
- */
-gint moz_gtk_get_downarrow_size(gint* width, gint* height);
-
-/**
- * Get the desired size of a toolbar separator
- * size: [OUT] the desired width
- *
- * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
- */
-gint moz_gtk_get_toolbar_separator_width(gint* size);
-
-/**
- * Get the size of a regular GTK expander that shows/hides content
- * size: [OUT] the size of the GTK expander, size = width = height.
- *
- * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
- */
-gint moz_gtk_get_expander_size(gint* size);
-
-/**
- * Get the size of a treeview's expander (we call them twisties)
- * size: [OUT] the size of the GTK expander, size = width = height.
- *
- * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
- */
-gint moz_gtk_get_treeview_expander_size(gint* size);
-
-/**
- * Get the desired height of a menu separator
- * size: [OUT] the desired height
- *
- * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
- */
-gint moz_gtk_get_menu_separator_height(gint* size);
-
-/**
- * Get the desired size of a splitter
- * orientation: [IN] GTK_ORIENTATION_HORIZONTAL or GTK_ORIENTATION_VERTICAL
- * size: [OUT] width or height of the splitter handle
- *
- * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
- */
-gint moz_gtk_splitter_get_metrics(gint orientation, gint* size);
-
-/**
* Retrieve an actual GTK scrollbar widget for style analysis. It will not
* be modified.
*/
GtkWidget* moz_gtk_get_scrollbar_widget(void);
/**
- * Get the YTHICKNESS of a tab (notebook extension).
- */
-gint moz_gtk_get_tab_thickness(void);
-
-/**
- * Get a boolean which indicates whether or not to use images in menus.
- * If TRUE, use images in menus.
- */
-gboolean moz_gtk_images_in_menus(void);
-
-/**
* Retrieve an actual GTK progress bar widget for style analysis. It will not
* be modified.
*/
diff --git a/WebCore/platform/image-decoders/ImageDecoder.cpp b/WebCore/platform/image-decoders/ImageDecoder.cpp
index 1c3dcf8..10c0b3b 100644
--- a/WebCore/platform/image-decoders/ImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/ImageDecoder.cpp
@@ -31,6 +31,7 @@
#include "ICOImageDecoder.h"
#include "JPEGImageDecoder.h"
#include "PNGImageDecoder.h"
+#include "WEBPImageDecoder.h"
#include "SharedBuffer.h"
using namespace std;
@@ -78,6 +79,19 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data, bool premultiplyAlp
if (!memcmp(contents, "\xFF\xD8\xFF", 3))
return new JPEGImageDecoder(premultiplyAlpha);
+#if USE(WEBP)
+ if (!memcmp(contents, "RIFF", 4)) {
+ static const unsigned webpExtraMarker = 6;
+ static const unsigned webpExtraMarkeroffset = 8;
+ char header[webpExtraMarker];
+ unsigned length = copyFromSharedBuffer(header, webpExtraMarker, data, webpExtraMarkeroffset);
+ if (length >= webpExtraMarker) {
+ if (!memcmp(header, "WEBPVP", webpExtraMarker))
+ return new WEBPImageDecoder(premultiplyAlpha);
+ }
+ }
+#endif
+
// BMP
if (strncmp(contents, "BM", 2) == 0)
return new BMPImageDecoder(premultiplyAlpha);
diff --git a/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp b/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp
new file mode 100644
index 0000000..5794fd6
--- /dev/null
+++ b/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp
@@ -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.
+ * 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 "WEBPImageDecoder.h"
+
+#if USE(WEBP)
+
+#include "webp/decode.h"
+
+namespace WebCore {
+
+WEBPImageDecoder::WEBPImageDecoder(bool premultiplyAlpha)
+ : ImageDecoder(premultiplyAlpha)
+{
+}
+
+WEBPImageDecoder::~WEBPImageDecoder()
+{
+}
+
+bool WEBPImageDecoder::isSizeAvailable()
+{
+ if (!ImageDecoder::isSizeAvailable())
+ decode(true);
+
+ return ImageDecoder::isSizeAvailable();
+}
+
+RGBA32Buffer* WEBPImageDecoder::frameBufferAtIndex(size_t index)
+{
+ if (index)
+ return 0;
+
+ if (m_frameBufferCache.isEmpty()) {
+ m_frameBufferCache.resize(1);
+ m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha);
+ }
+
+ RGBA32Buffer& frame = m_frameBufferCache[0];
+ if (frame.status() != RGBA32Buffer::FrameComplete)
+ decode(false);
+ return &frame;
+}
+
+
+bool WEBPImageDecoder::decode(bool onlySize)
+{
+ // Minimum number of bytes needed to ensure one can parse size information.
+ static const size_t sizeOfHeader = 30;
+ // Number of bytes per pixel.
+ static const int bytesPerPixel = 3;
+
+ if (failed())
+ return false;
+ const size_t dataSize = m_data->buffer().size();
+ const uint8_t* dataBytes =
+ reinterpret_cast<const uint8_t*>(m_data->buffer().data());
+ int width, height;
+ if (dataSize < sizeOfHeader)
+ return true;
+ if (!WebPGetInfo(dataBytes, dataSize, &width, &height))
+ return setFailed();
+ if (onlySize)
+ return setSize(width, height) || setFailed();
+
+ // FIXME: Add support for progressive decoding.
+ if (!isAllDataReceived())
+ return true;
+ if (m_frameBufferCache.isEmpty())
+ return true;
+ RGBA32Buffer& buffer = m_frameBufferCache[0];
+ if (buffer.status() == RGBA32Buffer::FrameEmpty) {
+ ASSERT(width == size().width());
+ ASSERT(height == size().height());
+ if (!buffer.setSize(width, height))
+ return setFailed();
+ }
+ const int stride = width * bytesPerPixel;
+ Vector<uint8_t> rgb;
+ rgb.reserveCapacity(height * stride);
+ if (!WebPDecodeBGRInto(dataBytes, dataSize, &rgb[0], height * stride, stride))
+ return setFailed();
+ // FIXME: remove this data copy.
+ for (int y = 0; y < height; ++y) {
+ const uint8_t* const src = &rgb[y * stride];
+ for (int x = 0; x < width; ++x)
+ buffer.setRGBA(x, y, src[bytesPerPixel * x + 2], src[bytesPerPixel * x + 1], src[bytesPerPixel * x + 0], 0xff);
+ }
+ buffer.setStatus(RGBA32Buffer::FrameComplete);
+ buffer.setHasAlpha(false);
+ buffer.setRect(IntRect(IntPoint(), size()));
+ return true;
+}
+
+}
+
+#endif
diff --git a/WebCore/platform/text/StringBuilder.h b/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h
index 72adfa7..266c0ff 100644
--- a/WebCore/platform/text/StringBuilder.h
+++ b/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 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
@@ -26,44 +26,31 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef StringBuilder_h
-#define StringBuilder_h
+#ifndef WEBPImageDecoder_h
+#define WEBPImageDecoder_h
-#include "PlatformString.h"
+#include "ImageDecoder.h"
-namespace WebCore {
+#if USE(WEBP)
-enum ConcatMode {
- ConcatUnaltered,
- ConcatAddingSpacesBetweenIndividualStrings
-};
+namespace WebCore {
-class StringBuilder {
+class WEBPImageDecoder : public ImageDecoder {
public:
- StringBuilder() : m_totalLength(UINT_MAX) {}
-
- void setNonNull()
- {
- if (m_totalLength == UINT_MAX)
- m_totalLength = 0;
- }
-
- void append(const String&);
- void append(UChar);
- void append(char);
-
- void clear();
- unsigned length() const;
-
- String toString(ConcatMode mode = ConcatUnaltered) const;
+ WEBPImageDecoder(bool premultiplyAlpha);
+ virtual ~WEBPImageDecoder();
+ virtual String filenameExtension() const { return "vp8"; }
+ virtual bool isSizeAvailable();
+ virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
+ virtual bool supportsAlpha() const { return false; }
private:
- bool isNull() const { return m_totalLength == UINT_MAX; }
-
- unsigned m_totalLength;
- Vector<String, 16> m_strings;
+ // Returns false in case of decoding failure.
+ bool decode(bool onlySize);
};
-}
+} // namespace WebCore
+
+#endif
#endif
diff --git a/WebCore/platform/mac/Language.mm b/WebCore/platform/mac/Language.mm
index 96caaa6..bb51cb5 100644
--- a/WebCore/platform/mac/Language.mm
+++ b/WebCore/platform/mac/Language.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2003, 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
@@ -10,32 +10,106 @@
* notice, this 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.
+ * 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.
*/
#import "config.h"
#import "Language.h"
#import "BlockExceptions.h"
-#import "PlatformString.h"
-#import "WebCoreViewFactory.h"
+#import "WebCoreSystemInterface.h"
+#import <wtf/Assertions.h>
+#import <wtf/MainThread.h>
+#import <wtf/text/WTFString.h>
+
+using namespace WebCore;
+
+static NSString *preferredLanguageCode;
+
+@interface LanguageChangeObserver : NSObject {
+}
+@end
+
+@implementation LanguageChangeObserver
+
++ (void)_webkit_languagePreferencesDidChange
+{
+ ASSERT(isMainThread());
+
+ [preferredLanguageCode release];
+ preferredLanguageCode = nil;
+
+ languageDidChange();
+}
+
+@end
namespace WebCore {
-String defaultLanguage()
+static NSString *createHTTPStyleLanguageCode(NSString *languageCode)
{
+ ASSERT(isMainThread());
+
+ // Look up the language code using CFBundle.
+ CFStringRef preferredLanguageCode = wkCopyCFLocalizationPreferredName((CFStringRef)languageCode);
+
+ if (preferredLanguageCode)
+ languageCode = (NSString *)preferredLanguageCode;
+
+ // Make the string lowercase.
+ NSString *lowercaseLanguageCode = [languageCode lowercaseString];
+
+ // Turn a '_' into a '-' if it appears after a 2-letter language code.
+ if ([lowercaseLanguageCode length] < 3 || [lowercaseLanguageCode characterAtIndex:2] != '_')
+ return lowercaseLanguageCode;
+
+ NSMutableString *result = [lowercaseLanguageCode mutableCopy];
+ [result replaceCharactersInRange:NSMakeRange(2, 1) withString:@"-"];
+
+ if (preferredLanguageCode)
+ CFRelease(preferredLanguageCode);
+
+ return result;
+}
+
+String platformDefaultLanguage()
+{
+ ASSERT(isMainThread());
+
BEGIN_BLOCK_OBJC_EXCEPTIONS;
- return [[WebCoreViewFactory sharedFactory] defaultLanguageCode];
+
+ if (!preferredLanguageCode) {
+ [[NSUserDefaults standardUserDefaults] synchronize];
+ NSArray *languages = [[NSUserDefaults standardUserDefaults] stringArrayForKey:@"AppleLanguages"];
+ if (![languages count])
+ preferredLanguageCode = @"en";
+ else
+ preferredLanguageCode = createHTTPStyleLanguageCode([languages objectAtIndex:0]);
+ }
+
+ NSString *code = [[preferredLanguageCode retain] autorelease];
+
+ static bool languageChangeObserverAdded;
+ if (!languageChangeObserverAdded) {
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:[LanguageChangeObserver self]
+ selector:@selector(_webkit_languagePreferencesDidChange)
+ name:@"AppleLanguagePreferencesChangedNotification"
+ object:nil];
+ languageChangeObserverAdded = true;
+ }
+
+ return code;
+
END_BLOCK_OBJC_EXCEPTIONS;
return String();
}
diff --git a/WebCore/platform/mac/LoggingMac.mm b/WebCore/platform/mac/LoggingMac.mm
index 3e83579..ee2f39e 100644
--- a/WebCore/platform/mac/LoggingMac.mm
+++ b/WebCore/platform/mac/LoggingMac.mm
@@ -62,6 +62,7 @@ void InitializeLoggingChannelsIfNecessary()
initializeWithUserDefault(LogHistory);
initializeWithUserDefault(LogPageCache);
initializeWithUserDefault(LogPlatformLeaks);
+ initializeWithUserDefault(LogResourceLoading);
initializeWithUserDefault(LogNetwork);
initializeWithUserDefault(LogFTP);
initializeWithUserDefault(LogThreading);
diff --git a/WebCore/platform/mac/ScrollbarThemeMac.mm b/WebCore/platform/mac/ScrollbarThemeMac.mm
index bfa584a..ce3be1a 100644
--- a/WebCore/platform/mac/ScrollbarThemeMac.mm
+++ b/WebCore/platform/mac/ScrollbarThemeMac.mm
@@ -378,10 +378,9 @@ bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, co
trackInfo.enableState = kThemeTrackNothingToScroll;
trackInfo.trackInfo.scrollbar.pressState = scrollbarPartToHIPressedState(scrollbar->pressedPart());
- CGAffineTransform currentCTM = CGContextGetCTM(context->platformContext());
-
// The Aqua scrollbar is buggy when rotated and scaled. We will just draw into a bitmap if we detect a scale or rotation.
- bool canDrawDirectly = currentCTM.a == 1.0f && currentCTM.b == 0.0f && currentCTM.c == 0.0f && (currentCTM.d == 1.0f || currentCTM.d == -1.0f);
+ const AffineTransform& currentCTM = context->getCTM();
+ bool canDrawDirectly = currentCTM.isIdentityOrTranslationOrFlipped();
if (canDrawDirectly)
HIThemeDrawTrack(&trackInfo, 0, context->platformContext(), kHIThemeOrientationNormal);
else {
@@ -396,7 +395,7 @@ bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, co
return true;
HIThemeDrawTrack(&trackInfo, 0, imageBuffer->context()->platformContext(), kHIThemeOrientationNormal);
- context->drawImageBuffer(imageBuffer.get(), DeviceColorSpace, scrollbar->frameRect().location());
+ context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, scrollbar->frameRect().location());
}
return true;
diff --git a/WebCore/platform/mac/SharedTimerMac.mm b/WebCore/platform/mac/SharedTimerMac.mm
index b9eaaef..cc9ff17 100644
--- a/WebCore/platform/mac/SharedTimerMac.mm
+++ b/WebCore/platform/mac/SharedTimerMac.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -26,51 +26,131 @@
#import "config.h"
#import "SharedTimer.h"
+#import <IOKit/IOMessage.h>
+#import <IOKit/pwr_mgt/IOPMLib.h>
#import <wtf/Assertions.h>
+#import <wtf/Noncopyable.h>
+#import <wtf/PassOwnPtr.h>
#import <wtf/UnusedParam.h>
-@class WebCorePowerNotifier;
+#include <stdio.h>
+
+// On Snow Leopard and newer we'll ask IOKit to deliver notifications on a queue.
+#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
+#define IOKIT_WITHOUT_LIBDISPATCH 1
+#endif
namespace WebCore {
-static WebCorePowerNotifier *powerNotifier;
static CFRunLoopTimerRef sharedTimer;
static void (*sharedTimerFiredFunction)();
static void timerFired(CFRunLoopTimerRef, void*);
+#if !defined(IOKIT_WITHOUT_LIBDISPATCH) && defined(BUILDING_ON_SNOW_LEOPARD)
+extern "C" void IONotificationPortSetDispatchQueue(IONotificationPortRef notify, dispatch_queue_t queue);
+#endif
+
+class PowerObserver {
+ WTF_MAKE_NONCOPYABLE(PowerObserver);
+
+public:
+ static PassOwnPtr<PowerObserver> create()
+ {
+ return adoptPtr(new PowerObserver);
+ }
+ ~PowerObserver();
+
+private:
+ PowerObserver();
+
+ static void didReceiveSystemPowerNotification(void* context, io_service_t, uint32_t messageType, void* messageArgument);
+ void didReceiveSystemPowerNotification(io_service_t, uint32_t messageType, void* messageArgument);
+
+ void restartSharedTimer();
+
+ io_connect_t m_powerConnection;
+ IONotificationPortRef m_notificationPort;
+ io_object_t m_notifierReference;
+#ifdef IOKIT_WITHOUT_LIBDISPATCH
+ CFRunLoopSourceRef m_runLoopSource;
+#else
+ dispatch_queue_t m_dispatchQueue;
+#endif
+};
+
+PowerObserver::PowerObserver()
+ : m_powerConnection(0)
+ , m_notificationPort(0)
+ , m_notifierReference(0)
+#ifdef IOKIT_WITHOUT_LIBDISPATCH
+ , m_runLoopSource(0)
+#else
+ , m_dispatchQueue(dispatch_queue_create("com.apple.WebKit.PowerObserver", 0))
+#endif
+{
+ m_powerConnection = IORegisterForSystemPower(this, &m_notificationPort, didReceiveSystemPowerNotification, &m_notifierReference);
+ if (!m_powerConnection)
+ return;
+
+#ifdef IOKIT_WITHOUT_LIBDISPATCH
+ m_runLoopSource = IONotificationPortGetRunLoopSource(m_notificationPort);
+ CFRunLoopAddSource(CFRunLoopGetMain(), m_runLoopSource, kCFRunLoopCommonModes);
+#else
+ IONotificationPortSetDispatchQueue(m_notificationPort, m_dispatchQueue);
+#endif
}
-@interface WebCorePowerNotifier : NSObject
-@end
+PowerObserver::~PowerObserver()
+{
+ if (!m_powerConnection)
+ return;
+
+#ifdef IOKIT_WITHOUT_LIBDISPATCH
+ CFRunLoopRemoveSource(CFRunLoopGetMain(), m_runLoopSource, kCFRunLoopCommonModes);
+#else
+ dispatch_release(m_dispatchQueue);
+#endif
+
+ IODeregisterForSystemPower(&m_notifierReference);
+ IOServiceClose(m_powerConnection);
+ IONotificationPortDestroy(m_notificationPort);
+}
-@implementation WebCorePowerNotifier
+void PowerObserver::didReceiveSystemPowerNotification(void* context, io_service_t service, uint32_t messageType, void* messageArgument)
+{
+ static_cast<PowerObserver*>(context)->didReceiveSystemPowerNotification(service, messageType, messageArgument);
+}
-- (id)init
+void PowerObserver::didReceiveSystemPowerNotification(io_service_t, uint32_t messageType, void* messageArgument)
{
- self = [super init];
-
- if (self)
- [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
- selector:@selector(didWake:)
- name:NSWorkspaceDidWakeNotification
- object:nil];
-
- return self;
+ IOAllowPowerChange(m_powerConnection, reinterpret_cast<long>(messageArgument));
+
+ // We only care about the "wake from sleep" message.
+ if (messageType != kIOMessageSystemWillPowerOn)
+ return;
+
+#ifdef IOKIT_WITHOUT_LIBDISPATCH
+ restartSharedTimer();
+#else
+ // We need to restart the timer on the main thread.
+ CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^() {
+ restartSharedTimer();
+ });
+#endif
}
-- (void)didWake:(NSNotification *)unusedNotification
+void PowerObserver::restartSharedTimer()
{
- UNUSED_PARAM(unusedNotification);
+ ASSERT(CFRunLoopGetCurrent() == CFRunLoopGetMain());
- if (WebCore::sharedTimer) {
- WebCore::stopSharedTimer();
- WebCore::timerFired(0, 0);
- }
-}
+ if (!sharedTimer)
+ return;
-@end
+ stopSharedTimer();
+ timerFired(0, 0);
+}
-namespace WebCore {
+static PowerObserver* PowerObserver;
void setSharedTimerFiredFunction(void (*f)())
{
@@ -100,11 +180,8 @@ void setSharedTimerFireTime(double fireTime)
sharedTimer = CFRunLoopTimerCreate(0, fireDate, 0, 0, 0, timerFired, 0);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), sharedTimer, kCFRunLoopCommonModes);
- if (!powerNotifier) {
- powerNotifier = [[WebCorePowerNotifier alloc] init];
- CFRetain(powerNotifier);
- [powerNotifier release];
- }
+ if (!PowerObserver)
+ PowerObserver = PowerObserver::create().leakPtr();
}
void stopSharedTimer()
@@ -116,4 +193,4 @@ void stopSharedTimer()
}
}
-}
+} // namespace WebCore
diff --git a/WebCore/platform/mac/WebCoreSystemInterface.h b/WebCore/platform/mac/WebCoreSystemInterface.h
index 0cc7fd5..7cac443 100644
--- a/WebCore/platform/mac/WebCoreSystemInterface.h
+++ b/WebCore/platform/mac/WebCoreSystemInterface.h
@@ -94,6 +94,7 @@ extern CFReadStreamRef (*wkCreateCustomCFReadStream)(void *(*formCreate)(CFReadS
void (*formSchedule)(CFReadStreamRef, CFRunLoopRef, CFStringRef, void *),
void (*formUnschedule)(CFReadStreamRef, CFRunLoopRef, CFStringRef, void *),
void *context);
+extern CFStringRef (*wkCopyCFLocalizationPreferredName)(CFStringRef);
extern NSString* (*wkCopyNSURLResponseStatusLine)(NSURLResponse*);
extern id (*wkCreateNSURLConnectionDelegateProxy)(void);
extern void (*wkDrawBezeledTextFieldCell)(NSRect, BOOL enabled);
diff --git a/WebCore/platform/mac/WebCoreSystemInterface.mm b/WebCore/platform/mac/WebCoreSystemInterface.mm
index 309a8fb..52e0064 100644
--- a/WebCore/platform/mac/WebCoreSystemInterface.mm
+++ b/WebCore/platform/mac/WebCoreSystemInterface.mm
@@ -29,6 +29,7 @@
void (*wkAdvanceDefaultButtonPulseAnimation)(NSButtonCell *);
BOOL (*wkCGContextGetShouldSmoothFonts)(CGContextRef);
+CFStringRef (*wkCopyCFLocalizationPreferredName)(CFStringRef);
NSString* (*wkCopyNSURLResponseStatusLine)(NSURLResponse*);
NSString* (*wkCreateURLPasteboardFlavorTypeName)(void);
NSString* (*wkCreateURLNPasteboardFlavorTypeName)(void);
diff --git a/WebCore/platform/network/BlobData.cpp b/WebCore/platform/network/BlobData.cpp
index 21e8917..ff39ecc 100644
--- a/WebCore/platform/network/BlobData.cpp
+++ b/WebCore/platform/network/BlobData.cpp
@@ -31,40 +31,46 @@
#include "config.h"
#include "BlobData.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
namespace WebCore {
const long long BlobDataItem::toEndOfFile = -1;
const double BlobDataItem::doNotCheckFileChange = 0;
-void BlobDataItem::copy(const BlobDataItem& item)
+RawData::RawData()
{
- type = item.type;
- data = item.data; // This is OK because the underlying storage is Vector<char>.
- path = item.path.crossThreadString();
- url = item.url.copy();
- offset = item.offset;
- length = item.length;
- expectedModificationTime = item.expectedModificationTime;
}
-PassOwnPtr<BlobData> BlobData::copy() const
+void RawData::detachFromCurrentThread()
{
- OwnPtr<BlobData> blobData = adoptPtr(new BlobData());
- blobData->m_contentType = m_contentType.crossThreadString();
- blobData->m_contentDisposition = m_contentDisposition.crossThreadString();
- blobData->m_items.resize(m_items.size());
- for (size_t i = 0; i < m_items.size(); ++i)
- blobData->m_items.at(i).copy(m_items.at(i));
+}
+
+void BlobDataItem::detachFromCurrentThread()
+{
+ data->detachFromCurrentThread();
+ path = path.crossThreadString();
+ url = url.copy();
+}
- return blobData.release();
+PassOwnPtr<BlobData> BlobData::create()
+{
+ return adoptPtr(new BlobData());
}
-void BlobData::appendData(const CString& data)
+void BlobData::detachFromCurrentThread()
{
- m_items.append(BlobDataItem(data));
+ m_contentType = m_contentType.crossThreadString();
+ m_contentDisposition = m_contentDisposition.crossThreadString();
+ for (size_t i = 0; i < m_items.size(); ++i)
+ m_items.at(i).detachFromCurrentThread();
}
-void BlobData::appendData(const CString& data, long long offset, long long length)
+void BlobData::appendData(PassRefPtr<RawData> data, long long offset, long long length)
{
m_items.append(BlobDataItem(data, offset, length));
}
diff --git a/WebCore/platform/network/BlobData.h b/WebCore/platform/network/BlobData.h
index 13e3b9c..1ff6344 100644
--- a/WebCore/platform/network/BlobData.h
+++ b/WebCore/platform/network/BlobData.h
@@ -33,12 +33,30 @@
#include "KURL.h"
#include "PlatformString.h"
-#include <wtf/PassOwnPtr.h>
-#include <wtf/Vector.h>
-#include <wtf/text/CString.h>
+#include <wtf/Forward.h>
+#include <wtf/ThreadSafeShared.h>
namespace WebCore {
+class RawData : public ThreadSafeShared<RawData> {
+public:
+ static PassRefPtr<RawData> create()
+ {
+ return adoptRef(new RawData());
+ }
+
+ void detachFromCurrentThread();
+
+ const char* data() const { return m_data.data(); }
+ size_t length() const { return m_data.size(); }
+ Vector<char>* mutableData() { return &m_data; }
+
+private:
+ RawData();
+
+ Vector<char> m_data;
+};
+
struct BlobDataItem {
static const long long toEndOfFile;
static const double doNotCheckFileChange;
@@ -53,7 +71,7 @@ struct BlobDataItem {
}
// Constructor for String type (complete string).
- explicit BlobDataItem(const CString& data)
+ explicit BlobDataItem(PassRefPtr<RawData> data)
: type(Data)
, data(data)
, offset(0)
@@ -62,16 +80,6 @@ struct BlobDataItem {
{
}
- // Constructor for String type (partial string).
- BlobDataItem(const CString& data, long long offset, long long length)
- : type(Data)
- , data(data)
- , offset(offset)
- , length(length)
- , expectedModificationTime(doNotCheckFileChange)
- {
- }
-
// Constructor for File type (complete file).
explicit BlobDataItem(const String& path)
: type(File)
@@ -102,13 +110,13 @@ struct BlobDataItem {
{
}
- // Gets a copy of the data suitable for passing to another thread.
- void copy(const BlobDataItem&);
+ // Detaches from current thread so that it can be passed to another thread.
+ void detachFromCurrentThread();
enum { Data, File, Blob } type;
// For Data type.
- CString data;
+ RefPtr<RawData> data;
// For File type.
String path;
@@ -119,19 +127,29 @@ struct BlobDataItem {
long long offset;
long long length;
double expectedModificationTime;
+
+private:
+ friend class BlobData;
+
+ // Constructor for String type (partial string).
+ BlobDataItem(PassRefPtr<RawData> data, long long offset, long long length)
+ : type(Data)
+ , data(data)
+ , offset(offset)
+ , length(length)
+ , expectedModificationTime(doNotCheckFileChange)
+ {
+ }
};
typedef Vector<BlobDataItem> BlobDataItemList;
class BlobData {
public:
- static PassOwnPtr<BlobData> create()
- {
- return adoptPtr(new BlobData());
- }
+ static PassOwnPtr<BlobData> create();
- // Gets a copy of the data suitable for passing to another thread.
- PassOwnPtr<BlobData> copy() const;
+ // Detaches from current thread so that it can be passed to another thread.
+ void detachFromCurrentThread();
const String& contentType() const { return m_contentType; }
void setContentType(const String& contentType) { m_contentType = contentType; }
@@ -141,8 +159,8 @@ public:
const BlobDataItemList& items() const { return m_items; }
void swapItems(BlobDataItemList&);
-
- void appendData(const CString&);
+
+ void appendData(PassRefPtr<RawData>, long long offset, long long length);
void appendFile(const String& path);
void appendFile(const String& path, long long offset, long long length, double expectedModificationTime);
void appendBlob(const KURL&, long long offset, long long length);
@@ -154,7 +172,7 @@ private:
BlobData() { }
// This is only exposed to BlobStorageData.
- void appendData(const CString&, long long offset, long long length);
+ void appendData(const RawData&, long long offset, long long length);
String m_contentType;
String m_contentDisposition;
diff --git a/WebCore/platform/network/BlobRegistryImpl.cpp b/WebCore/platform/network/BlobRegistryImpl.cpp
index c5beb64..2c4e8fa 100644
--- a/WebCore/platform/network/BlobRegistryImpl.cpp
+++ b/WebCore/platform/network/BlobRegistryImpl.cpp
@@ -134,7 +134,7 @@ void BlobRegistryImpl::registerBlobURL(const KURL& url, PassOwnPtr<BlobData> blo
for (BlobDataItemList::const_iterator iter = blobData->items().begin(); iter != blobData->items().end(); ++iter) {
switch (iter->type) {
case BlobDataItem::Data:
- blobStorageData->m_data.appendData(iter->data, 0, iter->data.length());
+ blobStorageData->m_data.appendData(iter->data, 0, iter->data->length());
break;
case BlobDataItem::File:
blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime);
@@ -158,10 +158,7 @@ void BlobRegistryImpl::registerBlobURL(const KURL& url, const KURL& srcURL)
if (!src)
return;
- RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(src->contentType(), src->contentDisposition());
- appendStorageItems(blobStorageData.get(), src->items());
-
- m_blobs.set(url.string(), blobStorageData);
+ m_blobs.set(url.string(), src);
}
void BlobRegistryImpl::unregisterBlobURL(const KURL& url)
diff --git a/WebCore/platform/network/BlobResourceHandle.cpp b/WebCore/platform/network/BlobResourceHandle.cpp
index 48ac2c0..753052a 100644
--- a/WebCore/platform/network/BlobResourceHandle.cpp
+++ b/WebCore/platform/network/BlobResourceHandle.cpp
@@ -359,7 +359,7 @@ int BlobResourceHandle::readDataSync(const BlobDataItem& item, char* buf, int le
int bytesToRead = (length > remaining) ? static_cast<int>(remaining) : length;
if (bytesToRead > m_totalRemainingSize)
bytesToRead = static_cast<int>(m_totalRemainingSize);
- memcpy(buf, item.data.data() + item.offset + m_currentItemReadSize, bytesToRead);
+ memcpy(buf, item.data->data() + item.offset + m_currentItemReadSize, bytesToRead);
m_totalRemainingSize -= bytesToRead;
m_currentItemReadSize += bytesToRead;
@@ -434,7 +434,7 @@ void BlobResourceHandle::readDataAsync(const BlobDataItem& item)
long long bytesToRead = item.length - m_currentItemReadSize;
if (bytesToRead > m_totalRemainingSize)
bytesToRead = m_totalRemainingSize;
- consumeData(item.data.data() + item.offset + m_currentItemReadSize, static_cast<int>(bytesToRead));
+ consumeData(item.data->data() + item.offset + m_currentItemReadSize, static_cast<int>(bytesToRead));
m_currentItemReadSize = 0;
}
diff --git a/WebCore/platform/network/CredentialStorage.cpp b/WebCore/platform/network/CredentialStorage.cpp
index 38f71a4..428181d 100644
--- a/WebCore/platform/network/CredentialStorage.cpp
+++ b/WebCore/platform/network/CredentialStorage.cpp
@@ -29,7 +29,7 @@
#include "Credential.h"
#include "KURL.h"
#include "ProtectionSpaceHash.h"
-#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
#include <wtf/text/StringHash.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
@@ -60,9 +60,9 @@ static PathToDefaultProtectionSpaceMap& pathToDefaultProtectionSpaceMap()
static String originStringFromURL(const KURL& url)
{
if (url.port())
- return url.protocol() + "://" + url.host() + String::format(":%i/", url.port());
-
- return url.protocol() + "://" + url.host() + "/";
+ return makeString(url.protocol(), "://", url.host(), ':', String::number(url.port()), '/');
+
+ return makeString(url.protocol(), "://", url.host(), '/');
}
static String protectionSpaceMapKeyFromURL(const KURL& url)
diff --git a/WebCore/platform/network/DataURL.cpp b/WebCore/platform/network/DataURL.cpp
new file mode 100644
index 0000000..5de1b34
--- /dev/null
+++ b/WebCore/platform/network/DataURL.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * 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 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 "DataURL.h"
+
+#include "Base64.h"
+#include "HTTPParsers.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include "TextEncoding.h"
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+void handleDataURL(ResourceHandle* handle)
+{
+ ASSERT(handle->firstRequest().url().protocolIs("data"));
+ String url = handle->firstRequest().url().string();
+
+ int index = url.find(',');
+ if (index == -1) {
+ handle->client()->cannotShowURL(handle);
+ return;
+ }
+
+ String mediaType = url.substring(5, index - 5);
+ String data = url.substring(index + 1);
+
+ bool base64 = mediaType.endsWith(";base64", false);
+ if (base64)
+ mediaType = mediaType.left(mediaType.length() - 7);
+
+ if (mediaType.isEmpty())
+ mediaType = "text/plain;charset=US-ASCII";
+
+ String mimeType = extractMIMETypeFromMediaType(mediaType);
+ String charset = extractCharsetFromMediaType(mediaType);
+
+ ResourceResponse response;
+ response.setMimeType(mimeType);
+ response.setTextEncodingName(charset);
+ response.setURL(handle->firstRequest().url());
+
+ if (base64) {
+ data = decodeURLEscapeSequences(data);
+ handle->client()->didReceiveResponse(handle, response);
+
+ Vector<char> out;
+ if (base64Decode(data, out, IgnoreWhitespace) && out.size() > 0) {
+ response.setExpectedContentLength(out.size());
+ handle->client()->didReceiveData(handle, out.data(), out.size(), 0);
+ }
+ } else {
+ data = decodeURLEscapeSequences(data, TextEncoding(charset));
+ handle->client()->didReceiveResponse(handle, response);
+
+ CString encodedData = TextEncoding().encode(data.characters(), data.length(), URLEncodedEntitiesForUnencodables);
+ response.setExpectedContentLength(encodedData.length());
+ if (encodedData.length())
+ handle->client()->didReceiveData(handle, encodedData.data(), encodedData.length(), 0);
+ }
+
+ handle->client()->didFinishLoading(handle, 0);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/DataURL.h b/WebCore/platform/network/DataURL.h
new file mode 100644
index 0000000..33076a0
--- /dev/null
+++ b/WebCore/platform/network/DataURL.h
@@ -0,0 +1,37 @@
+/*
+ * 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 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 DataURL_h
+#define DataURL_h
+
+namespace WebCore {
+
+class ResourceHandle;
+
+void handleDataURL(ResourceHandle*);
+
+}
+
+#endif // DataURL_h
diff --git a/WebCore/platform/network/HTTPHeaderMap.cpp b/WebCore/platform/network/HTTPHeaderMap.cpp
index e304ffa..92079a0 100644
--- a/WebCore/platform/network/HTTPHeaderMap.cpp
+++ b/WebCore/platform/network/HTTPHeaderMap.cpp
@@ -37,6 +37,14 @@ using namespace std;
namespace WebCore {
+HTTPHeaderMap::HTTPHeaderMap()
+{
+}
+
+HTTPHeaderMap::~HTTPHeaderMap()
+{
+}
+
PassOwnPtr<CrossThreadHTTPHeaderMapData> HTTPHeaderMap::copyData() const
{
OwnPtr<CrossThreadHTTPHeaderMapData> data(new CrossThreadHTTPHeaderMapData());
@@ -58,7 +66,17 @@ void HTTPHeaderMap::adopt(PassOwnPtr<CrossThreadHTTPHeaderMapData> data)
set(header.first, header.second);
}
}
-
+
+String HTTPHeaderMap::get(const AtomicString& name) const
+{
+ return HashMap<AtomicString, String, CaseFoldingHash>::get(name);
+}
+
+pair<HTTPHeaderMap::iterator, bool> HTTPHeaderMap::add(const AtomicString& name, const String& value)
+{
+ return HashMap<AtomicString, String, CaseFoldingHash>::add(name, value);
+}
+
// Adapter that allows the HashMap to take C strings as keys.
struct CaseFoldingCStringTranslator {
static unsigned hash(const char* cString)
diff --git a/WebCore/platform/network/HTTPHeaderMap.h b/WebCore/platform/network/HTTPHeaderMap.h
index c6145bd..02071e3 100644
--- a/WebCore/platform/network/HTTPHeaderMap.h
+++ b/WebCore/platform/network/HTTPHeaderMap.h
@@ -41,20 +41,17 @@ namespace WebCore {
class HTTPHeaderMap : public HashMap<AtomicString, String, CaseFoldingHash> {
public:
+ HTTPHeaderMap();
+ ~HTTPHeaderMap();
+
// Gets a copy of the data suitable for passing to another thread.
PassOwnPtr<CrossThreadHTTPHeaderMapData> copyData() const;
void adopt(PassOwnPtr<CrossThreadHTTPHeaderMapData>);
- String get(const AtomicString& name) const
- {
- return HashMap<AtomicString, String, CaseFoldingHash>::get(name);
- }
+ String get(const AtomicString& name) const;
- pair<iterator, bool> add(const AtomicString& name, const String& value)
- {
- return HashMap<AtomicString, String, CaseFoldingHash>::add(name, value);
- }
+ pair<iterator, bool> add(const AtomicString& name, const String& value);
// Alternate accessors that are faster than converting the char* to AtomicString first.
bool contains(const char*) const;
diff --git a/WebCore/platform/network/ProxyServer.cpp b/WebCore/platform/network/ProxyServer.cpp
new file mode 100644
index 0000000..7ef283b
--- /dev/null
+++ b/WebCore/platform/network/ProxyServer.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "ProxyServer.h"
+
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+static void appendProxyServerString(StringBuilder& builder, const ProxyServer& proxyServer)
+{
+ switch (proxyServer.type()) {
+ case ProxyServer::Direct:
+ builder.append("DIRECT");
+ return;
+ case ProxyServer::HTTP:
+ case ProxyServer::HTTPS:
+ builder.append("PROXY");
+ break;
+ case ProxyServer::SOCKS:
+ builder.append("SOCKS");
+ break;
+ }
+
+ builder.append(' ');
+
+ ASSERT(!proxyServer.hostName().isNull());
+ builder.append(proxyServer.hostName());
+
+ builder.append(':');
+ ASSERT(proxyServer.port() != -1);
+ builder.append(String::number(proxyServer.port()));
+}
+
+String toString(const Vector<ProxyServer>& proxyServers)
+{
+ if (proxyServers.isEmpty())
+ return "DIRECT";
+
+ StringBuilder stringBuilder;
+ for (size_t i = 0; i < proxyServers.size(); ++i) {
+ if (i)
+ stringBuilder.append("; ");
+
+ appendProxyServerString(stringBuilder, proxyServers[i]);
+ }
+
+ return stringBuilder.toString();
+}
+
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/ProxyServer.h b/WebCore/platform/network/ProxyServer.h
new file mode 100644
index 0000000..8f7612e
--- /dev/null
+++ b/WebCore/platform/network/ProxyServer.h
@@ -0,0 +1,79 @@
+/*
+ * 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 ProxyServer_h
+#define ProxyServer_h
+
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class KURL;
+class NetworkingContext;
+
+// Represents a single proxy server.
+class ProxyServer {
+public:
+ enum Type {
+ Direct,
+ HTTP,
+ HTTPS,
+ SOCKS,
+ };
+
+ ProxyServer()
+ : m_type(Direct)
+ , m_port(-1)
+ {
+ }
+
+ ProxyServer(Type type, const String& hostName, int port)
+ : m_type(type)
+ , m_hostName(hostName)
+ , m_port(port)
+ {
+ }
+
+ Type type() const { return m_type; }
+ const String& hostName() const { return m_hostName; }
+ int port() const { return m_port; }
+
+private:
+ Type m_type;
+ String m_hostName;
+ int m_port;
+};
+
+// Return a vector of proxy servers for the given URL.
+Vector<ProxyServer> proxyServersForURL(const KURL&, const NetworkingContext*);
+
+// Converts the given vector of proxy servers to a PAC string, as described in
+// http://web.archive.org/web/20060424005037/wp.netscape.com/eng/mozilla/2.0/relnotes/demo/proxy-live.html
+String toString(const Vector<ProxyServer>&);
+
+} // namespace WebCore
+
+#endif // ProxyServer_h
diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h
index 2ea42b1..bb94b59 100644
--- a/WebCore/platform/network/ResourceHandle.h
+++ b/WebCore/platform/network/ResourceHandle.h
@@ -94,16 +94,6 @@ class ResourceHandle : public RefCounted<ResourceHandle>
, public AuthenticationClient
#endif
{
-protected:
- ResourceHandle(const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff);
-
-private:
- enum FailureType {
- NoFailure,
- BlockedFailure,
- InvalidURLFailure
- };
-
public:
static PassRefPtr<ResourceHandle> create(NetworkingContext*, const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff);
static void loadResourceSynchronously(NetworkingContext*, const ResourceRequest&, StoredCredentials, ResourceError&, ResourceResponse&, Vector<char>& data);
@@ -203,7 +193,16 @@ public:
using RefCounted<ResourceHandle>::ref;
using RefCounted<ResourceHandle>::deref;
+protected:
+ ResourceHandle(const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff);
+
private:
+ enum FailureType {
+ NoFailure,
+ BlockedFailure,
+ InvalidURLFailure
+ };
+
void platformSetDefersLoading(bool);
void scheduleFailure(FailureType);
diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h
index 96fbf00..9cccecd 100644
--- a/WebCore/platform/network/ResourceHandleInternal.h
+++ b/WebCore/platform/network/ResourceHandleInternal.h
@@ -46,6 +46,8 @@
#endif
#if USE(SOUP)
+#include "soup-requester.h"
+#include <GRefPtr.h>
#include <libsoup/soup.h>
class Frame;
#endif
@@ -108,15 +110,11 @@ namespace WebCore {
, m_formDataStream(loader)
#endif
#if USE(SOUP)
- , m_msg(0)
, m_cancelled(false)
- , m_gfile(0)
- , m_inputStream(0)
- , m_cancellable(0)
, m_buffer(0)
- , m_bufferSize(0)
, m_total(0)
, m_idleHandler(0)
+ , m_gotChunkHandler(0)
#endif
#if PLATFORM(QT)
, m_job(0)
@@ -133,6 +131,9 @@ namespace WebCore {
m_user = url.user();
m_pass = url.pass();
m_firstRequest.removeCredentials();
+#if USE(SOUP)
+ m_requester = adoptPlatformRef(webkit_soup_requester_new());
+#endif
}
~ResourceHandleInternal();
@@ -185,16 +186,18 @@ namespace WebCore {
Vector<char> m_postBytes;
#endif
#if USE(SOUP)
- SoupMessage* m_msg;
+ PlatformRefPtr<SoupMessage> m_soupMessage;
ResourceResponse m_response;
bool m_cancelled;
- GFile* m_gfile;
- GInputStream* m_inputStream;
- GCancellable* m_cancellable;
+ PlatformRefPtr<WebKitSoupRequest> m_soupRequest;
+ PlatformRefPtr<WebKitSoupRequester> m_requester;
+ PlatformRefPtr<GInputStream> m_inputStream;
+ PlatformRefPtr<GCancellable> m_cancellable;
char* m_buffer;
- gsize m_bufferSize, m_total;
+ gsize m_total;
guint m_idleHandler;
RefPtr<NetworkingContext> m_context;
+ gulong m_gotChunkHandler;
#endif
#if PLATFORM(QT)
QNetworkReplyHandler* m_job;
diff --git a/WebCore/platform/network/ResourceRawHeaders.h b/WebCore/platform/network/ResourceRawHeaders.h
new file mode 100644
index 0000000..e5f8d99
--- /dev/null
+++ b/WebCore/platform/network/ResourceRawHeaders.h
@@ -0,0 +1,41 @@
+/*
+ * 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. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED 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 ResourceRawHeaders_h
+#define ResourceRawHeaders_h
+
+#include "HTTPHeaderMap.h"
+
+namespace WebCore {
+
+struct ResourceRawHeaders : RefCounted<ResourceRawHeaders> {
+ HTTPHeaderMap requestHeaders;
+ HTTPHeaderMap responseHeaders;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp
index fd8832f..5312007 100644
--- a/WebCore/platform/network/ResourceRequestBase.cpp
+++ b/WebCore/platform/network/ResourceRequestBase.cpp
@@ -65,6 +65,7 @@ PassOwnPtr<ResourceRequest> ResourceRequestBase::adopt(PassOwnPtr<CrossThreadRes
}
request->setHTTPBody(data->m_httpBody);
request->setAllowCookies(data->m_allowCookies);
+ request->doPlatformAdopt(data);
return request.release();
}
@@ -87,7 +88,7 @@ PassOwnPtr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const
if (m_httpBody)
data->m_httpBody = m_httpBody->deepCopy();
data->m_allowCookies = m_allowCookies;
- return data.release();
+ return asResourceRequest().doPlatformCopyData(data.release());
}
bool ResourceRequestBase::isEmpty() const
@@ -355,7 +356,7 @@ bool equalIgnoringHeaderFields(const ResourceRequestBase& a, const ResourceReque
return true;
}
-bool operator==(const ResourceRequestBase& a, const ResourceRequestBase& b)
+bool ResourceRequestBase::compare(const ResourceRequest& a, const ResourceRequest& b)
{
if (!equalIgnoringHeaderFields(a, b))
return false;
@@ -363,7 +364,7 @@ bool operator==(const ResourceRequestBase& a, const ResourceRequestBase& b)
if (a.httpHeaderFields() != b.httpHeaderFields())
return false;
- return true;
+ return ResourceRequest::platformCompare(a, b);
}
bool ResourceRequestBase::isConditional() const
diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h
index 1622cdd..33a184e 100644
--- a/WebCore/platform/network/ResourceRequestBase.h
+++ b/WebCore/platform/network/ResourceRequestBase.h
@@ -136,10 +136,16 @@ namespace WebCore {
bool reportLoadTiming() const { return m_reportLoadTiming; }
void setReportLoadTiming(bool reportLoadTiming) { m_reportLoadTiming = reportLoadTiming; }
+ // Whether actual headers being sent/received should be collected and reported for the request.
+ bool reportRawHeaders() const { return m_reportRawHeaders; }
+ void setReportRawHeaders(bool reportRawHeaders) { m_reportRawHeaders = reportRawHeaders; }
+
// What this request is for.
TargetType targetType() const { return m_targetType; }
void setTargetType(TargetType type) { m_targetType = type; }
+ static bool compare(const ResourceRequest&, const ResourceRequest&);
+
protected:
// Used when ResourceRequest is initialized from a platform representation of the request
ResourceRequestBase()
@@ -147,6 +153,7 @@ namespace WebCore {
, m_platformRequestUpdated(true)
, m_reportUploadProgress(false)
, m_reportLoadTiming(false)
+ , m_reportRawHeaders(false)
, m_targetType(TargetIsSubresource)
{
}
@@ -161,6 +168,7 @@ namespace WebCore {
, m_platformRequestUpdated(false)
, m_reportUploadProgress(false)
, m_reportLoadTiming(false)
+ , m_reportRawHeaders(false)
, m_targetType(TargetIsSubresource)
{
}
@@ -168,6 +176,9 @@ namespace WebCore {
void updatePlatformRequest() const;
void updateResourceRequest() const;
+ // The ResourceRequest subclass may "shadow" this method to compare platform specific fields
+ static bool platformCompare(const ResourceRequest&, const ResourceRequest&) { return true; }
+
KURL m_url;
ResourceRequestCachePolicy m_cachePolicy;
@@ -182,6 +193,7 @@ namespace WebCore {
mutable bool m_platformRequestUpdated;
bool m_reportUploadProgress;
bool m_reportLoadTiming;
+ bool m_reportRawHeaders;
TargetType m_targetType;
private:
@@ -190,10 +202,10 @@ namespace WebCore {
bool equalIgnoringHeaderFields(const ResourceRequestBase&, const ResourceRequestBase&);
- bool operator==(const ResourceRequestBase&, const ResourceRequestBase&);
- inline bool operator!=(ResourceRequestBase& a, const ResourceRequestBase& b) { return !(a == b); }
+ inline bool operator==(const ResourceRequest& a, const ResourceRequest& b) { return ResourceRequestBase::compare(a, b); }
+ inline bool operator!=(ResourceRequest& a, const ResourceRequest& b) { return !(a == b); }
- struct CrossThreadResourceRequestData : Noncopyable {
+ struct CrossThreadResourceRequestDataBase : Noncopyable {
KURL m_url;
ResourceRequestCachePolicy m_cachePolicy;
diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp
index e231652..a254168 100644
--- a/WebCore/platform/network/ResourceResponseBase.cpp
+++ b/WebCore/platform/network/ResourceResponseBase.cpp
@@ -39,6 +39,11 @@ namespace WebCore {
static void parseCacheHeader(const String& header, Vector<pair<String, String> >& result);
+inline const ResourceResponse& ResourceResponseBase::asResourceResponse() const
+{
+ return *static_cast<const ResourceResponse*>(this);
+}
+
ResourceResponseBase::ResourceResponseBase()
: m_expectedContentLength(0)
, m_httpStatusCode(0)
@@ -107,7 +112,7 @@ PassOwnPtr<ResourceResponse> ResourceResponseBase::adopt(PassOwnPtr<CrossThreadR
response->m_httpHeaderFields.adopt(data->m_httpHeaders.release());
response->setLastModifiedDate(data->m_lastModifiedDate);
response->setResourceLoadTiming(data->m_resourceLoadTiming.release());
-
+ response->doPlatformAdopt(data);
return response.release();
}
@@ -125,7 +130,7 @@ PassOwnPtr<CrossThreadResourceResponseData> ResourceResponseBase::copyData() con
data->m_lastModifiedDate = lastModifiedDate();
if (m_resourceLoadTiming)
data->m_resourceLoadTiming = m_resourceLoadTiming->deepCopy();
- return data.release();
+ return asResourceResponse().doPlatformCopyData(data.release());
}
bool ResourceResponseBase::isHTTP() const
@@ -515,6 +520,20 @@ void ResourceResponseBase::setResourceLoadTiming(PassRefPtr<ResourceLoadTiming>
m_resourceLoadTiming = resourceLoadTiming;
}
+PassRefPtr<ResourceRawHeaders> ResourceResponseBase::resourceRawHeaders() const
+{
+ lazyInit();
+
+ return m_resourceRawHeaders.get();
+}
+
+void ResourceResponseBase::setResourceRawHeaders(PassRefPtr<ResourceRawHeaders> headers)
+{
+ lazyInit();
+
+ m_resourceRawHeaders = headers;
+}
+
void ResourceResponseBase::lazyInit() const
{
const_cast<ResourceResponse*>(static_cast<const ResourceResponse*>(this))->platformLazyInit();
diff --git a/WebCore/platform/network/ResourceResponseBase.h b/WebCore/platform/network/ResourceResponseBase.h
index 65e24ad..4da13bb 100644
--- a/WebCore/platform/network/ResourceResponseBase.h
+++ b/WebCore/platform/network/ResourceResponseBase.h
@@ -30,6 +30,7 @@
#include "HTTPHeaderMap.h"
#include "KURL.h"
#include "ResourceLoadTiming.h"
+#include "ResourceRawHeaders.h"
#include <wtf/PassOwnPtr.h>
#include <wtf/RefPtr.h>
@@ -109,6 +110,9 @@ public:
ResourceLoadTiming* resourceLoadTiming() const;
void setResourceLoadTiming(PassRefPtr<ResourceLoadTiming>);
+ PassRefPtr<ResourceRawHeaders> resourceRawHeaders() const;
+ void setResourceRawHeaders(PassRefPtr<ResourceRawHeaders>);
+
// The ResourceResponse subclass may "shadow" this method to provide platform-specific memory usage information
unsigned memoryUsage() const
{
@@ -116,7 +120,7 @@ public:
return 1280;
}
- static bool compare(const ResourceResponse& a, const ResourceResponse& b);
+ static bool compare(const ResourceResponse&, const ResourceResponse&);
protected:
ResourceResponseBase();
@@ -143,10 +147,12 @@ protected:
unsigned m_connectionID;
bool m_connectionReused : 1;
RefPtr<ResourceLoadTiming> m_resourceLoadTiming;
+ RefPtr<ResourceRawHeaders> m_resourceRawHeaders;
bool m_isNull : 1;
private:
+ const ResourceResponse& asResourceResponse() const;
void parseCacheControlDirectives() const;
mutable bool m_haveParsedCacheControlHeader : 1;
@@ -169,7 +175,7 @@ private:
inline bool operator==(const ResourceResponse& a, const ResourceResponse& b) { return ResourceResponseBase::compare(a, b); }
inline bool operator!=(const ResourceResponse& a, const ResourceResponse& b) { return !(a == b); }
-struct CrossThreadResourceResponseData : Noncopyable {
+struct CrossThreadResourceResponseDataBase : Noncopyable {
KURL m_url;
String m_mimeType;
long long m_expectedContentLength;
diff --git a/WebCore/platform/network/android/ResourceRequest.h b/WebCore/platform/network/android/ResourceRequest.h
index 1edd4bf..745c2ef 100644
--- a/WebCore/platform/network/android/ResourceRequest.h
+++ b/WebCore/platform/network/android/ResourceRequest.h
@@ -53,6 +53,12 @@ public:
private:
friend class ResourceRequestBase;
+
+ PassOwnPtr<CrossThreadResourceRequestData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceRequestData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceRequestData>) { }
+};
+
+struct CrossThreadResourceRequestData : public CrossThreadResourceRequestDataBase {
};
} // namespace WebCore
diff --git a/WebCore/platform/network/android/ResourceResponse.h b/WebCore/platform/network/android/ResourceResponse.h
index e6ae2cc..78307b9 100644
--- a/WebCore/platform/network/android/ResourceResponse.h
+++ b/WebCore/platform/network/android/ResourceResponse.h
@@ -46,6 +46,12 @@ private:
{
notImplemented();
}
+
+ PassOwnPtr<CrossThreadResourceResponseData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData>) { }
+};
+
+struct CrossThreadResourceResponseData : public CrossThreadResourceResponseDataBase {
};
} // namespace WebCore
diff --git a/WebCore/platform/network/cf/ProxyServerCFNet.cpp b/WebCore/platform/network/cf/ProxyServerCFNet.cpp
new file mode 100644
index 0000000..3bef808
--- /dev/null
+++ b/WebCore/platform/network/cf/ProxyServerCFNet.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "ProxyServer.h"
+
+#include "KURL.h"
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+static void addProxyServersForURL(Vector<ProxyServer>& proxyServers, const KURL& url)
+{
+ RetainPtr<CFDictionaryRef> proxySettings(AdoptCF, CFNetworkCopySystemProxySettings());
+ if (!proxySettings)
+ return;
+
+ RetainPtr<CFURLRef> cfURL(AdoptCF, url.createCFURL());
+ RetainPtr<CFArrayRef> proxiesForURL(AdoptCF, CFNetworkCopyProxiesForURL(cfURL.get(), proxySettings.get()));
+ if (!proxiesForURL)
+ return;
+
+ CFIndex numProxies = CFArrayGetCount(proxiesForURL.get());
+ for (CFIndex i = 0; i < numProxies; ++i) {
+ CFDictionaryRef proxyDictionary = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(proxiesForURL.get(), i));
+
+ ProxyServer::Type type = ProxyServer::Direct;
+ CFStringRef typeString = static_cast<CFStringRef>(CFDictionaryGetValue(proxyDictionary, kCFProxyTypeKey));
+ if (CFEqual(typeString, kCFProxyTypeAutoConfigurationURL)) {
+ // FIXME: Handle PAC URLs.
+ continue;
+ }
+
+ if (CFEqual(typeString, kCFProxyTypeNone)) {
+ proxyServers.append(ProxyServer(ProxyServer::Direct, String(), -1));
+ continue;
+ }
+
+ if (CFEqual(typeString, kCFProxyTypeHTTP))
+ type = ProxyServer::HTTP;
+ else if (CFEqual(typeString, kCFProxyTypeHTTPS))
+ type = ProxyServer::HTTPS;
+ else if (CFEqual(typeString, kCFProxyTypeSOCKS))
+ type = ProxyServer::SOCKS;
+ else {
+ // We don't know how to handle this type.
+ continue;
+ }
+
+ CFStringRef host = static_cast<CFStringRef>(CFDictionaryGetValue(proxyDictionary, kCFProxyHostNameKey));
+ CFNumberRef port = static_cast<CFNumberRef>(CFDictionaryGetValue(proxyDictionary, kCFProxyPortNumberKey));
+ SInt32 portValue;
+ CFNumberGetValue(port, kCFNumberSInt32Type, &portValue);
+
+ proxyServers.append(ProxyServer(type, host, portValue));
+ }
+}
+
+Vector<ProxyServer> proxyServersForURL(const KURL& url, const NetworkingContext*)
+{
+ Vector<ProxyServer> proxyServers;
+
+ addProxyServersForURL(proxyServers, url);
+ return proxyServers;
+
+}
+#else
+Vector<ProxyServer> proxyServersForURL(const KURL&, const NetworkingContext*)
+{
+ // FIXME: Implement.
+ return Vector<ProxyServer>();
+}
+#endif
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/cf/ResourceRequest.h b/WebCore/platform/network/cf/ResourceRequest.h
index e361af5..9ed79f2 100644
--- a/WebCore/platform/network/cf/ResourceRequest.h
+++ b/WebCore/platform/network/cf/ResourceRequest.h
@@ -68,10 +68,16 @@ namespace WebCore {
void doUpdatePlatformRequest();
void doUpdateResourceRequest();
-
+
+ PassOwnPtr<CrossThreadResourceRequestData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceRequestData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceRequestData>) { }
+
RetainPtr<CFURLRequestRef> m_cfRequest;
};
+ struct CrossThreadResourceRequestData : public CrossThreadResourceRequestDataBase {
+ };
+
} // namespace WebCore
#endif // ResourceRequest_h
diff --git a/WebCore/platform/network/cf/ResourceResponse.h b/WebCore/platform/network/cf/ResourceResponse.h
index 04cc82c..5e27670 100644
--- a/WebCore/platform/network/cf/ResourceResponse.h
+++ b/WebCore/platform/network/cf/ResourceResponse.h
@@ -70,12 +70,18 @@ private:
friend class ResourceResponseBase;
void platformLazyInit();
+ PassOwnPtr<CrossThreadResourceResponseData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData>) { }
+
static bool platformCompare(const ResourceResponse& a, const ResourceResponse& b);
RetainPtr<CFURLResponseRef> m_cfResponse;
bool m_isUpToDate;
};
+struct CrossThreadResourceResponseData : public CrossThreadResourceResponseDataBase {
+};
+
} // namespace WebCore
#endif // ResourceResponse_h
diff --git a/WebCore/platform/network/cf/SocketStreamHandle.h b/WebCore/platform/network/cf/SocketStreamHandle.h
index 63bf9a7..8643db7 100644
--- a/WebCore/platform/network/cf/SocketStreamHandle.h
+++ b/WebCore/platform/network/cf/SocketStreamHandle.h
@@ -36,6 +36,7 @@
#include "SocketStreamHandleBase.h"
#include <wtf/RetainPtr.h>
+
namespace WebCore {
class AuthenticationChallenge;
diff --git a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp
index c66de33..800301a 100644
--- a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp
+++ b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp
@@ -194,8 +194,10 @@ void SocketStreamHandle::chooseProxy()
void SocketStreamHandle::chooseProxyFromArray(CFArrayRef proxyArray)
{
- if (!proxyArray)
+ if (!proxyArray) {
m_connectionType = Direct;
+ return;
+ }
CFIndex proxyArrayCount = CFArrayGetCount(proxyArray);
@@ -565,7 +567,7 @@ void SocketStreamHandle::writeStreamCallback(CFStreamEventType type)
break;
}
- ASSERT(m_state = Open);
+ ASSERT(m_state == Open);
ASSERT(m_connectingSubstate == Connected);
sendPendingData();
diff --git a/WebCore/platform/network/chromium/ResourceRequest.cpp b/WebCore/platform/network/chromium/ResourceRequest.cpp
index 016bd34..a33895a 100644
--- a/WebCore/platform/network/chromium/ResourceRequest.cpp
+++ b/WebCore/platform/network/chromium/ResourceRequest.cpp
@@ -37,4 +37,19 @@ unsigned initializeMaximumHTTPConnectionCountPerHost()
return 10000;
}
+PassOwnPtr<CrossThreadResourceRequestData> ResourceRequest::doPlatformCopyData(PassOwnPtr<CrossThreadResourceRequestData> data) const
+{
+ data->m_requestorID = m_requestorID;
+ data->m_requestorProcessID = m_requestorProcessID;
+ data->m_appCacheHostID = m_appCacheHostID;
+ return data;
+}
+
+void ResourceRequest::doPlatformAdopt(PassOwnPtr<CrossThreadResourceRequestData> data)
+{
+ m_requestorID = data->m_requestorID;
+ m_requestorProcessID = data->m_requestorProcessID;
+ m_appCacheHostID = data->m_appCacheHostID;
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/network/chromium/ResourceRequest.h b/WebCore/platform/network/chromium/ResourceRequest.h
index 8ef0c5e..8571cf4 100644
--- a/WebCore/platform/network/chromium/ResourceRequest.h
+++ b/WebCore/platform/network/chromium/ResourceRequest.h
@@ -90,6 +90,15 @@ namespace WebCore {
void doUpdatePlatformRequest() {}
void doUpdateResourceRequest() {}
+ PassOwnPtr<CrossThreadResourceRequestData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceRequestData>) const;
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceRequestData>);
+
+ int m_requestorID;
+ int m_requestorProcessID;
+ int m_appCacheHostID;
+ };
+
+ struct CrossThreadResourceRequestData : public CrossThreadResourceRequestDataBase {
int m_requestorID;
int m_requestorProcessID;
int m_appCacheHostID;
diff --git a/WebCore/platform/network/chromium/ResourceResponse.cpp b/WebCore/platform/network/chromium/ResourceResponse.cpp
new file mode 100644
index 0000000..acd44d3
--- /dev/null
+++ b/WebCore/platform/network/chromium/ResourceResponse.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Google, 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 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 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 "ResourceResponse.h"
+
+namespace WebCore {
+
+PassOwnPtr<CrossThreadResourceResponseData> ResourceResponse::doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData> data) const
+{
+ data->m_appCacheID = m_appCacheID;
+ data->m_appCacheManifestURL = m_appCacheManifestURL.copy();
+ data->m_isContentFiltered = m_isContentFiltered;
+ data->m_isMultipartPayload = m_isMultipartPayload;
+ data->m_wasFetchedViaSPDY = m_wasFetchedViaSPDY;
+ data->m_wasNpnNegotiated = m_wasNpnNegotiated;
+ data->m_wasAlternateProtocolAvailable = m_wasAlternateProtocolAvailable;
+ data->m_wasFetchedViaProxy = m_wasFetchedViaProxy;
+ data->m_responseTime = m_responseTime;
+ return data;
+}
+
+void ResourceResponse::doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData> data)
+{
+ m_appCacheID = data->m_appCacheID;
+ m_appCacheManifestURL = data->m_appCacheManifestURL.copy();
+ m_isContentFiltered = data->m_isContentFiltered;
+ m_isMultipartPayload = data->m_isMultipartPayload;
+ m_wasFetchedViaSPDY = data->m_wasFetchedViaSPDY;
+ m_wasNpnNegotiated = data->m_wasNpnNegotiated;
+ m_wasAlternateProtocolAvailable = data->m_wasAlternateProtocolAvailable;
+ m_wasFetchedViaProxy = data->m_wasFetchedViaProxy;
+ m_responseTime = data->m_responseTime;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/chromium/ResourceResponse.h b/WebCore/platform/network/chromium/ResourceResponse.h
index 852b9f5..5e99994 100644
--- a/WebCore/platform/network/chromium/ResourceResponse.h
+++ b/WebCore/platform/network/chromium/ResourceResponse.h
@@ -109,6 +109,9 @@ namespace WebCore {
notImplemented();
}
+ PassOwnPtr<CrossThreadResourceResponseData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData>) const;
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData>);
+
// The id of the appcache this response was retrieved from, or zero if
// the response was not retrieved from an appcache.
long long m_appCacheID;
@@ -142,6 +145,18 @@ namespace WebCore {
double m_responseTime;
};
+ struct CrossThreadResourceResponseData : public CrossThreadResourceResponseDataBase {
+ long long m_appCacheID;
+ KURL m_appCacheManifestURL;
+ bool m_isContentFiltered;
+ bool m_isMultipartPayload;
+ bool m_wasFetchedViaSPDY;
+ bool m_wasNpnNegotiated;
+ bool m_wasAlternateProtocolAvailable;
+ bool m_wasFetchedViaProxy;
+ double m_responseTime;
+ };
+
} // namespace WebCore
#endif
diff --git a/WebCore/platform/network/curl/ProxyServerCurl.cpp b/WebCore/platform/network/curl/ProxyServerCurl.cpp
new file mode 100644
index 0000000..212768a
--- /dev/null
+++ b/WebCore/platform/network/curl/ProxyServerCurl.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Brent Fulgham <bfulgham@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 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 "ProxyServer.h"
+
+#include "KURL.h"
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+Vector<ProxyServer> proxyServersForURL(const KURL&, const NetworkingContext*)
+{
+ // FIXME: Implement.
+ return Vector<ProxyServer>();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/curl/ResourceHandleCurl.cpp b/WebCore/platform/network/curl/ResourceHandleCurl.cpp
index 052ac56..f360f86 100644
--- a/WebCore/platform/network/curl/ResourceHandleCurl.cpp
+++ b/WebCore/platform/network/curl/ResourceHandleCurl.cpp
@@ -83,14 +83,6 @@ void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& err
m_error = error;
}
-
-static HashSet<String>& allowsAnyHTTPSCertificateHosts()
-{
- static HashSet<String> hosts;
-
- return hosts;
-}
-
ResourceHandleInternal::~ResourceHandleInternal()
{
fastFree(m_url);
@@ -133,6 +125,13 @@ bool ResourceHandle::supportsBufferedData()
}
#if PLATFORM(WIN) && PLATFORM(CF)
+static HashSet<String>& allowsAnyHTTPSCertificateHosts()
+{
+ static HashSet<String> hosts;
+
+ return hosts;
+}
+
void ResourceHandle::setHostAllowsAnyHTTPSCertificate(const String& host)
{
allowsAnyHTTPSCertificateHosts().add(host.lower());
diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp
index a4d71e0..2e4259c 100644
--- a/WebCore/platform/network/curl/ResourceHandleManager.cpp
+++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp
@@ -34,14 +34,13 @@
#include "config.h"
#include "ResourceHandleManager.h"
-#include "Base64.h"
+#include "DataURL.h"
#include "HTTPParsers.h"
#include "MIMETypeRegistry.h"
#include "NotImplemented.h"
#include "ResourceError.h"
#include "ResourceHandle.h"
#include "ResourceHandleInternal.h"
-#include "TextEncoding.h"
#include <errno.h>
#include <stdio.h>
@@ -121,8 +120,9 @@ static void curl_unlock_callback(CURL* handle, curl_lock_data data, void* userPt
ResourceHandleManager::ResourceHandleManager()
: m_downloadTimer(this, &ResourceHandleManager::downloadTimerCallback)
, m_cookieJarFileName(0)
- , m_runningJobs(0)
, m_certificatePath (certificatePath())
+ , m_runningJobs(0)
+
{
curl_global_init(CURL_GLOBAL_ALL);
m_curlMultiHandle = curl_multi_init();
@@ -164,7 +164,7 @@ static void handleLocalReceiveResponse (CURL* handle, ResourceHandle* job, Resou
// TODO: See if there is a better approach for handling this.
const char* hdr;
CURLcode err = curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &hdr);
- ASSERT(CURLE_OK == err);
+ ASSERT_UNUSED(err, CURLE_OK == err);
d->m_response.setURL(KURL(ParsedURLString, hdr));
if (d->client())
d->client()->didReceiveResponse(job, d->m_response);
@@ -372,7 +372,7 @@ void ResourceHandleManager::downloadTimerCallback(Timer<ResourceHandleManager>*
ASSERT(handle);
ResourceHandle* job = 0;
CURLcode err = curl_easy_getinfo(handle, CURLINFO_PRIVATE, &job);
- ASSERT(CURLE_OK == err);
+ ASSERT_UNUSED(err, CURLE_OK == err);
ASSERT(job);
if (!job)
continue;
@@ -572,67 +572,12 @@ bool ResourceHandleManager::startScheduledJobs()
return started;
}
-static void parseDataUrl(ResourceHandle* handle)
-{
- ResourceHandleClient* client = handle->client();
-
- ASSERT(client);
- if (!client)
- return;
-
- String url = handle->firstRequest().url().string();
- ASSERT(url.startsWith("data:", false));
-
- int index = url.find(',');
- if (index == -1) {
- client->cannotShowURL(handle);
- return;
- }
-
- String mediaType = url.substring(5, index - 5);
- String data = url.substring(index + 1);
-
- bool base64 = mediaType.endsWith(";base64", false);
- if (base64)
- mediaType = mediaType.left(mediaType.length() - 7);
-
- if (mediaType.isEmpty())
- mediaType = "text/plain;charset=US-ASCII";
-
- String mimeType = extractMIMETypeFromMediaType(mediaType);
- String charset = extractCharsetFromMediaType(mediaType);
-
- ResourceResponse response;
- response.setMimeType(mimeType);
-
- if (base64) {
- data = decodeURLEscapeSequences(data);
- response.setTextEncodingName(charset);
- client->didReceiveResponse(handle, response);
-
- // WebCore's decoder fails on Acid3 test 97 (whitespace).
- Vector<char> out;
- CString latin1 = data.latin1();
- if (base64Decode(latin1.data(), latin1.length(), out) && out.size() > 0)
- client->didReceiveData(handle, out.data(), out.size(), 0);
- } else {
- // We have to convert to UTF-16 early due to limitations in KURL
- data = decodeURLEscapeSequences(data, TextEncoding(charset));
- response.setTextEncodingName("UTF-16");
- client->didReceiveResponse(handle, response);
- if (data.length() > 0)
- client->didReceiveData(handle, reinterpret_cast<const char*>(data.characters()), data.length() * sizeof(UChar), 0);
- }
-
- client->didFinishLoading(handle, 0);
-}
-
void ResourceHandleManager::dispatchSynchronousJob(ResourceHandle* job)
{
KURL kurl = job->firstRequest().url();
- if (kurl.protocolIs("data")) {
- parseDataUrl(job);
+ if (kurl.protocolIsData()) {
+ handleDataURL(job);
return;
}
@@ -662,8 +607,8 @@ void ResourceHandleManager::startJob(ResourceHandle* job)
{
KURL kurl = job->firstRequest().url();
- if (kurl.protocolIs("data")) {
- parseDataUrl(job);
+ if (kurl.protocolIsData()) {
+ handleDataURL(job);
return;
}
@@ -711,7 +656,7 @@ void ResourceHandleManager::initializeHandle(ResourceHandle* job)
CURLcode error = curl_easy_pause(d->m_handle, CURLPAUSE_ALL);
// If we did not pause the handle, we would ASSERT in the
// header callback. So just assert here.
- ASSERT(error == CURLE_OK);
+ ASSERT_UNUSED(error, error == CURLE_OK);
}
#endif
#ifndef NDEBUG
diff --git a/WebCore/platform/network/curl/ResourceRequest.h b/WebCore/platform/network/curl/ResourceRequest.h
index 12dc214..c88501a 100644
--- a/WebCore/platform/network/curl/ResourceRequest.h
+++ b/WebCore/platform/network/curl/ResourceRequest.h
@@ -69,6 +69,12 @@ namespace WebCore {
void doUpdatePlatformRequest() {}
void doUpdateResourceRequest() {}
+
+ PassOwnPtr<CrossThreadResourceRequestData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceRequestData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceRequestData>) { }
+ };
+
+ struct CrossThreadResourceRequestData : public CrossThreadResourceRequestDataBase {
};
} // namespace WebCore
diff --git a/WebCore/platform/network/curl/ResourceResponse.h b/WebCore/platform/network/curl/ResourceResponse.h
index 860e902..49dd56c 100644
--- a/WebCore/platform/network/curl/ResourceResponse.h
+++ b/WebCore/platform/network/curl/ResourceResponse.h
@@ -28,7 +28,7 @@
#include "ResourceResponseBase.h"
-typedef const struct _CFURLResponse* CFURLResponseRef;
+typedef struct _CFURLResponse* CFURLResponseRef;
namespace WebCore {
@@ -52,9 +52,17 @@ public:
CFURLResponseRef cfURLResponse() const { return 0; }
private:
+ friend class ResourceResponseBase;
+
+ PassOwnPtr<CrossThreadResourceResponseData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData>) { }
+
bool m_responseFired;
};
+struct CrossThreadResourceResponseData : public CrossThreadResourceResponseDataBase {
+};
+
} // namespace WebCore
#endif // ResourceResponse_h
diff --git a/WebCore/platform/network/mac/FormDataStreamMac.mm b/WebCore/platform/network/mac/FormDataStreamMac.mm
index ed98356..9b5884f 100644
--- a/WebCore/platform/network/mac/FormDataStreamMac.mm
+++ b/WebCore/platform/network/mac/FormDataStreamMac.mm
@@ -424,7 +424,7 @@ void setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> formData)
for (size_t j = 0; j < blobData->items().size(); ++j) {
const BlobDataItem& blobItem = blobData->items()[j];
if (blobItem.type == BlobDataItem::Data) {
- newFormData->appendData(blobItem.data.data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
+ newFormData->appendData(blobItem.data->data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
} else {
ASSERT(blobItem.type == BlobDataItem::File);
newFormData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime);
diff --git a/WebCore/platform/network/mac/ResourceRequest.h b/WebCore/platform/network/mac/ResourceRequest.h
index b09e72d..ea0d13a 100644
--- a/WebCore/platform/network/mac/ResourceRequest.h
+++ b/WebCore/platform/network/mac/ResourceRequest.h
@@ -73,10 +73,16 @@ namespace WebCore {
void doUpdatePlatformRequest();
void doUpdateResourceRequest();
-
+
+ PassOwnPtr<CrossThreadResourceRequestData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceRequestData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceRequestData>) { }
+
RetainPtr<NSURLRequest> m_nsRequest;
};
+ struct CrossThreadResourceRequestData : public CrossThreadResourceRequestDataBase {
+ };
+
} // namespace WebCore
#endif // ResourceRequest_h
diff --git a/WebCore/platform/network/mac/ResourceResponse.h b/WebCore/platform/network/mac/ResourceResponse.h
index 16b0cbf..2867e9f 100644
--- a/WebCore/platform/network/mac/ResourceResponse.h
+++ b/WebCore/platform/network/mac/ResourceResponse.h
@@ -75,12 +75,19 @@ private:
friend class ResourceResponseBase;
void platformLazyInit();
+
+ PassOwnPtr<CrossThreadResourceResponseData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData>) { }
+
static bool platformCompare(const ResourceResponse& a, const ResourceResponse& b);
RetainPtr<NSURLResponse> m_nsResponse;
bool m_isUpToDate;
};
+struct CrossThreadResourceResponseData : public CrossThreadResourceResponseDataBase {
+};
+
} // namespace WebCore
#endif // ResourceResponse_h
diff --git a/WebCore/platform/network/qt/ProxyServerQt.cpp b/WebCore/platform/network/qt/ProxyServerQt.cpp
new file mode 100644
index 0000000..0bf3687
--- /dev/null
+++ b/WebCore/platform/network/qt/ProxyServerQt.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 "ProxyServer.h"
+
+#include "KURL.h"
+#include "NetworkingContext.h"
+
+#include <QNetworkAccessManager>
+#include <QNetworkProxy>
+#include <QNetworkProxyFactory>
+#include <QNetworkProxyQuery>
+#include <QUrl>
+
+namespace WebCore {
+
+Vector<ProxyServer> proxyServersForURL(const KURL& url, const NetworkingContext* context)
+{
+ Vector<ProxyServer> servers;
+
+ const QNetworkAccessManager* accessManager = context ? context->networkAccessManager() : 0;
+ QNetworkProxyFactory* proxyFactory = accessManager ? accessManager->proxyFactory() : 0;
+
+ if (proxyFactory) {
+ const QList<QNetworkProxy> proxies = proxyFactory->queryProxy(QNetworkProxyQuery(url));
+ Q_FOREACH(const QNetworkProxy& proxy, proxies) {
+ ProxyServer::Type proxyType;
+ switch (proxy.type()) {
+ case QNetworkProxy::Socks5Proxy:
+ proxyType = ProxyServer::SOCKS;
+ break;
+ case QNetworkProxy::HttpProxy:
+ case QNetworkProxy::HttpCachingProxy:
+ case QNetworkProxy::FtpCachingProxy:
+ proxyType = ProxyServer::HTTP;
+ break;
+ case QNetworkProxy::DefaultProxy:
+ case QNetworkProxy::NoProxy:
+ default:
+ proxyType = ProxyServer::Direct;
+ break;
+ }
+ servers.append(ProxyServer(proxyType, proxy.hostName(), proxy.port()));
+ }
+ }
+
+ return servers;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
index ca3af75..01e624e 100644
--- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
+++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
@@ -30,6 +30,7 @@
#include "ResourceRequest.h"
#include <QDateTime>
#include <QFile>
+#include <QFileInfo>
#include <QNetworkReply>
#include <QNetworkCookie>
#include <qwebframe.h>
@@ -59,11 +60,14 @@ FormDataIODevice::FormDataIODevice(FormData* data)
: m_formElements(data ? data->elements() : Vector<FormDataElement>())
, m_currentFile(0)
, m_currentDelta(0)
+ , m_fileSize(0)
+ , m_dataSize(0)
{
setOpenMode(FormDataIODevice::ReadOnly);
if (!m_formElements.isEmpty() && m_formElements[0].m_type == FormDataElement::encodedFile)
openFileForCurrentElement();
+ computeSize();
}
FormDataIODevice::~FormDataIODevice()
@@ -71,6 +75,20 @@ FormDataIODevice::~FormDataIODevice()
delete m_currentFile;
}
+qint64 FormDataIODevice::computeSize()
+{
+ for (int i = 0; i < m_formElements.size(); ++i) {
+ const FormDataElement& element = m_formElements[i];
+ if (element.m_type == FormDataElement::data)
+ m_dataSize += element.m_data.size();
+ else {
+ QFileInfo fi(element.m_filename);
+ m_fileSize += fi.size();
+ }
+ }
+ return m_dataSize + m_fileSize;
+}
+
void FormDataIODevice::moveToNextElement()
{
if (m_currentFile)
@@ -137,6 +155,29 @@ bool FormDataIODevice::isSequential() const
return true;
}
+String QNetworkReplyHandler::httpMethod() const
+{
+ switch (m_method) {
+ case QNetworkAccessManager::GetOperation:
+ return "GET";
+ case QNetworkAccessManager::HeadOperation:
+ return "HEAD";
+ case QNetworkAccessManager::PostOperation:
+ return "POST";
+ case QNetworkAccessManager::PutOperation:
+ return "PUT";
+ case QNetworkAccessManager::DeleteOperation:
+ return "DELETE";
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ case QNetworkAccessManager::CustomOperation:
+ return m_resourceHandle->firstRequest().httpMethod();
+#endif
+ default:
+ ASSERT_NOT_REACHED();
+ return "GET";
+ }
+}
+
QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode loadMode)
: QObject(0)
, m_reply(0)
@@ -164,11 +205,12 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load
else if (r.httpMethod() == "DELETE")
m_method = QNetworkAccessManager::DeleteOperation;
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
- else if (r.httpMethod() == "OPTIONS")
+ else
m_method = QNetworkAccessManager::CustomOperation;
-#endif
+#else
else
m_method = QNetworkAccessManager::UnknownOperation;
+#endif
QObject* originatingObject = 0;
if (m_resourceHandle->getInternal()->m_context)
@@ -359,13 +401,17 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
}
m_redirected = true;
- ResourceRequest newRequest = m_resourceHandle->firstRequest();
- newRequest.setURL(newUrl);
- if (((statusCode >= 301 && statusCode <= 303) || statusCode == 307) && newRequest.httpMethod() == "POST") {
+ // Status Code 301 (Moved Permanently), 302 (Moved Temporarily), 303 (See Other):
+ // - If original request is POST convert to GET and redirect automatically
+ // Status Code 307 (Temporary Redirect) and all other redirect status codes:
+ // - Use the HTTP method from the previous request
+ if ((statusCode >= 301 && statusCode <= 303) && m_resourceHandle->firstRequest().httpMethod() == "POST")
m_method = QNetworkAccessManager::GetOperation;
- newRequest.setHTTPMethod("GET");
- }
+
+ ResourceRequest newRequest = m_resourceHandle->firstRequest();
+ newRequest.setHTTPMethod(httpMethod());
+ newRequest.setURL(newUrl);
// Should not set Referer after a redirect from a secure resource to non-secure one.
if (!newRequest.url().protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https"))
@@ -453,6 +499,9 @@ void QNetworkReplyHandler::start()
break;
case QNetworkAccessManager::PostOperation: {
FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody());
+ // We may be uploading files so prevent QNR from buffering data
+ m_request.setHeader(QNetworkRequest::ContentLengthHeader, postDevice->getFormDataSize());
+ m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true));
m_reply = manager->post(m_request, postDevice);
postDevice->setParent(m_reply);
break;
@@ -462,6 +511,9 @@ void QNetworkReplyHandler::start()
break;
case QNetworkAccessManager::PutOperation: {
FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody());
+ // We may be uploading files so prevent QNR from buffering data
+ m_request.setHeader(QNetworkRequest::ContentLengthHeader, putDevice->getFormDataSize());
+ m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true));
m_reply = manager->put(m_request, putDevice);
putDevice->setParent(m_reply);
break;
diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h
index f6b2358..884a1a4 100644
--- a/WebCore/platform/network/qt/QNetworkReplyHandler.h
+++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h
@@ -67,6 +67,7 @@ private slots:
private:
void start();
void resetState();
+ String httpMethod() const;
QNetworkReply* m_reply;
ResourceHandle* m_resourceHandle;
@@ -97,6 +98,7 @@ public:
~FormDataIODevice();
bool isSequential() const;
+ qint64 getFormDataSize() const { return m_fileSize + m_dataSize; }
protected:
qint64 readData(char*, qint64);
@@ -104,12 +106,15 @@ protected:
private:
void moveToNextElement();
+ qint64 computeSize();
void openFileForCurrentElement();
private:
Vector<FormDataElement> m_formElements;
QFile* m_currentFile;
qint64 m_currentDelta;
+ qint64 m_fileSize;
+ qint64 m_dataSize;
};
}
diff --git a/WebCore/platform/network/qt/ResourceRequest.h b/WebCore/platform/network/qt/ResourceRequest.h
index fb69326..0c7b62b 100644
--- a/WebCore/platform/network/qt/ResourceRequest.h
+++ b/WebCore/platform/network/qt/ResourceRequest.h
@@ -66,6 +66,12 @@ namespace WebCore {
void doUpdatePlatformRequest() {}
void doUpdateResourceRequest() {}
+
+ PassOwnPtr<CrossThreadResourceRequestData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceRequestData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceRequestData>) { }
+ };
+
+ struct CrossThreadResourceRequestData : public CrossThreadResourceRequestDataBase {
};
} // namespace WebCore
diff --git a/WebCore/platform/network/qt/ResourceResponse.h b/WebCore/platform/network/qt/ResourceResponse.h
index 345ef25..288cf84 100644
--- a/WebCore/platform/network/qt/ResourceResponse.h
+++ b/WebCore/platform/network/qt/ResourceResponse.h
@@ -40,6 +40,15 @@ public:
: ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename)
{
}
+
+private:
+ friend class ResourceResponseBase;
+
+ PassOwnPtr<CrossThreadResourceResponseData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData>) { }
+};
+
+struct CrossThreadResourceResponseData : public CrossThreadResourceResponseDataBase {
};
} // namespace WebCore
diff --git a/WebCore/platform/network/qt/SocketStreamHandle.h b/WebCore/platform/network/qt/SocketStreamHandle.h
index 5c55749..e725344 100644
--- a/WebCore/platform/network/qt/SocketStreamHandle.h
+++ b/WebCore/platform/network/qt/SocketStreamHandle.h
@@ -38,6 +38,10 @@
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
+#if !PLATFORM(QT)
+#error This should only be built on Qt
+#endif
+
namespace WebCore {
class AuthenticationChallenge;
diff --git a/WebCore/platform/network/qt/SocketStreamHandlePrivate.h b/WebCore/platform/network/qt/SocketStreamHandlePrivate.h
index 235f1b1..d074f42 100644
--- a/WebCore/platform/network/qt/SocketStreamHandlePrivate.h
+++ b/WebCore/platform/network/qt/SocketStreamHandlePrivate.h
@@ -54,7 +54,7 @@ public slots:
void socketReadyRead();
int send(const char* data, int len);
void close();
- void socketSentdata();
+ void socketSentData();
void socketClosed();
void socketError(QAbstractSocket::SocketError);
void socketClosedCallback();
diff --git a/WebCore/platform/network/qt/SocketStreamHandleQt.cpp b/WebCore/platform/network/qt/SocketStreamHandleQt.cpp
index cc508b6..10550ae 100644
--- a/WebCore/platform/network/qt/SocketStreamHandleQt.cpp
+++ b/WebCore/platform/network/qt/SocketStreamHandleQt.cpp
@@ -110,7 +110,7 @@ void SocketStreamHandlePrivate::close()
m_socket->close();
}
-void SocketStreamHandlePrivate::socketSentdata()
+void SocketStreamHandlePrivate::socketSentData()
{
if (m_streamHandle)
m_streamHandle->sendPendingData();
diff --git a/WebCore/platform/network/soup/ProxyServerSoup.cpp b/WebCore/platform/network/soup/ProxyServerSoup.cpp
new file mode 100644
index 0000000..50b32de
--- /dev/null
+++ b/WebCore/platform/network/soup/ProxyServerSoup.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 Brent Fulgham <bfulgham@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 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 "ProxyServer.h"
+
+#include "KURL.h"
+
+namespace WebCore {
+
+Vector<ProxyServer> proxyServersForURL(const KURL&, const NetworkingContext*)
+{
+ // FIXME: Implement.
+ return Vector<ProxyServer>();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
index 0d84388..05c659f 100644
--- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp
+++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
@@ -45,8 +45,8 @@
#include "ResourceHandleInternal.h"
#include "ResourceResponse.h"
#include "SharedBuffer.h"
+#include "soup-request-http.h"
#include "TextEncoding.h"
-
#include <errno.h>
#include <fcntl.h>
#include <gio/gio.h>
@@ -58,6 +58,8 @@
namespace WebCore {
+#define READ_BUFFER_SIZE 8192
+
class WebCoreSynchronousLoader : public ResourceHandleClient, public Noncopyable {
public:
WebCoreSynchronousLoader(ResourceError&, ResourceResponse &, Vector<char>&);
@@ -120,16 +122,16 @@ void WebCoreSynchronousLoader::run()
g_main_loop_run(m_mainLoop);
}
-static void cleanupGioOperation(ResourceHandle* handle, bool isDestroying);
-static bool startData(ResourceHandle* handle, String urlString);
-static bool startGio(ResourceHandle* handle, KURL url);
+static void cleanupSoupRequestOperation(ResourceHandle*, bool isDestroying);
+static void sendRequestCallback(GObject*, GAsyncResult*, gpointer);
+static void readCallback(GObject*, GAsyncResult*, gpointer);
+static void closeCallback(GObject*, GAsyncResult*, gpointer);
+static bool startGio(ResourceHandle*, KURL);
ResourceHandleInternal::~ResourceHandleInternal()
{
- if (m_msg) {
- g_object_unref(m_msg);
- m_msg = 0;
- }
+ if (m_soupRequest)
+ g_object_set_data(G_OBJECT(m_soupRequest.get()), "webkit-resource", 0);
if (m_idleHandler) {
g_source_remove(m_idleHandler);
@@ -139,11 +141,7 @@ ResourceHandleInternal::~ResourceHandleInternal()
ResourceHandle::~ResourceHandle()
{
- if (d->m_msg)
- g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA,
- 0, 0, 0, 0, this);
-
- cleanupGioOperation(this, true);
+ cleanupSoupRequestOperation(this, true);
}
void ResourceHandle::prepareForURL(const KURL &url)
@@ -185,9 +183,8 @@ static void restartedCallback(SoupMessage* msg, gpointer data)
if (d->m_cancelled)
return;
- char* uri = soup_uri_to_string(soup_message_get_uri(msg), false);
- String location = String(uri);
- g_free(uri);
+ GOwnPtr<char> uri(soup_uri_to_string(soup_message_get_uri(msg), false));
+ String location = String::fromUTF8(uri.get());
KURL newURL = KURL(handle->firstRequest().url(), location);
ResourceRequest request = handle->firstRequest();
@@ -213,7 +210,7 @@ static void restartedCallback(SoupMessage* msg, gpointer data)
String firstPartyString = request.firstPartyForCookies().string();
if (!firstPartyString.isEmpty()) {
GOwnPtr<SoupURI> firstParty(soup_uri_new(firstPartyString.utf8().data()));
- soup_message_set_first_party(d->m_msg, firstParty.get());
+ soup_message_set_first_party(d->m_soupMessage.get(), firstParty.get());
}
#endif
}
@@ -221,8 +218,10 @@ static void restartedCallback(SoupMessage* msg, gpointer data)
static void gotHeadersCallback(SoupMessage* msg, gpointer data)
{
// For 401, we will accumulate the resource body, and only use it
- // in case authentication with the soup feature doesn't happen
- if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+ // in case authentication with the soup feature doesn't happen.
+ // For 302 we accumulate the body too because it could be used by
+ // some servers to redirect with a clunky http-equiv=REFRESH
+ if (statusWillBeHandledBySoup(msg->status_code)) {
soup_message_body_set_accumulate(msg->response_body, TRUE);
return;
}
@@ -295,51 +294,6 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data)
client->didReceiveData(handle.get(), chunk->data, chunk->length, false);
}
-// Called at the end of the message, with all the necessary about the last informations.
-// Doesn't get called for redirects.
-static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer data)
-{
- RefPtr<ResourceHandle> handle = adoptRef(static_cast<ResourceHandle*>(data));
- // TODO: maybe we should run this code even if there's no client?
- if (!handle)
- return;
-
- ResourceHandleInternal* d = handle->getInternal();
-
- ResourceHandleClient* client = handle->client();
- if (!client)
- return;
-
- if (d->m_cancelled)
- return;
-
- if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
- char* uri = soup_uri_to_string(soup_message_get_uri(msg), false);
- ResourceError error(g_quark_to_string(SOUP_HTTP_ERROR),
- msg->status_code,
- uri,
- String::fromUTF8(msg->reason_phrase));
- g_free(uri);
- client->didFail(handle.get(), error);
- return;
- }
-
- if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
- fillResponseFromMessage(msg, &d->m_response);
- client->didReceiveResponse(handle.get(), d->m_response);
-
- // WebCore might have cancelled the job in the while
- if (d->m_cancelled)
- return;
-
- if (msg->response_body->data)
- client->didReceiveData(handle.get(), msg->response_body->data, msg->response_body->length, true);
- }
-
- client->didFinishLoading(handle.get(), 0);
-}
-
-// parseDataUrl() is taken from the CURL http backend.
static gboolean parseDataUrl(gpointer callbackData)
{
ResourceHandle* handle = static_cast<ResourceHandle*>(callbackData);
@@ -364,7 +318,6 @@ static gboolean parseDataUrl(gpointer callbackData)
}
String mediaType = url.substring(5, index - 5);
- String data = url.substring(index + 1);
bool isBase64 = mediaType.endsWith(";base64", false);
if (isBase64)
@@ -380,42 +333,43 @@ static gboolean parseDataUrl(gpointer callbackData)
response.setURL(handle->firstRequest().url());
response.setMimeType(mimeType);
- if (isBase64) {
- data = decodeURLEscapeSequences(data);
- response.setTextEncodingName(charset);
- client->didReceiveResponse(handle, response);
-
- // The load may be cancelled, and the client may be destroyed
- // by any of the client reporting calls, so we check, and bail
- // out in either of those cases.
- if (d->m_cancelled || !handle->client())
- return false;
-
- // Use the GLib Base64, since WebCore's decoder isn't
- // general-purpose and fails on Acid3 test 97 (whitespace).
- size_t outLength = 0;
- char* outData = 0;
- outData = reinterpret_cast<char*>(g_base64_decode(data.utf8().data(), &outLength));
- if (outData && outLength > 0)
- client->didReceiveData(handle, outData, outLength, 0);
- g_free(outData);
- } else {
- // We have to convert to UTF-16 early due to limitations in KURL
- data = decodeURLEscapeSequences(data, TextEncoding(charset));
- response.setTextEncodingName("UTF-16");
- client->didReceiveResponse(handle, response);
-
- if (d->m_cancelled || !handle->client())
- return false;
-
- if (data.length() > 0)
- client->didReceiveData(handle, reinterpret_cast<const char*>(data.characters()), data.length() * sizeof(UChar), 0);
- }
+ // For non base64 encoded data we have to convert to UTF-16 early
+ // due to limitations in KURL
+ response.setTextEncodingName(isBase64 ? charset : "UTF-16");
+ client->didReceiveResponse(handle, response);
+ // The load may be cancelled, and the client may be destroyed
+ // by any of the client reporting calls, so we check, and bail
+ // out in either of those cases.
if (d->m_cancelled || !handle->client())
return false;
- client->didFinishLoading(handle, 0);
+ SoupSession* session = handle->defaultSession();
+ GOwnPtr<GError> error;
+ d->m_soupRequest = adoptPlatformRef(webkit_soup_requester_request(d->m_requester.get(), handle->firstRequest().url().string().utf8().data(), session, &error.outPtr()));
+ if (error) {
+ d->m_soupRequest = 0;
+ client->didFinishLoading(handle, 0);
+ return false;
+ }
+
+ d->m_inputStream = adoptPlatformRef(webkit_soup_request_send(d->m_soupRequest.get(), 0, &error.outPtr()));
+ if (error) {
+ d->m_inputStream = 0;
+ client->didFinishLoading(handle, 0);
+ return false;
+ }
+
+ d->m_buffer = static_cast<char*>(g_slice_alloc0(READ_BUFFER_SIZE));
+ d->m_total = 0;
+
+ g_object_set_data(G_OBJECT(d->m_inputStream.get()), "webkit-resource", handle);
+ // balanced by a deref() in cleanupSoupRequestOperation, which should always run
+ handle->ref();
+
+ d->m_cancellable = adoptPlatformRef(g_cancellable_new());
+ g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT,
+ d->m_cancellable.get(), readCallback, GINT_TO_POINTER(!isBase64));
return false;
}
@@ -469,6 +423,132 @@ static void ensureSessionIsInitialized(SoupSession* session)
g_object_set_data(G_OBJECT(session), "webkit-init", reinterpret_cast<void*>(0xdeadbeef));
}
+static void cleanupSoupRequestOperation(ResourceHandle* handle, bool isDestroying = false)
+{
+ ResourceHandleInternal* d = handle->getInternal();
+
+ if (d->m_soupRequest) {
+ g_object_set_data(G_OBJECT(d->m_soupRequest.get()), "webkit-resource", 0);
+ d->m_soupRequest.clear();
+ }
+
+ if (d->m_inputStream) {
+ g_object_set_data(G_OBJECT(d->m_inputStream.get()), "webkit-resource", 0);
+ d->m_inputStream.clear();
+ }
+
+ d->m_cancellable.clear();
+
+ if (d->m_soupMessage) {
+ g_signal_handlers_disconnect_matched(d->m_soupMessage.get(), G_SIGNAL_MATCH_DATA,
+ 0, 0, 0, 0, handle);
+ d->m_soupMessage.clear();
+ }
+
+ if (d->m_buffer) {
+ g_slice_free1(READ_BUFFER_SIZE, d->m_buffer);
+ d->m_buffer = 0;
+ }
+
+ if (!isDestroying)
+ handle->deref();
+}
+
+static void sendRequestCallback(GObject* source, GAsyncResult* res, gpointer userData)
+{
+ RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));
+ if (!handle)
+ return;
+
+ ResourceHandleInternal* d = handle->getInternal();
+ ResourceHandleClient* client = handle->client();
+
+ if (d->m_gotChunkHandler) {
+ // No need to call gotChunkHandler anymore. Received data will
+ // be reported by readCallback
+ if (g_signal_handler_is_connected(d->m_soupMessage.get(), d->m_gotChunkHandler))
+ g_signal_handler_disconnect(d->m_soupMessage.get(), d->m_gotChunkHandler);
+ }
+
+ if (d->m_cancelled || !client) {
+ cleanupSoupRequestOperation(handle.get());
+ return;
+ }
+
+ GOwnPtr<GError> error;
+ GInputStream* in = webkit_soup_request_send_finish(d->m_soupRequest.get(), res, &error.outPtr());
+
+ if (error) {
+ SoupMessage* soupMsg = d->m_soupMessage.get();
+ gboolean isTransportError = d->m_soupMessage && SOUP_STATUS_IS_TRANSPORT_ERROR(soupMsg->status_code);
+
+ if (isTransportError || (error->domain == G_IO_ERROR)) {
+ SoupURI* uri = webkit_soup_request_get_uri(d->m_soupRequest.get());
+ GOwnPtr<char> uriStr(soup_uri_to_string(uri, false));
+ gint errorCode = isTransportError ? soupMsg->status_code : error->code;
+ const gchar* errorMsg = isTransportError ? soupMsg->reason_phrase : error->message;
+ const gchar* quarkStr = isTransportError ? g_quark_to_string(SOUP_HTTP_ERROR) : g_quark_to_string(G_IO_ERROR);
+ ResourceError resourceError(quarkStr, errorCode, uriStr.get(), String::fromUTF8(errorMsg));
+
+ cleanupSoupRequestOperation(handle.get());
+ client->didFail(handle.get(), resourceError);
+ return;
+ }
+
+ if (d->m_soupMessage && statusWillBeHandledBySoup(d->m_soupMessage->status_code)) {
+ fillResponseFromMessage(soupMsg, &d->m_response);
+ client->didReceiveResponse(handle.get(), d->m_response);
+
+ // WebCore might have cancelled the job in the while
+ if (!d->m_cancelled && soupMsg->response_body->data)
+ client->didReceiveData(handle.get(), soupMsg->response_body->data, soupMsg->response_body->length, true);
+ }
+
+ // didReceiveData above might have cancelled it
+ if (d->m_cancelled || !client) {
+ cleanupSoupRequestOperation(handle.get());
+ return;
+ }
+
+ client->didFinishLoading(handle.get(), 0);
+ return;
+ }
+
+ if (d->m_cancelled) {
+ cleanupSoupRequestOperation(handle.get());
+ return;
+ }
+
+ d->m_inputStream = adoptPlatformRef(in);
+ d->m_buffer = static_cast<char*>(g_slice_alloc0(READ_BUFFER_SIZE));
+ d->m_total = 0;
+
+ // readCallback needs it
+ g_object_set_data(G_OBJECT(d->m_inputStream.get()), "webkit-resource", handle.get());
+
+ // We need to check if it's a file: URL and if it is a regular
+ // file as it could be a directory. In that case Soup properly
+ // returns a stream whose content is a HTML with a list of files
+ // in the directory
+ if (equalIgnoringCase(handle->firstRequest().url().protocol(), "file")
+ && G_IS_FILE_INPUT_STREAM(in)) {
+ ResourceResponse response;
+
+ response.setURL(handle->firstRequest().url());
+ response.setMimeType(webkit_soup_request_get_content_type(d->m_soupRequest.get()));
+ response.setExpectedContentLength(webkit_soup_request_get_content_length(d->m_soupRequest.get()));
+ client->didReceiveResponse(handle.get(), response);
+
+ if (d->m_cancelled) {
+ cleanupSoupRequestOperation(handle.get());
+ return;
+ }
+ }
+
+ g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE,
+ G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, 0);
+}
+
static bool startHttp(ResourceHandle* handle)
{
ASSERT(handle);
@@ -483,26 +563,37 @@ static bool startHttp(ResourceHandle* handle)
url.removeFragmentIdentifier();
request.setURL(url);
- d->m_msg = request.toSoupMessage();
- if (!d->m_msg)
+ GOwnPtr<GError> error;
+ d->m_soupRequest = adoptPlatformRef(webkit_soup_requester_request(d->m_requester.get(), url.string().utf8().data(), session, &error.outPtr()));
+ if (error) {
+ d->m_soupRequest = 0;
return false;
+ }
+
+ g_object_set_data(G_OBJECT(d->m_soupRequest.get()), "webkit-resource", handle);
+
+ d->m_soupMessage = adoptPlatformRef(webkit_soup_request_http_get_message(WEBKIT_SOUP_REQUEST_HTTP(d->m_soupRequest.get())));
+ if (!d->m_soupMessage)
+ return false;
+
+ SoupMessage* soupMessage = d->m_soupMessage.get();
+ request.updateSoupMessage(soupMessage);
if (!handle->shouldContentSniff())
- soup_message_disable_feature(d->m_msg, SOUP_TYPE_CONTENT_SNIFFER);
+ soup_message_disable_feature(soupMessage, SOUP_TYPE_CONTENT_SNIFFER);
- g_signal_connect(d->m_msg, "restarted", G_CALLBACK(restartedCallback), handle);
- g_signal_connect(d->m_msg, "got-headers", G_CALLBACK(gotHeadersCallback), handle);
- g_signal_connect(d->m_msg, "content-sniffed", G_CALLBACK(contentSniffedCallback), handle);
- g_signal_connect(d->m_msg, "got-chunk", G_CALLBACK(gotChunkCallback), handle);
+ g_signal_connect(soupMessage, "restarted", G_CALLBACK(restartedCallback), handle);
+ g_signal_connect(soupMessage, "got-headers", G_CALLBACK(gotHeadersCallback), handle);
+ g_signal_connect(soupMessage, "content-sniffed", G_CALLBACK(contentSniffedCallback), handle);
+ d->m_gotChunkHandler = g_signal_connect(soupMessage, "got-chunk", G_CALLBACK(gotChunkCallback), handle);
#ifdef HAVE_LIBSOUP_2_29_90
String firstPartyString = request.firstPartyForCookies().string();
if (!firstPartyString.isEmpty()) {
GOwnPtr<SoupURI> firstParty(soup_uri_new(firstPartyString.utf8().data()));
- soup_message_set_first_party(d->m_msg, firstParty.get());
+ soup_message_set_first_party(soupMessage, firstParty.get());
}
#endif
- g_object_set_data(G_OBJECT(d->m_msg), "resourceHandle", reinterpret_cast<void*>(handle));
FormData* httpBody = d->m_firstRequest.httpBody();
if (httpBody && !httpBody->isEmpty()) {
@@ -512,7 +603,7 @@ static bool startHttp(ResourceHandle* handle)
if (numElements < 2) {
Vector<char> body;
httpBody->flatten(body);
- soup_message_set_request(d->m_msg, d->m_firstRequest.httpContentType().utf8().data(),
+ soup_message_set_request(soupMessage, d->m_firstRequest.httpContentType().utf8().data(),
SOUP_MEMORY_COPY, body.data(), body.size());
} else {
/*
@@ -521,27 +612,25 @@ static bool startHttp(ResourceHandle* handle)
* copying into memory; TODO: support upload of non-local
* (think sftp://) files by using GIO?
*/
- soup_message_body_set_accumulate(d->m_msg->request_body, FALSE);
+ soup_message_body_set_accumulate(soupMessage->request_body, FALSE);
for (size_t i = 0; i < numElements; i++) {
const FormDataElement& element = httpBody->elements()[i];
if (element.m_type == FormDataElement::data)
- soup_message_body_append(d->m_msg->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size());
+ soup_message_body_append(soupMessage->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size());
else {
/*
* mapping for uploaded files code inspired by technique used in
* libsoup's simple-httpd test
*/
- GError* error = 0;
+ GOwnPtr<GError> error;
CString fileName = fileSystemRepresentation(element.m_filename);
- GMappedFile* fileMapping = g_mapped_file_new(fileName.data(), false, &error);
+ GMappedFile* fileMapping = g_mapped_file_new(fileName.data(), false, &error.outPtr());
if (error) {
- g_error_free(error);
- g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA,
+ g_signal_handlers_disconnect_matched(soupMessage, G_SIGNAL_MATCH_DATA,
0, 0, 0, 0, handle);
- g_object_unref(d->m_msg);
- d->m_msg = 0;
+ d->m_soupMessage.clear();
return false;
}
@@ -549,38 +638,31 @@ static bool startHttp(ResourceHandle* handle)
SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping),
g_mapped_file_get_length(fileMapping),
fileMapping,
-#if GLIB_CHECK_VERSION(2, 21, 3)
reinterpret_cast<GDestroyNotify>(g_mapped_file_unref));
-#else
- reinterpret_cast<GDestroyNotify>(g_mapped_file_free));
-#endif
- soup_message_body_append_buffer(d->m_msg->request_body, soupBuffer);
+ soup_message_body_append_buffer(soupMessage->request_body, soupBuffer);
soup_buffer_free(soupBuffer);
}
}
}
}
- // balanced by a deref() in finishedCallback, which should always run
+ // balanced by a deref() in cleanupSoupRequestOperation, which should always run
handle->ref();
// Make sure we have an Accept header for subresources; some sites
// want this to serve some of their subresources
- if (!soup_message_headers_get_one(d->m_msg->request_headers, "Accept"))
- soup_message_headers_append(d->m_msg->request_headers, "Accept", "*/*");
+ if (!soup_message_headers_get_one(soupMessage->request_headers, "Accept"))
+ soup_message_headers_append(soupMessage->request_headers, "Accept", "*/*");
- // Balanced in ResourceHandleInternal's destructor; we need to
- // keep our own ref, because after queueing the message, the
- // session owns the initial reference.
- g_object_ref(d->m_msg);
- soup_session_queue_message(session, d->m_msg, finishedCallback, handle);
+ d->m_cancellable = adoptPlatformRef(g_cancellable_new());
+ webkit_soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, 0);
return true;
}
bool ResourceHandle::start(NetworkingContext* context)
{
- ASSERT(!d->m_msg);
+ ASSERT(!d->m_soupMessage);
// The frame could be null if the ResourceHandle is not associated to any
// Frame, e.g. if we are downloading a file.
@@ -620,10 +702,10 @@ bool ResourceHandle::start(NetworkingContext* context)
void ResourceHandle::cancel()
{
d->m_cancelled = true;
- if (d->m_msg)
- soup_session_cancel_message(defaultSession(), d->m_msg, SOUP_STATUS_CANCELLED);
+ if (d->m_soupMessage)
+ soup_session_cancel_message(defaultSession(), d->m_soupMessage.get(), SOUP_STATUS_CANCELLED);
else if (d->m_cancellable)
- g_cancellable_cancel(d->m_cancellable);
+ g_cancellable_cancel(d->m_cancellable.get());
}
PassRefPtr<SharedBuffer> ResourceHandle::bufferedData()
@@ -667,38 +749,6 @@ void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const
syncLoader.run();
}
-// GIO-based loader
-
-static void cleanupGioOperation(ResourceHandle* handle, bool isDestroying = false)
-{
- ResourceHandleInternal* d = handle->getInternal();
-
- if (d->m_gfile) {
- g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", 0);
- g_object_unref(d->m_gfile);
- d->m_gfile = 0;
- }
-
- if (d->m_cancellable) {
- g_object_unref(d->m_cancellable);
- d->m_cancellable = 0;
- }
-
- if (d->m_inputStream) {
- g_object_set_data(G_OBJECT(d->m_inputStream), "webkit-resource", 0);
- g_object_unref(d->m_inputStream);
- d->m_inputStream = 0;
- }
-
- if (d->m_buffer) {
- g_free(d->m_buffer);
- d->m_buffer = 0;
- }
-
- if (!isDestroying)
- handle->deref();
-}
-
static void closeCallback(GObject* source, GAsyncResult* res, gpointer)
{
RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));
@@ -708,8 +758,8 @@ static void closeCallback(GObject* source, GAsyncResult* res, gpointer)
ResourceHandleInternal* d = handle->getInternal();
ResourceHandleClient* client = handle->client();
- g_input_stream_close_finish(d->m_inputStream, res, 0);
- cleanupGioOperation(handle.get());
+ g_input_stream_close_finish(d->m_inputStream.get(), res, 0);
+ cleanupSoupRequestOperation(handle.get());
// The load may have been cancelled, the client may have been
// destroyed already. In such cases calling didFinishLoading is a
@@ -720,210 +770,92 @@ static void closeCallback(GObject* source, GAsyncResult* res, gpointer)
client->didFinishLoading(handle.get(), 0);
}
-static void readCallback(GObject* source, GAsyncResult* res, gpointer)
+static void readCallback(GObject* source, GAsyncResult* asyncResult, gpointer data)
{
RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));
if (!handle)
return;
+ bool convertToUTF16 = static_cast<bool>(data);
ResourceHandleInternal* d = handle->getInternal();
ResourceHandleClient* client = handle->client();
if (d->m_cancelled || !client) {
- cleanupGioOperation(handle.get());
+ cleanupSoupRequestOperation(handle.get());
return;
}
- GError* error = 0;
+ GOwnPtr<GError> error;
- gssize bytesRead = g_input_stream_read_finish(d->m_inputStream, res, &error);
+ gssize bytesRead = g_input_stream_read_finish(d->m_inputStream.get(), asyncResult, &error.outPtr());
if (error) {
- char* uri = g_file_get_uri(d->m_gfile);
- ResourceError resourceError(g_quark_to_string(G_IO_ERROR),
- error->code,
- uri,
+ SoupURI* uri = webkit_soup_request_get_uri(d->m_soupRequest.get());
+ GOwnPtr<char> uriStr(soup_uri_to_string(uri, false));
+ ResourceError resourceError(g_quark_to_string(G_IO_ERROR), error->code, uriStr.get(),
error ? String::fromUTF8(error->message) : String());
- g_free(uri);
- g_error_free(error);
- cleanupGioOperation(handle.get());
+ cleanupSoupRequestOperation(handle.get());
client->didFail(handle.get(), resourceError);
return;
}
if (!bytesRead) {
- g_input_stream_close_async(d->m_inputStream, G_PRIORITY_DEFAULT,
+ g_input_stream_close_async(d->m_inputStream.get(), G_PRIORITY_DEFAULT,
0, closeCallback, 0);
return;
}
d->m_total += bytesRead;
- client->didReceiveData(handle.get(), d->m_buffer, bytesRead, d->m_total);
-
- // didReceiveData may cancel the load, which may release the last reference.
- if (d->m_cancelled) {
- cleanupGioOperation(handle.get());
- return;
+ if (G_LIKELY(!convertToUTF16))
+ client->didReceiveData(handle.get(), d->m_buffer, bytesRead, d->m_total);
+ else {
+ // We have to convert it to UTF-16 due to limitations in KURL
+ String data = String::fromUTF8(d->m_buffer, bytesRead);
+ client->didReceiveData(handle.get(), reinterpret_cast<const char*>(data.characters()), data.length() * sizeof(UChar), 0);
}
- g_input_stream_read_async(d->m_inputStream, d->m_buffer, d->m_bufferSize,
- G_PRIORITY_DEFAULT, d->m_cancellable,
- readCallback, 0);
-}
-
-static void openCallback(GObject* source, GAsyncResult* res, gpointer)
-{
- RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));
- if (!handle)
- return;
-
- ResourceHandleInternal* d = handle->getInternal();
- ResourceHandleClient* client = handle->client();
-
+ // didReceiveData may cancel the load, which may release the last reference.
if (d->m_cancelled || !client) {
- cleanupGioOperation(handle.get());
- return;
- }
-
- GError* error = 0;
- GFileInputStream* in = g_file_read_finish(G_FILE(source), res, &error);
- if (error) {
- char* uri = g_file_get_uri(d->m_gfile);
- ResourceError resourceError(g_quark_to_string(G_IO_ERROR),
- error->code,
- uri,
- error ? String::fromUTF8(error->message) : String());
- g_free(uri);
- g_error_free(error);
- cleanupGioOperation(handle.get());
- client->didFail(handle.get(), resourceError);
+ cleanupSoupRequestOperation(handle.get());
return;
}
- d->m_inputStream = G_INPUT_STREAM(in);
- d->m_bufferSize = 8192;
- d->m_buffer = static_cast<char*>(g_malloc(d->m_bufferSize));
- d->m_total = 0;
-
- g_object_set_data(G_OBJECT(d->m_inputStream), "webkit-resource", handle.get());
- g_input_stream_read_async(d->m_inputStream, d->m_buffer, d->m_bufferSize,
- G_PRIORITY_DEFAULT, d->m_cancellable,
- readCallback, 0);
+ g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT,
+ d->m_cancellable.get(), readCallback, data);
}
-static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer)
-{
- RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));
- if (!handle)
- return;
-
- ResourceHandleInternal* d = handle->getInternal();
- ResourceHandleClient* client = handle->client();
-
- if (d->m_cancelled) {
- cleanupGioOperation(handle.get());
- return;
- }
-
- ResourceResponse response;
-
- char* uri = g_file_get_uri(d->m_gfile);
- response.setURL(KURL(KURL(), uri));
- g_free(uri);
-
- GError* error = 0;
- GFileInfo* info = g_file_query_info_finish(d->m_gfile, res, &error);
-
- if (error) {
- // FIXME: to be able to handle ftp URIs properly, we must
- // check if the error is G_IO_ERROR_NOT_MOUNTED, and if so,
- // call g_file_mount_enclosing_volume() to mount the ftp
- // server (and then keep track of the fact that we mounted it,
- // and set a timeout to unmount it later after it's been idle
- // for a while).
- char* uri = g_file_get_uri(d->m_gfile);
- ResourceError resourceError(g_quark_to_string(G_IO_ERROR),
- error->code,
- uri,
- error ? String::fromUTF8(error->message) : String());
- g_free(uri);
- g_error_free(error);
- cleanupGioOperation(handle.get());
- client->didFail(handle.get(), resourceError);
- return;
- }
-
- if (g_file_info_get_file_type(info) != G_FILE_TYPE_REGULAR) {
- // FIXME: what if the URI points to a directory? Should we
- // generate a listing? How? What do other backends do here?
- char* uri = g_file_get_uri(d->m_gfile);
- ResourceError resourceError(g_quark_to_string(G_IO_ERROR),
- G_IO_ERROR_FAILED,
- uri,
- String());
- g_free(uri);
- cleanupGioOperation(handle.get());
- client->didFail(handle.get(), resourceError);
- return;
- }
-
- // According to http://library.gnome.org/devel/gio/stable/gio-GContentType.html
- // GContentType on Unix is the mime type, but not on Win32.
- GOwnPtr<gchar> mimeType(g_content_type_get_mime_type(g_file_info_get_content_type(info)));
- response.setMimeType(mimeType.get());
- response.setExpectedContentLength(g_file_info_get_size(info));
-
- GTimeVal tv;
- g_file_info_get_modification_time(info, &tv);
- response.setLastModifiedDate(tv.tv_sec);
-
- client->didReceiveResponse(handle.get(), response);
-
- if (d->m_cancelled) {
- cleanupGioOperation(handle.get());
- return;
- }
-
- g_file_read_async(d->m_gfile, G_PRIORITY_DEFAULT, d->m_cancellable,
- openCallback, 0);
-}
static bool startGio(ResourceHandle* handle, KURL url)
{
ASSERT(handle);
- ResourceHandleInternal* d = handle->getInternal();
-
if (handle->firstRequest().httpMethod() != "GET" && handle->firstRequest().httpMethod() != "POST")
return false;
+ SoupSession* session = handle->defaultSession();
+ ResourceHandleInternal* d = handle->getInternal();
+
// GIO doesn't know how to handle refs and queries, so remove them
// TODO: use KURL.fileSystemPath after KURLGtk and FileSystemGtk are
// using GIO internally, and providing URIs instead of file paths
url.removeFragmentIdentifier();
url.setQuery(String());
url.removePort();
+ CString urlStr = url.string().utf8();
-#if !OS(WINDOWS)
- // we avoid the escaping for local files, because
- // g_filename_from_uri (used internally by GFile) has problems
- // decoding strings with arbitrary percent signs
- if (url.isLocalFile())
- d->m_gfile = g_file_new_for_path(url.prettyURL().utf8().data() + sizeof("file://") - 1);
- else
-#endif
- d->m_gfile = g_file_new_for_uri(url.string().utf8().data());
- g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", handle);
+ GOwnPtr<GError> error;
+ d->m_soupRequest = adoptPlatformRef(webkit_soup_requester_request(d->m_requester.get(), urlStr.data(), session, &error.outPtr()));
+ if (error) {
+ d->m_soupRequest = 0;
+ return false;
+ }
+
+ g_object_set_data(G_OBJECT(d->m_soupRequest.get()), "webkit-resource", handle);
- // balanced by a deref() in cleanupGioOperation, which should always run
+ // balanced by a deref() in cleanupSoupRequestOperation, which should always run
handle->ref();
- d->m_cancellable = g_cancellable_new();
- g_file_query_info_async(d->m_gfile,
- G_FILE_ATTRIBUTE_STANDARD_TYPE ","
- G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
- G_FILE_ATTRIBUTE_STANDARD_SIZE,
- G_FILE_QUERY_INFO_NONE,
- G_PRIORITY_DEFAULT, d->m_cancellable,
- queryInfoCallback, 0);
+ d->m_cancellable = adoptPlatformRef(g_cancellable_new());
+ webkit_soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, 0);
+
return true;
}
diff --git a/WebCore/platform/network/soup/ResourceRequest.h b/WebCore/platform/network/soup/ResourceRequest.h
index a1d916f..879a47f 100644
--- a/WebCore/platform/network/soup/ResourceRequest.h
+++ b/WebCore/platform/network/soup/ResourceRequest.h
@@ -67,8 +67,9 @@ namespace WebCore {
updateFromSoupMessage(soupMessage);
}
+ void updateSoupMessage(SoupMessage*) const;
SoupMessage* toSoupMessage() const;
- void updateFromSoupMessage(SoupMessage* soupMessage);
+ void updateFromSoupMessage(SoupMessage*);
SoupMessageFlags soupMessageFlags() const { return m_soupFlags; }
void setSoupMessageFlags(SoupMessageFlags soupFlags) { m_soupFlags = soupFlags; }
@@ -80,6 +81,12 @@ namespace WebCore {
void doUpdatePlatformRequest() {};
void doUpdateResourceRequest() {};
+
+ PassOwnPtr<CrossThreadResourceRequestData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceRequestData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceRequestData>) { }
+ };
+
+ struct CrossThreadResourceRequestData : public CrossThreadResourceRequestDataBase {
};
} // namespace WebCore
diff --git a/WebCore/platform/network/soup/ResourceRequestSoup.cpp b/WebCore/platform/network/soup/ResourceRequestSoup.cpp
index 62deb01..380fc84 100644
--- a/WebCore/platform/network/soup/ResourceRequestSoup.cpp
+++ b/WebCore/platform/network/soup/ResourceRequestSoup.cpp
@@ -33,6 +33,29 @@ using namespace std;
namespace WebCore {
+void ResourceRequest::updateSoupMessage(SoupMessage* soupMessage) const
+{
+ g_object_set(soupMessage, SOUP_MESSAGE_METHOD, httpMethod().utf8().data(), NULL);
+
+ const HTTPHeaderMap& headers = httpHeaderFields();
+ SoupMessageHeaders* soupHeaders = soupMessage->request_headers;
+ if (!headers.isEmpty()) {
+ HTTPHeaderMap::const_iterator end = headers.end();
+ for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it)
+ soup_message_headers_append(soupHeaders, it->first.string().utf8().data(), it->second.utf8().data());
+ }
+
+#ifdef HAVE_LIBSOUP_2_29_90
+ String firstPartyString = firstPartyForCookies().string();
+ if (!firstPartyString.isEmpty()) {
+ GOwnPtr<SoupURI> firstParty(soup_uri_new(firstPartyString.utf8().data()));
+ soup_message_set_first_party(soupMessage, firstParty.get());
+ }
+#endif
+
+ soup_message_set_flags(soupMessage, m_soupFlags);
+}
+
SoupMessage* ResourceRequest::toSoupMessage() const
{
SoupMessage* soupMessage = soup_message_new(httpMethod().utf8().data(), url().string().utf8().data());
diff --git a/WebCore/platform/network/soup/ResourceResponse.h b/WebCore/platform/network/soup/ResourceResponse.h
index e6d872c..e7213f5 100644
--- a/WebCore/platform/network/soup/ResourceResponse.h
+++ b/WebCore/platform/network/soup/ResourceResponse.h
@@ -63,9 +63,13 @@ private:
SoupMessageFlags m_soupFlags;
- void doUpdateResourceResponse()
- {
- }
+ void doUpdateResourceResponse() { }
+
+ PassOwnPtr<CrossThreadResourceResponseData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData> data) const { return data; }
+ void doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData>) { }
+};
+
+struct CrossThreadResourceResponseData : public CrossThreadResourceResponseDataBase {
};
} // namespace WebCore
diff --git a/WebCore/platform/network/soup/cache/soup-directory-input-stream.c b/WebCore/platform/network/soup/cache/soup-directory-input-stream.c
new file mode 100644
index 0000000..c14863b
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-directory-input-stream.c
@@ -0,0 +1,200 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-directory-input-stream.h"
+
+#include <libsoup/soup.h>
+#include <stdio.h>
+#include <string.h>
+
+#define INIT_STRING "<html><head><title>OMG!</title></head><body><table>"
+#define EXIT_STRING "</table></html>"
+
+G_DEFINE_TYPE (WebKitSoupDirectoryInputStream, webkit_soup_directory_input_stream, G_TYPE_INPUT_STREAM)
+
+static SoupBuffer *
+webkit_soup_directory_input_stream_parse_info (WebKitSoupDirectoryInputStream * stream,
+ GFileInfo * info)
+{
+ SoupBuffer *buffer;
+ GString *string;
+ const char *s;
+ char *escaped, *path, *xml_string;
+
+ if (!g_file_info_get_name (info))
+ return NULL;
+
+ s = g_file_info_get_display_name (info);
+ if (!s) {
+ s = g_file_info_get_name (info);
+ /* FIXME: convert somehow? */
+ if (!g_utf8_validate (s, -1, NULL))
+ return NULL;
+ }
+ string = g_string_new ("<tr>");
+
+ xml_string = g_markup_escape_text (s, -1);
+ escaped = g_uri_escape_string (g_file_info_get_name (info), NULL, FALSE);
+ path = g_strconcat (stream->uri, "/", escaped, NULL);
+ g_free (escaped);
+ g_string_append_printf (string, "<td><a href=\"%s\">%s</a></td>", path, xml_string);
+ g_free (path);
+ g_free (xml_string);
+ g_string_append (string, "</tr>");
+
+ buffer = soup_buffer_new (SOUP_MEMORY_TAKE, string->str, string->len);
+ g_string_free (string, FALSE);
+
+ return buffer;
+}
+
+static SoupBuffer *
+webkit_soup_directory_input_stream_read_next_file (WebKitSoupDirectoryInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GFileInfo *info;
+ SoupBuffer *buffer;
+ GError *err = NULL;
+
+ do {
+ info = g_file_enumerator_next_file (stream->enumerator, cancellable, &err);
+ if (info == NULL) {
+ if (err) {
+ g_propagate_error (error, err);
+ return NULL;
+ } else if (!stream->done) {
+ stream->done = TRUE;
+ return soup_buffer_new (SOUP_MEMORY_STATIC,
+ EXIT_STRING,
+ sizeof (EXIT_STRING));
+ } else {
+ return NULL;
+ }
+ }
+
+ buffer = webkit_soup_directory_input_stream_parse_info (stream, info);
+ } while (buffer == NULL);
+
+ return buffer;
+}
+
+static gssize
+webkit_soup_directory_input_stream_read (GInputStream *input,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupDirectoryInputStream *stream = WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (input);
+ gsize total, size;
+
+ for (total = 0; total < count; total += size) {
+ if (stream->buffer == NULL) {
+ stream->buffer = webkit_soup_directory_input_stream_read_next_file (stream, cancellable, error);
+ if (stream->buffer == NULL) {
+ /* FIXME: Is this correct or should we forward the error? */
+ if (total)
+ g_clear_error (error);
+ return total;
+ }
+ }
+
+ size = MIN (stream->buffer->length, count - total);
+ memcpy ((char *)buffer + total, stream->buffer->data, size);
+ if (size == stream->buffer->length) {
+ soup_buffer_free (stream->buffer);
+ stream->buffer = NULL;
+ } else {
+ SoupBuffer *sub = soup_buffer_new_subbuffer (stream->buffer,
+ size,
+ stream->buffer->length - size);
+ soup_buffer_free (stream->buffer);
+ stream->buffer = sub;
+ }
+ }
+
+ return total;
+}
+
+static gboolean
+webkit_soup_directory_input_stream_close (GInputStream *input,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupDirectoryInputStream *stream = WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (input);
+ gboolean result;
+
+ if (stream->buffer) {
+ soup_buffer_free (stream->buffer);
+ stream->buffer = NULL;
+ }
+
+ result = g_file_enumerator_close (stream->enumerator,
+ cancellable,
+ error);
+ g_object_unref (stream->enumerator);
+ stream->enumerator = NULL;
+
+ g_free (stream->uri);
+ stream->uri = NULL;
+
+ return result;
+}
+
+static void
+webkit_soup_directory_input_stream_class_init (WebKitSoupDirectoryInputStreamClass *stream_class)
+{
+ GInputStreamClass *inputstream_class = G_INPUT_STREAM_CLASS (stream_class);
+
+ inputstream_class->read_fn = webkit_soup_directory_input_stream_read;
+ inputstream_class->close_fn = webkit_soup_directory_input_stream_close;
+}
+
+static void
+webkit_soup_directory_input_stream_init (WebKitSoupDirectoryInputStream *stream)
+{
+ stream->buffer = soup_buffer_new (SOUP_MEMORY_STATIC,
+ INIT_STRING,
+ sizeof (INIT_STRING));
+}
+
+GInputStream *
+webkit_soup_directory_input_stream_new (GFileEnumerator *enumerator,
+ SoupURI *uri)
+{
+ GInputStream *stream;
+
+ g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ stream = g_object_new (WEBKIT_TYPE_SOUP_DIRECTORY_INPUT_STREAM, NULL);
+
+ WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (stream)->enumerator = g_object_ref (enumerator);
+ WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (stream)->uri = soup_uri_to_string (uri, FALSE);
+
+ return stream;
+}
+
diff --git a/WebCore/platform/network/soup/cache/soup-directory-input-stream.h b/WebCore/platform/network/soup/cache/soup-directory-input-stream.h
new file mode 100644
index 0000000..0c5b0be
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-directory-input-stream.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ * 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 WEBKIT_SOUP_DIRECTORY_INPUT_STREAM_H
+#define WEBKIT_SOUP_DIRECTORY_INPUT_STREAM_H 1
+
+#include <gio/gio.h>
+#include <libsoup/soup-types.h>
+#include <libsoup/soup-message-body.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_SOUP_DIRECTORY_INPUT_STREAM (webkit_soup_directory_input_stream_get_type ())
+#define WEBKIT_SOUP_DIRECTORY_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_SOUP_DIRECTORY_INPUT_STREAM, WebKitSoupDirectoryInputStream))
+#define WEBKIT_SOUP_DIRECTORY_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_SOUP_DIRECTORY_INPUT_STREAM, WebKitSoupDirectoryInputStreamClass))
+#define WEBKIT_IS_SOUP_DIRECTORY_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_SOUP_DIRECTORY_INPUT_STREAM))
+#define WEBKIT_IS_SOUP_DIRECTORY_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), WEBKIT_TYPE_SOUP_DIRECTORY_INPUT_STREAM))
+#define WEBKIT_SOUP_DIRECTORY_INPUT_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), WEBKIT_TYPE_SOUP_DIRECTORY_INPUT_STREAM, WebKitSoupDirectoryInputStreamClass))
+
+typedef struct _WebKitSoupDirectoryInputStream WebKitSoupDirectoryInputStream;
+typedef struct _WebKitSoupDirectoryInputStreamClass WebKitSoupDirectoryInputStreamClass;
+
+struct _WebKitSoupDirectoryInputStream {
+ GInputStream parent;
+
+ GFileEnumerator *enumerator;
+ char *uri;
+ SoupBuffer *buffer;
+ gboolean done;
+};
+
+struct _WebKitSoupDirectoryInputStreamClass {
+ GInputStreamClass parent_class;
+};
+
+GType webkit_soup_directory_input_stream_get_type (void);
+
+GInputStream *webkit_soup_directory_input_stream_new (GFileEnumerator *enumerator,
+ SoupURI *uri);
+
+
+G_END_DECLS
+
+#endif /* WEBKIT_SOUP_DIRECTORY_INPUT_STREAM_H */
diff --git a/WebCore/platform/network/soup/cache/soup-http-input-stream.c b/WebCore/platform/network/soup/cache/soup-http-input-stream.c
new file mode 100644
index 0000000..dc95d6e
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-http-input-stream.c
@@ -0,0 +1,921 @@
+/* soup-input-stream.c, based on gsocketinputstream.c
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <libsoup/soup.h>
+
+#include "soup-http-input-stream.h"
+
+static void webkit_soup_http_input_stream_seekable_iface_init (GSeekableIface *seekable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (WebKitSoupHTTPInputStream, webkit_soup_http_input_stream, G_TYPE_INPUT_STREAM,
+ G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
+ webkit_soup_http_input_stream_seekable_iface_init))
+
+typedef void (*WebKitSoupHTTPInputStreamCallback)(GInputStream *);
+
+typedef struct {
+ SoupSession *session;
+ GMainContext *async_context;
+ SoupMessage *msg;
+ gboolean got_headers, finished;
+ goffset offset;
+
+ GCancellable *cancellable;
+ GSource *cancel_watch;
+ WebKitSoupHTTPInputStreamCallback got_headers_cb;
+ WebKitSoupHTTPInputStreamCallback got_chunk_cb;
+ WebKitSoupHTTPInputStreamCallback finished_cb;
+ WebKitSoupHTTPInputStreamCallback cancelled_cb;
+
+ guchar *leftover_buffer;
+ gsize leftover_bufsize, leftover_offset;
+
+ guchar *caller_buffer;
+ gsize caller_bufsize, caller_nread;
+ GAsyncReadyCallback outstanding_callback;
+ GSimpleAsyncResult *result;
+} WebKitSoupHTTPInputStreamPrivate;
+#define WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), WEBKIT_TYPE_SOUP_HTTP_INPUT_STREAM, WebKitSoupHTTPInputStreamPrivate))
+
+
+static gssize webkit_soup_http_input_stream_read (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error);
+static gboolean webkit_soup_http_input_stream_close (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+static void webkit_soup_http_input_stream_read_async (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer data);
+static gssize webkit_soup_http_input_stream_read_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error);
+static void webkit_soup_http_input_stream_close_async (GInputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer data);
+static gboolean webkit_soup_http_input_stream_close_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error);
+
+static goffset webkit_soup_http_input_stream_tell (GSeekable *seekable);
+
+static gboolean webkit_soup_http_input_stream_can_seek (GSeekable *seekable);
+static gboolean webkit_soup_http_input_stream_seek (GSeekable *seekable,
+ goffset offset,
+ GSeekType type,
+ GCancellable *cancellable,
+ GError **error);
+
+static gboolean webkit_soup_http_input_stream_can_truncate (GSeekable *seekable);
+static gboolean webkit_soup_http_input_stream_truncate (GSeekable *seekable,
+ goffset offset,
+ GCancellable *cancellable,
+ GError **error);
+
+static void webkit_soup_http_input_stream_got_headers (SoupMessage *msg, gpointer stream);
+static void webkit_soup_http_input_stream_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer stream);
+static void webkit_soup_http_input_stream_finished (SoupMessage *msg, gpointer stream);
+
+static void
+webkit_soup_http_input_stream_finalize (GObject *object)
+{
+ WebKitSoupHTTPInputStream *stream = WEBKIT_SOUP_HTTP_INPUT_STREAM (object);
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ g_object_unref (priv->session);
+
+ g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (webkit_soup_http_input_stream_got_headers), stream);
+ g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (webkit_soup_http_input_stream_got_chunk), stream);
+ g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (webkit_soup_http_input_stream_finished), stream);
+ g_object_unref (priv->msg);
+ g_free (priv->leftover_buffer);
+
+ if (G_OBJECT_CLASS (webkit_soup_http_input_stream_parent_class)->finalize)
+ (*G_OBJECT_CLASS (webkit_soup_http_input_stream_parent_class)->finalize)(object);
+}
+
+static void
+webkit_soup_http_input_stream_class_init (WebKitSoupHTTPInputStreamClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (WebKitSoupHTTPInputStreamPrivate));
+
+ gobject_class->finalize = webkit_soup_http_input_stream_finalize;
+
+ stream_class->read_fn = webkit_soup_http_input_stream_read;
+ stream_class->close_fn = webkit_soup_http_input_stream_close;
+ stream_class->read_async = webkit_soup_http_input_stream_read_async;
+ stream_class->read_finish = webkit_soup_http_input_stream_read_finish;
+ stream_class->close_async = webkit_soup_http_input_stream_close_async;
+ stream_class->close_finish = webkit_soup_http_input_stream_close_finish;
+}
+
+static void
+webkit_soup_http_input_stream_seekable_iface_init (GSeekableIface *seekable_iface)
+{
+ seekable_iface->tell = webkit_soup_http_input_stream_tell;
+ seekable_iface->can_seek = webkit_soup_http_input_stream_can_seek;
+ seekable_iface->seek = webkit_soup_http_input_stream_seek;
+ seekable_iface->can_truncate = webkit_soup_http_input_stream_can_truncate;
+ seekable_iface->truncate_fn = webkit_soup_http_input_stream_truncate;
+}
+
+static void
+webkit_soup_http_input_stream_init (WebKitSoupHTTPInputStream *stream)
+{
+ ;
+}
+
+static void
+webkit_soup_http_input_stream_queue_message (WebKitSoupHTTPInputStream *stream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ priv->got_headers = priv->finished = FALSE;
+
+ /* Add an extra ref since soup_session_queue_message steals one */
+ g_object_ref (priv->msg);
+ soup_session_queue_message (priv->session, priv->msg, NULL, NULL);
+}
+
+/**
+ * webkit_soup_http_input_stream_new:
+ * @session: the #SoupSession to use
+ * @msg: the #SoupMessage whose response will be streamed
+ *
+ * Prepares to send @msg over @session, and returns a #GInputStream
+ * that can be used to read the response.
+ *
+ * @msg may not be sent until the first read call; if you need to look
+ * at the status code or response headers before reading the body, you
+ * can use webkit_soup_http_input_stream_send() or webkit_soup_http_input_stream_send_async()
+ * to force the message to be sent and the response headers read.
+ *
+ * If @msg gets a non-2xx result, the first read (or send) will return
+ * an error with type %WEBKIT_SOUP_HTTP_INPUT_STREAM_HTTP_ERROR.
+ *
+ * Internally, #WebKitSoupHTTPInputStream is implemented using asynchronous I/O,
+ * so if you are using the synchronous API (eg,
+ * g_input_stream_read()), you should create a new #GMainContext and
+ * set it as the %SOUP_SESSION_ASYNC_CONTEXT property on @session. (If
+ * you don't, then synchronous #GInputStream calls will cause the main
+ * loop to be run recursively.) The async #GInputStream API works fine
+ * with %SOUP_SESSION_ASYNC_CONTEXT either set or unset.
+ *
+ * Returns: a new #GInputStream.
+ **/
+WebKitSoupHTTPInputStream *
+webkit_soup_http_input_stream_new (SoupSession *session, SoupMessage *msg)
+{
+ WebKitSoupHTTPInputStream *stream;
+ WebKitSoupHTTPInputStreamPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
+
+ stream = g_object_new (WEBKIT_TYPE_SOUP_HTTP_INPUT_STREAM, NULL);
+ priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ priv->session = g_object_ref (session);
+ priv->async_context = soup_session_get_async_context (session);
+ priv->msg = g_object_ref (msg);
+
+ g_signal_connect (msg, "got_headers",
+ G_CALLBACK (webkit_soup_http_input_stream_got_headers), stream);
+ g_signal_connect (msg, "got_chunk",
+ G_CALLBACK (webkit_soup_http_input_stream_got_chunk), stream);
+ g_signal_connect (msg, "finished",
+ G_CALLBACK (webkit_soup_http_input_stream_finished), stream);
+
+ webkit_soup_http_input_stream_queue_message (stream);
+ return stream;
+}
+
+static void
+webkit_soup_http_input_stream_got_headers (SoupMessage *msg, gpointer stream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ /* If the status is unsuccessful, we just ignore the signal and let
+ * libsoup keep going (eventually either it will requeue the request
+ * (after handling authentication/redirection), or else the
+ * "finished" handler will run).
+ */
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+ return;
+
+ priv->got_headers = TRUE;
+ if (!priv->caller_buffer) {
+ /* Not ready to read the body yet */
+ soup_session_pause_message (priv->session, msg);
+ }
+
+ if (priv->got_headers_cb)
+ priv->got_headers_cb (stream);
+}
+
+static void
+webkit_soup_http_input_stream_got_chunk (SoupMessage *msg, SoupBuffer *chunk_buffer,
+ gpointer stream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ const gchar *chunk = chunk_buffer->data;
+ gsize chunk_size = chunk_buffer->length;
+
+ /* We only pay attention to the chunk if it's part of a successful
+ * response.
+ */
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+ return;
+
+ /* Sanity check */
+ if (priv->caller_bufsize == 0 || priv->leftover_bufsize != 0)
+ g_warning ("webkit_soup_http_input_stream_got_chunk called again before previous chunk was processed");
+
+ /* Copy what we can into priv->caller_buffer */
+ if (priv->caller_bufsize - priv->caller_nread > 0) {
+ gsize nread = MIN (chunk_size, priv->caller_bufsize - priv->caller_nread);
+
+ memcpy (priv->caller_buffer + priv->caller_nread, chunk, nread);
+ priv->caller_nread += nread;
+ priv->offset += nread;
+ chunk += nread;
+ chunk_size -= nread;
+ }
+
+ if (chunk_size > 0) {
+ /* Copy the rest into priv->leftover_buffer. If
+ * there's already some data there, realloc and
+ * append. Otherwise just copy.
+ */
+ if (priv->leftover_bufsize) {
+ priv->leftover_buffer = g_realloc (priv->leftover_buffer,
+ priv->leftover_bufsize + chunk_size);
+ memcpy (priv->leftover_buffer + priv->leftover_bufsize,
+ chunk, chunk_size);
+ priv->leftover_bufsize += chunk_size;
+ } else {
+ priv->leftover_bufsize = chunk_size;
+ priv->leftover_buffer = g_memdup (chunk, chunk_size);
+ priv->leftover_offset = 0;
+ }
+ }
+
+ soup_session_pause_message (priv->session, msg);
+ if (priv->got_chunk_cb)
+ priv->got_chunk_cb (stream);
+}
+
+static void
+webkit_soup_http_input_stream_finished (SoupMessage *msg, gpointer stream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ priv->finished = TRUE;
+
+ if (priv->finished_cb)
+ priv->finished_cb (stream);
+}
+
+static gboolean
+webkit_soup_http_input_stream_cancelled (GIOChannel *chan, GIOCondition condition,
+ gpointer stream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ priv->cancel_watch = NULL;
+
+ soup_session_pause_message (priv->session, priv->msg);
+ if (priv->cancelled_cb)
+ priv->cancelled_cb (stream);
+
+ return FALSE;
+}
+
+static void
+webkit_soup_http_input_stream_prepare_for_io (GInputStream *stream,
+ GCancellable *cancellable,
+ guchar *buffer,
+ gsize count)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ int cancel_fd;
+
+ priv->cancellable = cancellable;
+ cancel_fd = g_cancellable_get_fd (cancellable);
+ if (cancel_fd != -1) {
+ GIOChannel *chan = g_io_channel_unix_new (cancel_fd);
+ priv->cancel_watch = soup_add_io_watch (priv->async_context, chan,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ webkit_soup_http_input_stream_cancelled,
+ stream);
+ g_io_channel_unref (chan);
+ }
+
+ priv->caller_buffer = buffer;
+ priv->caller_bufsize = count;
+ priv->caller_nread = 0;
+
+ if (priv->got_headers)
+ soup_session_unpause_message (priv->session, priv->msg);
+}
+
+static void
+webkit_soup_http_input_stream_done_io (GInputStream *stream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ if (priv->cancel_watch) {
+ g_source_destroy (priv->cancel_watch);
+ priv->cancel_watch = NULL;
+ g_cancellable_release_fd (priv->cancellable);
+ }
+ priv->cancellable = NULL;
+
+ priv->caller_buffer = NULL;
+ priv->caller_bufsize = 0;
+}
+
+static gboolean
+set_error_if_http_failed (SoupMessage *msg, GError **error)
+{
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ g_set_error_literal (error, SOUP_HTTP_ERROR,
+ msg->status_code, msg->reason_phrase);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gsize
+read_from_leftover (WebKitSoupHTTPInputStreamPrivate *priv,
+ gpointer buffer, gsize bufsize)
+{
+ gsize nread;
+
+ if (priv->leftover_bufsize - priv->leftover_offset <= bufsize) {
+ nread = priv->leftover_bufsize - priv->leftover_offset;
+ memcpy (buffer, priv->leftover_buffer + priv->leftover_offset, nread);
+
+ g_free (priv->leftover_buffer);
+ priv->leftover_buffer = NULL;
+ priv->leftover_bufsize = priv->leftover_offset = 0;
+ } else {
+ nread = bufsize;
+ memcpy (buffer, priv->leftover_buffer + priv->leftover_offset, nread);
+ priv->leftover_offset += nread;
+ }
+
+ priv->offset += nread;
+ return nread;
+}
+
+/* This does the work of webkit_soup_http_input_stream_send(), assuming that the
+ * GInputStream pending flag has already been set. It is also used by
+ * webkit_soup_http_input_stream_send_async() in some circumstances.
+ */
+static gboolean
+webkit_soup_http_input_stream_send_internal (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ webkit_soup_http_input_stream_prepare_for_io (stream, cancellable, NULL, 0);
+ while (!priv->finished && !priv->got_headers &&
+ !g_cancellable_is_cancelled (cancellable))
+ g_main_context_iteration (priv->async_context, TRUE);
+ webkit_soup_http_input_stream_done_io (stream);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+ else if (set_error_if_http_failed (priv->msg, error))
+ return FALSE;
+ return TRUE;
+}
+
+static void
+send_sync_finished (GInputStream *stream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ GError *error = NULL;
+
+ if (!g_cancellable_set_error_if_cancelled (priv->cancellable, &error))
+ set_error_if_http_failed (priv->msg, &error);
+
+ priv->got_headers_cb = NULL;
+ priv->finished_cb = NULL;
+
+ /* Wake up the main context iteration */
+ g_source_attach (g_idle_source_new (), NULL);
+}
+
+/**
+ * webkit_soup_http_input_stream_send:
+ * @httpstream: a #WebKitSoupHTTPInputStream
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: location to store the error occuring, or %NULL to ignore
+ *
+ * Synchronously sends the HTTP request associated with @stream, and
+ * reads the response headers. Call this after webkit_soup_http_input_stream_new()
+ * and before the first g_input_stream_read() if you want to check the
+ * HTTP status code before you start reading.
+ *
+ * Return value: %TRUE if msg has a successful (2xx) status, %FALSE if
+ * not.
+ **/
+gboolean
+webkit_soup_http_input_stream_send (WebKitSoupHTTPInputStream *httpstream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (httpstream);
+ GInputStream *istream = (GInputStream *)httpstream;
+ gboolean result;
+
+ g_return_val_if_fail (WEBKIT_IS_SOUP_HTTP_INPUT_STREAM (httpstream), FALSE);
+
+ if (!g_input_stream_set_pending (istream, error))
+ return FALSE;
+
+ priv->got_headers_cb = send_sync_finished;
+ priv->finished_cb = send_sync_finished;
+
+ result = webkit_soup_http_input_stream_send_internal (istream, cancellable, error);
+ g_input_stream_clear_pending (istream);
+
+ return result;
+}
+
+static gssize
+webkit_soup_http_input_stream_read (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ if (priv->finished)
+ return 0;
+
+ /* If there is data leftover from a previous read, return it. */
+ if (priv->leftover_bufsize)
+ return read_from_leftover (priv, buffer, count);
+
+ /* No leftover data, accept one chunk from the network */
+ webkit_soup_http_input_stream_prepare_for_io (stream, cancellable, buffer, count);
+ while (!priv->finished && priv->caller_nread == 0 &&
+ !g_cancellable_is_cancelled (cancellable))
+ g_main_context_iteration (priv->async_context, TRUE);
+ webkit_soup_http_input_stream_done_io (stream);
+
+ if (priv->caller_nread > 0)
+ return priv->caller_nread;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return -1;
+ else if (set_error_if_http_failed (priv->msg, error))
+ return -1;
+ else
+ return 0;
+}
+
+static gboolean
+webkit_soup_http_input_stream_close (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ if (!priv->finished)
+ soup_session_cancel_message (priv->session, priv->msg, SOUP_STATUS_CANCELLED);
+
+ return TRUE;
+}
+
+static void
+wrapper_callback (GObject *source_object, GAsyncResult *res,
+ gpointer user_data)
+{
+ GInputStream *stream = G_INPUT_STREAM (source_object);
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ g_input_stream_clear_pending (stream);
+ if (priv->outstanding_callback)
+ (*priv->outstanding_callback)(source_object, res, user_data);
+ priv->outstanding_callback = NULL;
+ g_object_unref (stream);
+}
+
+static void
+send_async_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GError *error = NULL;
+ gboolean success;
+
+ success = webkit_soup_http_input_stream_send_internal (G_INPUT_STREAM (object),
+ cancellable, &error);
+ g_simple_async_result_set_op_res_gboolean (res, success);
+ if (error) {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ }
+}
+
+static void
+webkit_soup_http_input_stream_send_async_in_thread (GInputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+
+ res = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
+ webkit_soup_http_input_stream_send_async_in_thread);
+ g_simple_async_result_run_in_thread (res, send_async_thread,
+ io_priority, cancellable);
+ g_object_unref (res);
+}
+
+static void
+send_async_finished (GInputStream *stream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ GSimpleAsyncResult *result;
+ GError *error = NULL;
+
+ if (!g_cancellable_set_error_if_cancelled (priv->cancellable, &error))
+ set_error_if_http_failed (priv->msg, &error);
+
+ priv->got_headers_cb = NULL;
+ priv->finished_cb = NULL;
+ webkit_soup_http_input_stream_done_io (stream);
+
+ result = priv->result;
+ priv->result = NULL;
+
+ g_simple_async_result_set_op_res_gboolean (result, error == NULL);
+ if (error) {
+ g_simple_async_result_set_from_error (result, error);
+ g_error_free (error);
+ }
+ g_simple_async_result_complete (result);
+}
+
+static void
+webkit_soup_http_input_stream_send_async_internal (GInputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ g_object_ref (stream);
+ priv->outstanding_callback = callback;
+
+ /* If the session uses the default GMainContext, then we can do
+ * async I/O directly. But if it has its own main context, it's
+ * easier to just run it in another thread.
+ */
+ if (soup_session_get_async_context (priv->session)) {
+ webkit_soup_http_input_stream_send_async_in_thread (stream, io_priority, cancellable,
+ wrapper_callback, user_data);
+ return;
+ }
+
+ priv->got_headers_cb = send_async_finished;
+ priv->finished_cb = send_async_finished;
+
+ webkit_soup_http_input_stream_prepare_for_io (stream, cancellable, NULL, 0);
+ priv->result = g_simple_async_result_new (G_OBJECT (stream),
+ wrapper_callback, user_data,
+ webkit_soup_http_input_stream_send_async);
+}
+
+/**
+ * webkit_soup_http_input_stream_send_async:
+ * @httpstream: a #WebKitSoupHTTPInputStream
+ * @io_priority: the io priority of the request.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied
+ * @user_data: the data to pass to callback function
+ *
+ * Asynchronously sends the HTTP request associated with @stream, and
+ * reads the response headers. Call this after webkit_soup_http_input_stream_new()
+ * and before the first g_input_stream_read_async() if you want to
+ * check the HTTP status code before you start reading.
+ **/
+void
+webkit_soup_http_input_stream_send_async (WebKitSoupHTTPInputStream *httpstream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GInputStream *istream = (GInputStream *)httpstream;
+ GError *error = NULL;
+
+ g_return_if_fail (WEBKIT_IS_SOUP_HTTP_INPUT_STREAM (httpstream));
+
+ if (!g_input_stream_set_pending (istream, &error)) {
+ g_simple_async_report_gerror_in_idle (G_OBJECT (httpstream),
+ callback,
+ user_data,
+ error);
+ g_error_free (error);
+ return;
+ }
+ webkit_soup_http_input_stream_send_async_internal (istream, io_priority, cancellable,
+ callback, user_data);
+}
+
+/**
+ * webkit_soup_http_input_stream_send_finish:
+ * @httpstream: a #WebKitSoupHTTPInputStream
+ * @result: a #GAsyncResult.
+ * @error: a #GError location to store the error occuring, or %NULL to
+ * ignore.
+ *
+ * Finishes a webkit_soup_http_input_stream_send_async() operation.
+ *
+ * Return value: %TRUE if the message was sent successfully and
+ * received a successful status code, %FALSE if not.
+ **/
+gboolean
+webkit_soup_http_input_stream_send_finish (WebKitSoupHTTPInputStream *httpstream,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ g_return_val_if_fail (g_simple_async_result_get_source_tag (simple) == webkit_soup_http_input_stream_send_async, FALSE);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return g_simple_async_result_get_op_res_gboolean (simple);
+}
+
+static void
+read_async_done (GInputStream *stream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ GSimpleAsyncResult *result;
+ GError *error = NULL;
+
+ result = priv->result;
+ priv->result = NULL;
+
+ if (g_cancellable_set_error_if_cancelled (priv->cancellable, &error) ||
+ set_error_if_http_failed (priv->msg, &error)) {
+ g_simple_async_result_set_from_error (result, error);
+ g_error_free (error);
+ } else
+ g_simple_async_result_set_op_res_gssize (result, priv->caller_nread);
+
+ priv->got_chunk_cb = NULL;
+ priv->finished_cb = NULL;
+ priv->cancelled_cb = NULL;
+ webkit_soup_http_input_stream_done_io (stream);
+
+ g_simple_async_result_complete (result);
+ g_object_unref (result);
+}
+
+static void
+webkit_soup_http_input_stream_read_async (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ GSimpleAsyncResult *result;
+
+ /* If the session uses the default GMainContext, then we can do
+ * async I/O directly. But if it has its own main context, we fall
+ * back to the async-via-sync-in-another-thread implementation.
+ */
+ if (soup_session_get_async_context (priv->session)) {
+ G_INPUT_STREAM_CLASS (webkit_soup_http_input_stream_parent_class)->
+ read_async (stream, buffer, count, io_priority,
+ cancellable, callback, user_data);
+ return;
+ }
+
+ result = g_simple_async_result_new (G_OBJECT (stream),
+ callback, user_data,
+ webkit_soup_http_input_stream_read_async);
+
+ if (priv->finished) {
+ g_simple_async_result_set_op_res_gssize (result, 0);
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+ return;
+ }
+
+ if (priv->leftover_bufsize) {
+ gsize nread = read_from_leftover (priv, buffer, count);
+ g_simple_async_result_set_op_res_gssize (result, nread);
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+ return;
+ }
+
+ priv->result = result;
+
+ priv->got_chunk_cb = read_async_done;
+ priv->finished_cb = read_async_done;
+ priv->cancelled_cb = read_async_done;
+ webkit_soup_http_input_stream_prepare_for_io (stream, cancellable, buffer, count);
+}
+
+static gssize
+webkit_soup_http_input_stream_read_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), -1);
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ g_return_val_if_fail (g_simple_async_result_get_source_tag (simple) == webkit_soup_http_input_stream_read_async, -1);
+
+ return g_simple_async_result_get_op_res_gssize (simple);
+}
+
+static void
+webkit_soup_http_input_stream_close_async (GInputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+ gboolean success;
+ GError *error = NULL;
+
+ result = g_simple_async_result_new (G_OBJECT (stream),
+ callback, user_data,
+ webkit_soup_http_input_stream_close_async);
+ success = webkit_soup_http_input_stream_close (stream, cancellable, &error);
+ g_simple_async_result_set_op_res_gboolean (result, success);
+ if (error) {
+ g_simple_async_result_set_from_error (result, error);
+ g_error_free (error);
+ }
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static gboolean
+webkit_soup_http_input_stream_close_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ /* Failures handled in generic close_finish code */
+ return TRUE;
+}
+
+static goffset
+webkit_soup_http_input_stream_tell (GSeekable *seekable)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (seekable);
+
+ return priv->offset;
+}
+
+static gboolean
+webkit_soup_http_input_stream_can_seek (GSeekable *seekable)
+{
+ return TRUE;
+}
+
+extern void soup_message_io_cleanup (SoupMessage *msg);
+
+static gboolean
+webkit_soup_http_input_stream_seek (GSeekable *seekable,
+ goffset offset,
+ GSeekType type,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GInputStream *stream = G_INPUT_STREAM (seekable);
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (seekable);
+ char *range;
+
+ if (type == G_SEEK_END) {
+ /* FIXME: we could send "bytes=-offset", but unless we
+ * know the Content-Length, we wouldn't be able to
+ * answer a tell() properly. We could find the
+ * Content-Length by doing a HEAD...
+ */
+
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "G_SEEK_END not currently supported");
+ return FALSE;
+ }
+
+ if (!g_input_stream_set_pending (stream, error))
+ return FALSE;
+
+ soup_session_cancel_message (priv->session, priv->msg, SOUP_STATUS_CANCELLED);
+ soup_message_io_cleanup (priv->msg);
+
+ switch (type) {
+ case G_SEEK_CUR:
+ offset += priv->offset;
+ /* fall through */
+
+ case G_SEEK_SET:
+ range = g_strdup_printf ("bytes=%" G_GUINT64_FORMAT "-", (guint64)offset);
+ priv->offset = offset;
+ break;
+
+ case G_SEEK_END:
+ range = NULL; /* keep compilers happy */
+ g_return_val_if_reached (FALSE);
+ break;
+
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ soup_message_headers_remove (priv->msg->request_headers, "Range");
+ soup_message_headers_append (priv->msg->request_headers, "Range", range);
+ g_free (range);
+
+ webkit_soup_http_input_stream_queue_message (WEBKIT_SOUP_HTTP_INPUT_STREAM (stream));
+
+ g_input_stream_clear_pending (stream);
+ return TRUE;
+}
+
+static gboolean
+webkit_soup_http_input_stream_can_truncate (GSeekable *seekable)
+{
+ return FALSE;
+}
+
+static gboolean
+webkit_soup_http_input_stream_truncate (GSeekable *seekable,
+ goffset offset,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Truncate not allowed on input stream");
+ return FALSE;
+}
+
+SoupMessage *
+webkit_soup_http_input_stream_get_message (WebKitSoupHTTPInputStream *httpstream)
+{
+ WebKitSoupHTTPInputStreamPrivate *priv = WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (httpstream);
+ return priv->msg ? g_object_ref (priv->msg) : NULL;
+}
diff --git a/WebCore/platform/network/soup/cache/soup-http-input-stream.h b/WebCore/platform/network/soup/cache/soup-http-input-stream.h
new file mode 100644
index 0000000..6b98559
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-http-input-stream.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006, 2007, 2009 Red Hat, Inc.
+ * 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __WEBKIT_SOUP_HTTP_INPUT_STREAM_H__
+#define __WEBKIT_SOUP_HTTP_INPUT_STREAM_H__
+
+#include <gio/gio.h>
+#include <libsoup/soup-types.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_SOUP_HTTP_INPUT_STREAM (webkit_soup_http_input_stream_get_type ())
+#define WEBKIT_SOUP_HTTP_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), WEBKIT_TYPE_SOUP_HTTP_INPUT_STREAM, WebKitSoupHTTPInputStream))
+#define WEBKIT_SOUP_HTTP_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), WEBKIT_TYPE_SOUP_HTTP_INPUT_STREAM, WebKitSoupHTTPInputStreamClass))
+#define WEBKIT_IS_SOUP_HTTP_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), WEBKIT_TYPE_SOUP_HTTP_INPUT_STREAM))
+#define WEBKIT_IS_SOUP_HTTP_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), WEBKIT_TYPE_SOUP_HTTP_INPUT_STREAM))
+#define WEBKIT_SOUP_HTTP_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), WEBKIT_TYPE_SOUP_HTTP_INPUT_STREAM, WebKitSoupHTTPInputStreamClass))
+
+typedef struct WebKitSoupHTTPInputStream WebKitSoupHTTPInputStream;
+typedef struct WebKitSoupHTTPInputStreamClass WebKitSoupHTTPInputStreamClass;
+
+struct WebKitSoupHTTPInputStream {
+ GInputStream parent;
+};
+
+struct WebKitSoupHTTPInputStreamClass {
+ GInputStreamClass parent_class;
+
+ /* Padding for future expansion */
+ void (*_g_reserved1)(void);
+ void (*_g_reserved2)(void);
+ void (*_g_reserved3)(void);
+ void (*_g_reserved4)(void);
+ void (*_g_reserved5)(void);
+};
+
+GType webkit_soup_http_input_stream_get_type (void) G_GNUC_CONST;
+
+WebKitSoupHTTPInputStream *webkit_soup_http_input_stream_new (SoupSession *session,
+ SoupMessage *msg);
+
+gboolean webkit_soup_http_input_stream_send (WebKitSoupHTTPInputStream *httpstream,
+ GCancellable *cancellable,
+ GError **error);
+
+void webkit_soup_http_input_stream_send_async (WebKitSoupHTTPInputStream *httpstream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean webkit_soup_http_input_stream_send_finish (WebKitSoupHTTPInputStream *httpstream,
+ GAsyncResult *result,
+ GError **error);
+
+SoupMessage *webkit_soup_http_input_stream_get_message (WebKitSoupHTTPInputStream *httpstream);
+
+G_END_DECLS
+
+#endif /* __WEBKIT_SOUP_HTTP_INPUT_STREAM_H__ */
diff --git a/WebCore/platform/network/soup/cache/soup-request-data.c b/WebCore/platform/network/soup/cache/soup-request-data.c
new file mode 100644
index 0000000..ced5c4a
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-request-data.c
@@ -0,0 +1,170 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-request-data.c: data: URI request object
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "soup-request-data.h"
+
+#include "soup-requester.h"
+#include <libsoup/soup.h>
+#include <glib/gi18n.h>
+
+G_DEFINE_TYPE (WebKitSoupRequestData, webkit_soup_request_data, WEBKIT_TYPE_SOUP_REQUEST)
+
+struct _WebKitSoupRequestDataPrivate {
+ gsize content_length;
+ char *content_type;
+};
+
+static void
+webkit_soup_request_data_init (WebKitSoupRequestData *data)
+{
+ data->priv = G_TYPE_INSTANCE_GET_PRIVATE (data, WEBKIT_TYPE_SOUP_REQUEST_DATA, WebKitSoupRequestDataPrivate);
+}
+
+static void
+webkit_soup_request_data_finalize (GObject *object)
+{
+ WebKitSoupRequestData *data = WEBKIT_SOUP_REQUEST_DATA (object);
+
+ g_free (data->priv->content_type);
+
+ G_OBJECT_CLASS (webkit_soup_request_data_parent_class)->finalize (object);
+}
+
+static gboolean
+webkit_soup_request_data_check_uri (WebKitSoupRequest *request,
+ SoupURI *uri,
+ GError **error)
+{
+ return uri->host == NULL;
+}
+
+static GInputStream *
+webkit_soup_request_data_send (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupRequestData *data = WEBKIT_SOUP_REQUEST_DATA (request);
+ SoupURI *uri = webkit_soup_request_get_uri (request);
+ GInputStream *memstream;
+ const char *comma, *semi, *start, *end;
+ gboolean base64 = FALSE;
+
+ gchar *uristr = soup_uri_to_string (uri, FALSE);
+ comma = strchr (uristr, ',');
+ if (comma && comma != uristr) {
+ /* Deal with MIME type / params */
+ semi = memchr (uristr, ';', comma - uristr);
+ end = semi ? semi : comma;
+
+ if (semi && !g_ascii_strncasecmp (semi, ";base64", MAX ((size_t) (comma - semi), strlen (";base64"))))
+ base64 = TRUE;
+
+ if (end != uristr)
+ if (base64)
+ data->priv->content_type = g_strndup (uristr, end - uristr);
+ else
+ data->priv->content_type =
+ webkit_soup_request_uri_decoded_copy (uristr, end - uristr);
+ }
+
+ memstream = g_memory_input_stream_new ();
+
+ start = comma ? comma + 1 : uristr;
+
+ if (*start) {
+ guchar *buf;
+
+ if (base64) {
+ int inlen, state = 0;
+ guint save = 0;
+
+ inlen = strlen (start);
+ buf = g_malloc0 (inlen * 3 / 4 + 3);
+ data->priv->content_length =
+ g_base64_decode_step (start, inlen, buf,
+ &state, &save);
+ if (state != 0) {
+ g_free (buf);
+ goto fail;
+ }
+ } else {
+ /* Cannot use g_uri_unescape_string nor
+ soup_uri_decode because we don't want to
+ fail for things like "%3E%%3C" -> ">%<" */
+ buf = (guchar *)webkit_soup_request_uri_decoded_copy (start, strlen (start));
+ if (!buf)
+ goto fail;
+ data->priv->content_length = strlen ((char *)buf);
+ }
+
+ g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (memstream),
+ buf, data->priv->content_length,
+ g_free);
+ }
+ g_free (uristr);
+
+ return memstream;
+
+ fail:
+ g_free (uristr);
+ g_set_error (error, WEBKIT_SOUP_ERROR, WEBKIT_SOUP_ERROR_BAD_URI,
+ _ ("Unable to decode URI: %s"), start);
+ g_object_unref (memstream);
+ return NULL;
+}
+
+static goffset
+webkit_soup_request_data_get_content_length (WebKitSoupRequest *request)
+{
+ WebKitSoupRequestData *data = WEBKIT_SOUP_REQUEST_DATA (request);
+
+ return data->priv->content_length;
+}
+
+static const char *
+webkit_soup_request_data_get_content_type (WebKitSoupRequest *request)
+{
+ WebKitSoupRequestData *data = WEBKIT_SOUP_REQUEST_DATA (request);
+
+ return data->priv->content_type;
+}
+
+static void
+webkit_soup_request_data_class_init (WebKitSoupRequestDataClass *request_data_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (request_data_class);
+ WebKitSoupRequestClass *request_class =
+ WEBKIT_SOUP_REQUEST_CLASS (request_data_class);
+
+ g_type_class_add_private (request_data_class, sizeof (WebKitSoupRequestDataPrivate));
+
+ object_class->finalize = webkit_soup_request_data_finalize;
+
+ request_class->check_uri = webkit_soup_request_data_check_uri;
+ request_class->send = webkit_soup_request_data_send;
+ request_class->get_content_length = webkit_soup_request_data_get_content_length;
+ request_class->get_content_type = webkit_soup_request_data_get_content_type;
+}
diff --git a/WebCore/platform/network/soup/cache/soup-request-data.h b/WebCore/platform/network/soup/cache/soup-request-data.h
new file mode 100644
index 0000000..c9631a4
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-request-data.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * 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 WEBKIT_SOUP_REQUEST_DATA_H
+#define WEBKIT_SOUP_REQUEST_DATA_H 1
+
+#include "soup-request.h"
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_SOUP_REQUEST_DATA (webkit_soup_request_data_get_type ())
+#define WEBKIT_SOUP_REQUEST_DATA(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), WEBKIT_TYPE_SOUP_REQUEST_DATA, WebKitSoupRequestData))
+#define WEBKIT_SOUP_REQUEST_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_SOUP_REQUEST_DATA, WebKitSoupRequestDataClass))
+#define WEBKIT_IS_SOUP_REQUEST_DATA(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), WEBKIT_TYPE_SOUP_REQUEST_DATA))
+#define WEBKIT_IS_SOUP_REQUEST_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_SOUP_REQUEST_DATA))
+#define WEBKIT_SOUP_REQUEST_DATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), WEBKIT_TYPE_SOUP_REQUEST_DATA, WebKitSoupRequestDataClass))
+
+typedef struct _WebKitSoupRequestDataPrivate WebKitSoupRequestDataPrivate;
+
+typedef struct {
+ WebKitSoupRequest parent;
+
+ WebKitSoupRequestDataPrivate *priv;
+} WebKitSoupRequestData;
+
+typedef struct {
+ WebKitSoupRequestClass parent;
+} WebKitSoupRequestDataClass;
+
+GType webkit_soup_request_data_get_type (void);
+
+G_END_DECLS
+
+#endif /* WEBKIT_SOUP_REQUEST_DATA_H */
diff --git a/WebCore/platform/network/soup/cache/soup-request-file.c b/WebCore/platform/network/soup/cache/soup-request-file.c
new file mode 100644
index 0000000..24ccb10
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-request-file.c
@@ -0,0 +1,331 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-request-file.c: file: URI request object
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-request-file.h"
+#include "soup-directory-input-stream.h"
+#include "soup-requester.h"
+#include <glib/gi18n.h>
+
+G_DEFINE_TYPE (WebKitSoupRequestFile, webkit_soup_request_file, WEBKIT_TYPE_SOUP_REQUEST)
+
+struct _WebKitSoupRequestFilePrivate {
+ GFile *gfile;
+
+ char *mime_type;
+ goffset size;
+};
+
+GFile *
+webkit_soup_request_file_get_file (WebKitSoupRequestFile *file)
+{
+ return g_object_ref (file->priv->gfile);
+}
+
+static void
+webkit_soup_request_file_init (WebKitSoupRequestFile *file)
+{
+ file->priv = G_TYPE_INSTANCE_GET_PRIVATE (file, WEBKIT_TYPE_SOUP_REQUEST_FILE, WebKitSoupRequestFilePrivate);
+
+ file->priv->size = -1;
+}
+
+static void
+webkit_soup_request_file_finalize (GObject *object)
+{
+ WebKitSoupRequestFile *file = WEBKIT_SOUP_REQUEST_FILE (object);
+
+ if (file->priv->gfile)
+ g_object_unref (file->priv->gfile);
+ g_free (file->priv->mime_type);
+
+ G_OBJECT_CLASS (webkit_soup_request_file_parent_class)->finalize (object);
+}
+
+static gboolean
+webkit_soup_request_file_check_uri (WebKitSoupRequest *request,
+ SoupURI *uri,
+ GError **error)
+{
+ /* "file:/foo" is not valid */
+ if (!uri->host)
+ return FALSE;
+
+ /* but it must be "file:///..." or "file://localhost/..." */
+ if (uri->scheme == SOUP_URI_SCHEME_FILE &&
+ *uri->host &&
+ g_ascii_strcasecmp (uri->host, "localhost") != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+webkit_soup_request_file_ftp_main_loop_quit (GObject *object,
+ GAsyncResult *result,
+ gpointer loop)
+{
+ g_main_loop_quit (loop);
+}
+
+/* This is a somewhat hacky way to get FTP to almost work. The proper way to
+ * get FTP to _really_ work involves hacking GIO to have APIs to handle
+ * canoncial URLs.
+ */
+static GFile *
+webkit_soup_request_file_ensure_file_ftp (SoupURI *uri,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupURI *host;
+ char *s;
+ GFile *file, *result;
+ GMount *mount;
+
+ host = soup_uri_copy_host (uri);
+ s = soup_uri_to_string (host, FALSE);
+ file = g_file_new_for_uri (s);
+ soup_uri_free (host);
+ g_free (s);
+
+ mount = g_file_find_enclosing_mount (file, cancellable, error);
+ if (mount == NULL && g_file_supports_thread_contexts (file)) {
+ GMainContext *context = g_main_context_new ();
+ GMainLoop *loop = g_main_loop_new (context, FALSE);
+
+ g_clear_error (error);
+ g_main_context_push_thread_default (context);
+ g_file_mount_enclosing_volume (file,
+ G_MOUNT_MOUNT_NONE,
+ NULL, /* FIXME! */
+ cancellable,
+ webkit_soup_request_file_ftp_main_loop_quit,
+ loop);
+ g_main_loop_run (loop);
+ g_main_context_pop_thread_default (context);
+ g_main_loop_unref (loop);
+ g_main_context_unref (context);
+ mount = g_file_find_enclosing_mount (file, cancellable, error);
+ }
+ if (mount == NULL)
+ return NULL;
+ g_object_unref (file);
+
+ file = g_mount_get_default_location (mount);
+ g_object_unref (mount);
+
+ s = g_strdup (uri->path);
+ if (strchr (s, ';'))
+ *strchr (s, ';') = 0;
+
+ result = g_file_resolve_relative_path (file, s);
+ g_free (s);
+ g_object_unref (file);
+
+ return result;
+}
+
+static gboolean
+webkit_soup_request_file_ensure_file (WebKitSoupRequestFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupURI *uri;
+
+ if (file->priv->gfile)
+ return TRUE;
+
+ uri = webkit_soup_request_get_uri (WEBKIT_SOUP_REQUEST (file));
+ if (uri->scheme == SOUP_URI_SCHEME_FILE) {
+ /* We cannot use soup_uri_decode as it incorrectly
+ * returns NULL for incorrectly encoded URIs (that
+ * could be valid filenames). This will be hopefully
+ * shipped in libsoup 2.32.1 but we want to land this
+ * first. TODO: replace uri_decoded_copy by
+ * soup_uri_decode when the required libsoup version
+ * is bumped out to 2.32.1
+ */
+ gchar *decoded_uri = webkit_soup_request_uri_decoded_copy (uri->path, strlen (uri->path));
+
+ if (decoded_uri) {
+ /* Do not use new_for_uri() as the decoded URI
+ * could not be a valid URI
+ */
+ file->priv->gfile = g_file_new_for_path (decoded_uri);
+ g_free (decoded_uri);
+ }
+
+ return TRUE;
+ } else if (uri->scheme == SOUP_URI_SCHEME_FTP) {
+ file->priv->gfile = webkit_soup_request_file_ensure_file_ftp (uri,
+ cancellable,
+ error);
+ return file->priv->gfile != NULL;
+ }
+
+ g_set_error (error, WEBKIT_SOUP_ERROR, WEBKIT_SOUP_ERROR_UNSUPPORTED_URI_SCHEME,
+ _ ("Unsupported URI scheme '%s'"), uri->scheme);
+ return FALSE;
+}
+
+static GInputStream *
+webkit_soup_request_file_send (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupRequestFile *file = WEBKIT_SOUP_REQUEST_FILE (request);
+ GInputStream *stream;
+ GError *my_error = NULL;
+
+ if (!webkit_soup_request_file_ensure_file (file, cancellable, error))
+ return NULL;
+
+ stream = G_INPUT_STREAM (g_file_read (file->priv->gfile,
+ cancellable, &my_error));
+ if (stream == NULL) {
+ if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) {
+ GFileEnumerator *enumerator;
+ g_clear_error (&my_error);
+ enumerator = g_file_enumerate_children (file->priv->gfile,
+ "*",
+ G_FILE_QUERY_INFO_NONE,
+ cancellable,
+ error);
+ if (enumerator) {
+ stream = webkit_soup_directory_input_stream_new (enumerator,
+ webkit_soup_request_get_uri (request));
+ g_object_unref (enumerator);
+ file->priv->mime_type = g_strdup ("text/html");
+ }
+ } else {
+ g_propagate_error (error, my_error);
+ }
+ } else {
+ GFileInfo *info = g_file_query_info (file->priv->gfile,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ 0, cancellable, NULL);
+ if (info) {
+ const char *content_type;
+ file->priv->size = g_file_info_get_size (info);
+ content_type = g_file_info_get_content_type (info);
+
+ if (content_type)
+ file->priv->mime_type = g_content_type_get_mime_type (content_type);
+ g_object_unref (info);
+ }
+ }
+
+ return stream;
+}
+
+static void
+webkit_soup_request_file_send_async_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GInputStream *stream;
+ WebKitSoupRequest *request;
+ GError *error = NULL;
+
+ request = WEBKIT_SOUP_REQUEST (object);
+
+ stream = webkit_soup_request_file_send (request, cancellable, &error);
+
+ if (stream == NULL) {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ } else {
+ g_simple_async_result_set_op_res_gpointer (res, stream, g_object_unref);
+ }
+}
+
+static void
+webkit_soup_request_file_send_async (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+
+ res = g_simple_async_result_new (G_OBJECT (request), callback, user_data, webkit_soup_request_file_send_async);
+
+ g_simple_async_result_run_in_thread (res, webkit_soup_request_file_send_async_thread, G_PRIORITY_DEFAULT, cancellable);
+ g_object_unref (res);
+}
+
+static GInputStream *
+webkit_soup_request_file_send_finish (WebKitSoupRequest *request,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == webkit_soup_request_file_send_async);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+static goffset
+webkit_soup_request_file_get_content_length (WebKitSoupRequest *request)
+{
+ WebKitSoupRequestFile *file = WEBKIT_SOUP_REQUEST_FILE (request);
+
+ return file->priv->size;
+}
+
+static const char *
+webkit_soup_request_file_get_content_type (WebKitSoupRequest *request)
+{
+ WebKitSoupRequestFile *file = WEBKIT_SOUP_REQUEST_FILE (request);
+
+ if (!file->priv->mime_type)
+ return "application/octet-stream";
+
+ return file->priv->mime_type;
+}
+
+static void
+webkit_soup_request_file_class_init (WebKitSoupRequestFileClass *request_file_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (request_file_class);
+ WebKitSoupRequestClass *request_class =
+ WEBKIT_SOUP_REQUEST_CLASS (request_file_class);
+
+ g_type_class_add_private (request_file_class, sizeof (WebKitSoupRequestFilePrivate));
+
+ object_class->finalize = webkit_soup_request_file_finalize;
+
+ request_class->check_uri = webkit_soup_request_file_check_uri;
+ request_class->send = webkit_soup_request_file_send;
+ request_class->send_async = webkit_soup_request_file_send_async;
+ request_class->send_finish = webkit_soup_request_file_send_finish;
+ request_class->get_content_length = webkit_soup_request_file_get_content_length;
+ request_class->get_content_type = webkit_soup_request_file_get_content_type;
+}
diff --git a/WebCore/platform/network/soup/cache/soup-request-file.h b/WebCore/platform/network/soup/cache/soup-request-file.h
new file mode 100644
index 0000000..459e82a
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-request-file.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * 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 WEBKIT_SOUP_REQUEST_FILE_H
+#define WEBKIT_SOUP_REQUEST_FILE_H 1
+
+#include "soup-request.h"
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_SOUP_REQUEST_FILE (webkit_soup_request_file_get_type ())
+#define WEBKIT_SOUP_REQUEST_FILE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), WEBKIT_TYPE_SOUP_REQUEST_FILE, WebKitSoupRequestFile))
+#define WEBKIT_SOUP_REQUEST_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_SOUP_REQUEST_FILE, WebKitSoupRequestFileClass))
+#define WEBKIT_IS_SOUP_REQUEST_FILE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), WEBKIT_TYPE_SOUP_REQUEST_FILE))
+#define WEBKIT_IS_SOUP_REQUEST_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_SOUP_REQUEST_FILE))
+#define WEBKIT_SOUP_REQUEST_FILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), WEBKIT_TYPE_SOUP_REQUEST_FILE, WebKitSoupRequestFileClass))
+
+typedef struct _WebKitSoupRequestFilePrivate WebKitSoupRequestFilePrivate;
+
+typedef struct {
+ WebKitSoupRequest parent;
+
+ WebKitSoupRequestFilePrivate *priv;
+} WebKitSoupRequestFile;
+
+typedef struct {
+ WebKitSoupRequestClass parent;
+} WebKitSoupRequestFileClass;
+
+GType webkit_soup_request_file_get_type (void);
+
+GFile *webkit_soup_request_file_get_file (WebKitSoupRequestFile *file);
+
+G_END_DECLS
+
+#endif /* WEBKIT_SOUP_REQUEST_FILE_H */
diff --git a/WebCore/platform/network/soup/cache/soup-request-http.c b/WebCore/platform/network/soup/cache/soup-request-http.c
new file mode 100644
index 0000000..f157cfc
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-request-http.c
@@ -0,0 +1,340 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-request-http.c: http: URI request object
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include "soup-cache.h"
+#include "soup-cache-private.h"
+#include "soup-http-input-stream.h"
+#include "soup-request-http.h"
+
+G_DEFINE_TYPE (WebKitSoupRequestHTTP, webkit_soup_request_http, WEBKIT_TYPE_SOUP_REQUEST)
+
+struct _WebKitSoupRequestHTTPPrivate {
+ SoupMessage *msg;
+};
+
+/**
+ * webkit_soup_request_http_get_message:
+ * @http: a #WebKitSoupRequestHTTP object
+ *
+ * Gets a new reference to the #SoupMessage associated to this SoupRequest
+ *
+ * Returns: a new reference to the #SoupMessage
+ **/
+SoupMessage *
+webkit_soup_request_http_get_message (WebKitSoupRequestHTTP *http)
+{
+ g_return_val_if_fail (WEBKIT_IS_SOUP_REQUEST_HTTP (http), NULL);
+
+ return g_object_ref (http->priv->msg);
+}
+
+static void
+webkit_soup_request_http_init (WebKitSoupRequestHTTP *http)
+{
+ http->priv = G_TYPE_INSTANCE_GET_PRIVATE (http, WEBKIT_TYPE_SOUP_REQUEST_HTTP, WebKitSoupRequestHTTPPrivate);
+}
+
+static gboolean
+webkit_soup_request_http_check_uri (WebKitSoupRequest *request,
+ SoupURI *uri,
+ GError **error)
+{
+ WebKitSoupRequestHTTP *http = WEBKIT_SOUP_REQUEST_HTTP (request);
+
+ if (!SOUP_URI_VALID_FOR_HTTP (uri))
+ return FALSE;
+
+ http->priv->msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+ return TRUE;
+}
+
+static void
+webkit_soup_request_http_finalize (GObject *object)
+{
+ WebKitSoupRequestHTTP *http = WEBKIT_SOUP_REQUEST_HTTP (object);
+
+ if (http->priv->msg)
+ g_object_unref (http->priv->msg);
+
+ G_OBJECT_CLASS (webkit_soup_request_http_parent_class)->finalize (object);
+}
+
+static GInputStream *
+webkit_soup_request_http_send (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupHTTPInputStream *httpstream;
+ WebKitSoupRequestHTTP *http = WEBKIT_SOUP_REQUEST_HTTP (request);
+
+ httpstream = webkit_soup_http_input_stream_new (webkit_soup_request_get_session (request), http->priv->msg);
+ if (!webkit_soup_http_input_stream_send (httpstream, cancellable, error)) {
+ g_object_unref (httpstream);
+ return NULL;
+ }
+ return (GInputStream *)httpstream;
+}
+
+
+static void
+sent_async (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+ WebKitSoupHTTPInputStream *httpstream = WEBKIT_SOUP_HTTP_INPUT_STREAM (source);
+ GSimpleAsyncResult *simple = user_data;
+ GError *error = NULL;
+
+ if (webkit_soup_http_input_stream_send_finish (httpstream, result, &error)) {
+ g_simple_async_result_set_op_res_gpointer (simple, httpstream, g_object_unref);
+ } else {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ g_object_unref (httpstream);
+ }
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+
+typedef struct {
+ WebKitSoupRequestHTTP *req;
+ SoupMessage *original;
+ GCancellable *cancellable;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} ConditionalHelper;
+
+
+static void
+conditional_get_ready_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
+{
+ ConditionalHelper *helper = (ConditionalHelper *)user_data;
+ GSimpleAsyncResult *simple;
+ WebKitSoupHTTPInputStream *httpstream;
+
+ simple = g_simple_async_result_new (G_OBJECT (helper->req),
+ helper->callback, helper->user_data,
+ conditional_get_ready_cb);
+
+ if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) {
+ WebKitSoupCache *cache = (WebKitSoupCache *)soup_session_get_feature (session, WEBKIT_TYPE_SOUP_CACHE);
+
+ httpstream = (WebKitSoupHTTPInputStream *)webkit_soup_cache_send_response (cache, msg);
+ if (httpstream) {
+ const gchar *content_type;
+
+ g_simple_async_result_set_op_res_gpointer (simple, httpstream, g_object_unref);
+
+ soup_message_got_headers (helper->original);
+ content_type = soup_message_headers_get_content_type (msg->response_headers, NULL);
+ soup_message_content_sniffed (helper->original, content_type, NULL);
+
+ g_simple_async_result_complete (simple);
+
+ soup_message_finished (helper->original);
+
+ g_object_unref (simple);
+ } else {
+ /* Ask again for the resource, somehow the cache cannot locate it */
+ httpstream = webkit_soup_http_input_stream_new (session, helper->original);
+ webkit_soup_http_input_stream_send_async (httpstream, G_PRIORITY_DEFAULT,
+ helper->cancellable, sent_async, simple);
+ }
+ } else {
+ /* It is in the cache but it was modified remotely */
+ httpstream = webkit_soup_http_input_stream_new (session, helper->original);
+ webkit_soup_http_input_stream_send_async (httpstream, G_PRIORITY_DEFAULT,
+ helper->cancellable, sent_async, simple);
+ }
+
+ g_object_unref (helper->req);
+ g_object_unref (helper->original);
+ g_slice_free (ConditionalHelper, helper);
+}
+
+typedef struct {
+ WebKitSoupRequestHTTP *http;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} SendAsyncHelper;
+
+static void webkit_soup_request_http_send_async (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static gboolean
+send_async_cb (gpointer data)
+{
+ GSimpleAsyncResult *simple;
+ WebKitSoupHTTPInputStream *httpstream;
+ SoupSession *session;
+ WebKitSoupCache *cache;
+ SendAsyncHelper *helper = (SendAsyncHelper *)data;
+
+ session = webkit_soup_request_get_session (WEBKIT_SOUP_REQUEST (helper->http));
+ cache = (WebKitSoupCache *)soup_session_get_feature (session, WEBKIT_TYPE_SOUP_CACHE);
+
+ httpstream = (WebKitSoupHTTPInputStream *)webkit_soup_cache_send_response (cache, SOUP_MESSAGE (helper->http->priv->msg));
+
+ if (httpstream) {
+ const gchar *content_type;
+
+ simple = g_simple_async_result_new (G_OBJECT (helper->http),
+ helper->callback, helper->user_data,
+ webkit_soup_request_http_send_async);
+ g_simple_async_result_set_op_res_gpointer (simple, httpstream, g_object_unref);
+
+ /* Update message status */
+ soup_message_set_status (helper->http->priv->msg, SOUP_STATUS_OK);
+
+ /* Issue signals */
+ soup_message_got_headers (helper->http->priv->msg);
+ content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL);
+ soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL);
+
+ g_simple_async_result_complete (simple);
+
+ soup_message_finished (helper->http->priv->msg);
+
+ g_object_unref (simple);
+ }
+
+ g_slice_free (SendAsyncHelper, helper);
+
+ return FALSE;
+}
+
+static void
+webkit_soup_request_http_send_async (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ WebKitSoupRequestHTTP *http = WEBKIT_SOUP_REQUEST_HTTP (request);
+ WebKitSoupHTTPInputStream *httpstream;
+ GSimpleAsyncResult *simple;
+ SoupSession *session;
+ WebKitSoupCache *cache;
+
+ session = webkit_soup_request_get_session (request);
+ cache = (WebKitSoupCache *)soup_session_get_feature (session, WEBKIT_TYPE_SOUP_CACHE);
+
+ if (cache) {
+ WebKitSoupCacheResponse response;
+
+ response = webkit_soup_cache_has_response (cache, http->priv->msg);
+ if (response == WEBKIT_SOUP_CACHE_RESPONSE_FRESH) {
+ /* Do return the stream asynchronously as in
+ the other cases. It's not enough to use
+ g_simple_async_result_complete_in_idle as
+ the signals must be also emitted
+ asynchronously */
+ SendAsyncHelper *helper = g_slice_new (SendAsyncHelper);
+ helper->http = http;
+ helper->callback = callback;
+ helper->user_data = user_data;
+ g_timeout_add (0, send_async_cb, helper);
+ return;
+ } else if (response == WEBKIT_SOUP_CACHE_RESPONSE_NEEDS_VALIDATION) {
+ SoupMessage *conditional_msg;
+ ConditionalHelper *helper;
+
+ conditional_msg = webkit_soup_cache_generate_conditional_request (cache, http->priv->msg);
+
+ helper = g_slice_new0 (ConditionalHelper);
+ helper->req = g_object_ref (http);
+ helper->original = g_object_ref (http->priv->msg);
+ helper->cancellable = cancellable;
+ helper->callback = callback;
+ helper->user_data = user_data;
+ soup_session_queue_message (session, conditional_msg,
+ conditional_get_ready_cb,
+ helper);
+ return;
+ }
+ }
+
+ simple = g_simple_async_result_new (G_OBJECT (http),
+ callback, user_data,
+ webkit_soup_request_http_send_async);
+ httpstream = webkit_soup_http_input_stream_new (webkit_soup_request_get_session (request),
+ http->priv->msg);
+ webkit_soup_http_input_stream_send_async (httpstream, G_PRIORITY_DEFAULT,
+ cancellable, sent_async, simple);
+}
+
+static GInputStream *
+webkit_soup_request_http_send_finish (WebKitSoupRequest *request,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (request), webkit_soup_request_http_send_async) || g_simple_async_result_is_valid (result, G_OBJECT (request), conditional_get_ready_cb), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+ return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+static goffset
+webkit_soup_request_http_get_content_length (WebKitSoupRequest *request)
+{
+ WebKitSoupRequestHTTP *http = WEBKIT_SOUP_REQUEST_HTTP (request);
+
+ return soup_message_headers_get_content_length (http->priv->msg->response_headers);
+}
+
+static const char *
+webkit_soup_request_http_get_content_type (WebKitSoupRequest *request)
+{
+ WebKitSoupRequestHTTP *http = WEBKIT_SOUP_REQUEST_HTTP (request);
+
+ return soup_message_headers_get_content_type (http->priv->msg->response_headers, NULL);
+}
+
+static void
+webkit_soup_request_http_class_init (WebKitSoupRequestHTTPClass *request_http_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (request_http_class);
+ WebKitSoupRequestClass *request_class =
+ WEBKIT_SOUP_REQUEST_CLASS (request_http_class);
+
+ g_type_class_add_private (request_http_class, sizeof (WebKitSoupRequestHTTPPrivate));
+
+ object_class->finalize = webkit_soup_request_http_finalize;
+
+ request_class->check_uri = webkit_soup_request_http_check_uri;
+ request_class->send = webkit_soup_request_http_send;
+ request_class->send_async = webkit_soup_request_http_send_async;
+ request_class->send_finish = webkit_soup_request_http_send_finish;
+ request_class->get_content_length = webkit_soup_request_http_get_content_length;
+ request_class->get_content_type = webkit_soup_request_http_get_content_type;
+}
diff --git a/WebCore/platform/network/soup/cache/soup-request-http.h b/WebCore/platform/network/soup/cache/soup-request-http.h
new file mode 100644
index 0000000..a06a821
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-request-http.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * 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 WEBKIT_SOUP_REQUEST_HTTP_H
+#define WEBKIT_SOUP_REQUEST_HTTP_H 1
+
+#include "soup-request.h"
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_SOUP_REQUEST_HTTP (webkit_soup_request_http_get_type ())
+#define WEBKIT_SOUP_REQUEST_HTTP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), WEBKIT_TYPE_SOUP_REQUEST_HTTP, WebKitSoupRequestHTTP))
+#define WEBKIT_SOUP_REQUEST_HTTP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_SOUP_REQUEST_HTTP, WebKitSoupRequestHTTPClass))
+#define WEBKIT_IS_SOUP_REQUEST_HTTP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), WEBKIT_TYPE_SOUP_REQUEST_HTTP))
+#define WEBKIT_IS_SOUP_REQUEST_HTTP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_SOUP_REQUEST_HTTP))
+#define WEBKIT_SOUP_REQUEST_HTTP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), WEBKIT_TYPE_SOUP_REQUEST_HTTP, WebKitSoupRequestHTTPClass))
+
+typedef struct _WebKitSoupRequestHTTPPrivate WebKitSoupRequestHTTPPrivate;
+
+typedef struct {
+ WebKitSoupRequest parent;
+
+ WebKitSoupRequestHTTPPrivate *priv;
+} WebKitSoupRequestHTTP;
+
+typedef struct {
+ WebKitSoupRequestClass parent;
+} WebKitSoupRequestHTTPClass;
+
+GType webkit_soup_request_http_get_type (void);
+
+SoupMessage *webkit_soup_request_http_get_message (WebKitSoupRequestHTTP *http);
+
+G_END_DECLS
+
+#endif /* WEBKIT_SOUP_REQUEST_HTTP_H */
diff --git a/WebCore/platform/network/soup/cache/soup-request.c b/WebCore/platform/network/soup/cache/soup-request.c
new file mode 100644
index 0000000..46b9f5a
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-request.c
@@ -0,0 +1,312 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-request.c: Protocol-independent streaming request interface
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include "soup-request.h"
+#include "soup-requester.h"
+
+/**
+ * SECTION:soup-request
+ * @short_description: Protocol-independent streaming request interface
+ *
+ * FIXME
+ **/
+
+/**
+ * WebKitSoupRequest:
+ *
+ * FIXME
+ *
+ * Since: 2.30
+ **/
+
+static void webkit_soup_request_initable_interface_init (GInitableIface *initable_interface);
+
+G_DEFINE_TYPE_WITH_CODE (WebKitSoupRequest, webkit_soup_request, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ webkit_soup_request_initable_interface_init))
+
+enum {
+ PROP_0,
+ PROP_URI,
+ PROP_SESSION
+};
+
+struct _WebKitSoupRequestPrivate {
+ SoupURI *uri;
+ SoupSession *session;
+};
+
+static void
+webkit_soup_request_init (WebKitSoupRequest *request)
+{
+ request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, WEBKIT_TYPE_SOUP_REQUEST, WebKitSoupRequestPrivate);
+}
+
+static void
+webkit_soup_request_finalize (GObject *object)
+{
+ WebKitSoupRequest *request = WEBKIT_SOUP_REQUEST (object);
+
+ if (request->priv->uri)
+ soup_uri_free (request->priv->uri);
+ if (request->priv->session)
+ g_object_unref (request->priv->session);
+
+ G_OBJECT_CLASS (webkit_soup_request_parent_class)->finalize (object);
+}
+
+static void
+webkit_soup_request_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ WebKitSoupRequest *request = WEBKIT_SOUP_REQUEST (object);
+
+ switch (prop_id) {
+ case PROP_URI:
+ if (request->priv->uri)
+ soup_uri_free (request->priv->uri);
+ request->priv->uri = g_value_dup_boxed (value);
+ break;
+ case PROP_SESSION:
+ if (request->priv->session)
+ g_object_unref (request->priv->session);
+ request->priv->session = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+webkit_soup_request_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ WebKitSoupRequest *request = WEBKIT_SOUP_REQUEST (object);
+
+ switch (prop_id) {
+ case PROP_URI:
+ g_value_set_boxed (value, request->priv->uri);
+ break;
+ case PROP_SESSION:
+ g_value_set_object (value, request->priv->session);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+webkit_soup_request_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ WebKitSoupRequest *request = WEBKIT_SOUP_REQUEST (initable);
+ gboolean ok;
+
+ if (!request->priv->uri) {
+ g_set_error (error, WEBKIT_SOUP_ERROR, WEBKIT_SOUP_ERROR_BAD_URI,
+ _ ("No URI provided"));
+ return FALSE;
+ }
+
+ ok = WEBKIT_SOUP_REQUEST_GET_CLASS (initable)->
+ check_uri (request, request->priv->uri, error);
+
+ if (!ok && error) {
+ char *uri_string = soup_uri_to_string (request->priv->uri, FALSE);
+ g_set_error (error, WEBKIT_SOUP_ERROR, WEBKIT_SOUP_ERROR_BAD_URI,
+ _ ("Invalid '%s' URI: %s"),
+ request->priv->uri->scheme,
+ uri_string);
+ g_free (uri_string);
+ }
+
+ return ok;
+}
+
+static gboolean
+webkit_soup_request_default_check_uri (WebKitSoupRequest *request,
+ SoupURI *uri,
+ GError **error)
+{
+ return TRUE;
+}
+
+/* Default implementation: assume the sync implementation doesn't block */
+static void
+webkit_soup_request_default_send_async (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (G_OBJECT (request),
+ callback, user_data,
+ webkit_soup_request_default_send_async);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+}
+
+static GInputStream *
+webkit_soup_request_default_send_finish (WebKitSoupRequest *request,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (request), webkit_soup_request_default_send_async), NULL);
+
+ return webkit_soup_request_send (request, NULL, error);
+}
+
+GInputStream *
+webkit_soup_request_send (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return WEBKIT_SOUP_REQUEST_GET_CLASS (request)->
+ send (request, cancellable, error);
+}
+
+void
+webkit_soup_request_send_async (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ WEBKIT_SOUP_REQUEST_GET_CLASS (request)->
+ send_async (request, cancellable, callback, user_data);
+}
+
+GInputStream *
+webkit_soup_request_send_finish (WebKitSoupRequest *request,
+ GAsyncResult *result,
+ GError **error)
+{
+ return WEBKIT_SOUP_REQUEST_GET_CLASS (request)->
+ send_finish (request, result, error);
+}
+
+static void
+webkit_soup_request_class_init (WebKitSoupRequestClass *request_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (request_class);
+
+ g_type_class_add_private (request_class, sizeof (WebKitSoupRequestPrivate));
+
+ request_class->check_uri = webkit_soup_request_default_check_uri;
+ request_class->send_async = webkit_soup_request_default_send_async;
+ request_class->send_finish = webkit_soup_request_default_send_finish;
+
+ object_class->finalize = webkit_soup_request_finalize;
+ object_class->set_property = webkit_soup_request_set_property;
+ object_class->get_property = webkit_soup_request_get_property;
+
+ g_object_class_install_property (
+ object_class, PROP_URI,
+ g_param_spec_boxed (WEBKIT_SOUP_REQUEST_URI,
+ "URI",
+ "The request URI",
+ SOUP_TYPE_URI,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (
+ object_class, PROP_SESSION,
+ g_param_spec_object (WEBKIT_SOUP_REQUEST_SESSION,
+ "Session",
+ "The request's session",
+ SOUP_TYPE_SESSION,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+webkit_soup_request_initable_interface_init (GInitableIface *initable_interface)
+{
+ initable_interface->init = webkit_soup_request_initable_init;
+}
+
+SoupURI *
+webkit_soup_request_get_uri (WebKitSoupRequest *request)
+{
+ return request->priv->uri;
+}
+
+SoupSession *
+webkit_soup_request_get_session (WebKitSoupRequest *request)
+{
+ return request->priv->session;
+}
+
+goffset
+webkit_soup_request_get_content_length (WebKitSoupRequest *request)
+{
+ return WEBKIT_SOUP_REQUEST_GET_CLASS (request)->get_content_length (request);
+}
+
+const char *
+webkit_soup_request_get_content_type (WebKitSoupRequest *request)
+{
+ return WEBKIT_SOUP_REQUEST_GET_CLASS (request)->get_content_type (request);
+}
+
+#define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
+#define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2]))
+
+/* Copy&pasted from libsoup's soup-uri.c after applying the patch in
+ * https://bugzilla.gnome.org/show_bug.cgi?id=630540. We need this
+ * instead of soup_uri_decode() as it incorrectly returns NULL for
+ * incorrectly encoded URLs. TODO: remove this when required libsoup
+ * version is bumped out to 2.32.1
+ */
+gchar *
+webkit_soup_request_uri_decoded_copy (const char *part, int length)
+{
+ unsigned char *s, *d;
+ char *decoded = g_strndup (part, length);
+
+ s = d = (unsigned char *)decoded;
+ do {
+ if (*s == '%') {
+ if (!g_ascii_isxdigit (s[1]) ||
+ !g_ascii_isxdigit (s[2])) {
+ *d++ = *s;
+ continue;
+ }
+ *d++ = HEXCHAR (s);
+ s += 2;
+ } else
+ *d++ = *s;
+ } while (*s++);
+
+ return decoded;
+}
diff --git a/WebCore/platform/network/soup/cache/soup-request.h b/WebCore/platform/network/soup/cache/soup-request.h
new file mode 100644
index 0000000..837d8f4
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-request.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * 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 WEBKIT_SOUP_REQUEST_H
+#define WEBKIT_SOUP_REQUEST_H 1
+
+#include <libsoup/soup.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_SOUP_REQUEST (webkit_soup_request_get_type ())
+#define WEBKIT_SOUP_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_SOUP_REQUEST, WebKitSoupRequest))
+#define WEBKIT_SOUP_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_SOUP_REQUEST, WebKitSoupRequestClass))
+#define WEBKIT_IS_SOUP_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_SOUP_REQUEST))
+#define WEBKIT_IS_SOUP_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_SOUP_REQUEST))
+#define WEBKIT_SOUP_REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), WEBKIT_TYPE_SOUP_REQUEST, WebKitSoupRequestClass))
+
+typedef struct _WebKitSoupRequest WebKitSoupRequest;
+typedef struct _WebKitSoupRequestPrivate WebKitSoupRequestPrivate;
+typedef struct _WebKitSoupRequestClass WebKitSoupRequestClass;
+
+struct _WebKitSoupRequest {
+ GObject parent;
+
+ WebKitSoupRequestPrivate *priv;
+};
+
+struct _WebKitSoupRequestClass {
+ GObjectClass parent;
+
+ gboolean (*check_uri)(WebKitSoupRequest *req_base,
+ SoupURI *uri,
+ GError **error);
+
+ GInputStream * (*send)(WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GError **error);
+ void (*send_async)(WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ GInputStream * (*send_finish)(WebKitSoupRequest *request,
+ GAsyncResult *result,
+ GError **error);
+
+ goffset (*get_content_length)(WebKitSoupRequest *request);
+ const char * (*get_content_type)(WebKitSoupRequest *request);
+};
+
+GType webkit_soup_request_get_type (void);
+
+#define WEBKIT_SOUP_REQUEST_URI "uri"
+#define WEBKIT_SOUP_REQUEST_SESSION "session"
+
+GInputStream *webkit_soup_request_send (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GError **error);
+void webkit_soup_request_send_async (WebKitSoupRequest *request,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GInputStream *webkit_soup_request_send_finish (WebKitSoupRequest *request,
+ GAsyncResult *result,
+ GError **error);
+
+SoupURI *webkit_soup_request_get_uri (WebKitSoupRequest *request);
+SoupSession *webkit_soup_request_get_session (WebKitSoupRequest *request);
+
+goffset webkit_soup_request_get_content_length (WebKitSoupRequest *request);
+const char *webkit_soup_request_get_content_type (WebKitSoupRequest *request);
+
+/* Used by WebKitSoupRequestFile and WebKitSoupRequestData. Ideally
+ * should be located in some util file but I'll place it here as it
+ * will be removed with libsoup 2.32.1 that will ship fixed versions
+ * of soup_uri_decode/normalize
+ */
+gchar *webkit_soup_request_uri_decoded_copy (const char *part, int length);
+
+G_END_DECLS
+
+#endif /* WEBKIT_SOUP_REQUEST_H */
diff --git a/WebCore/platform/network/soup/cache/soup-requester.c b/WebCore/platform/network/soup/cache/soup-requester.c
new file mode 100644
index 0000000..4d8a860
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-requester.c
@@ -0,0 +1,188 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-requester.c:
+ *
+ * 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 "soup-requester.h"
+
+#include "soup-request-data.h"
+#include "soup-request-file.h"
+#include "soup-request-http.h"
+#include <glib/gi18n.h>
+#include <libsoup/soup.h>
+
+struct _WebKitSoupRequesterPrivate {
+ GHashTable *request_types;
+};
+
+#define WEBKIT_SOUP_REQUESTER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), WEBKIT_TYPE_SOUP_REQUESTER, WebKitSoupRequesterPrivate))
+
+G_DEFINE_TYPE (WebKitSoupRequester, webkit_soup_requester, G_TYPE_OBJECT)
+
+static void webkit_soup_requester_init (WebKitSoupRequester *requester)
+{
+ requester->priv = WEBKIT_SOUP_REQUESTER_GET_PRIVATE (requester);
+
+ requester->priv->request_types = 0;
+}
+
+static void finalize (GObject *object)
+{
+ WebKitSoupRequester *requester = WEBKIT_SOUP_REQUESTER (object);
+
+ if (requester->priv->request_types)
+ g_hash_table_destroy (requester->priv->request_types);
+
+ G_OBJECT_CLASS (webkit_soup_requester_parent_class)->finalize (object);
+}
+
+static void webkit_soup_requester_class_init (WebKitSoupRequesterClass *requester_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (requester_class);
+
+ g_type_class_add_private (requester_class, sizeof (WebKitSoupRequesterPrivate));
+
+ /* virtual method override */
+ object_class->finalize = finalize;
+}
+
+static void init_request_types (WebKitSoupRequesterPrivate *priv)
+{
+ if (priv->request_types)
+ return;
+
+ priv->request_types = g_hash_table_new_full (soup_str_case_hash,
+ soup_str_case_equal,
+ g_free, 0);
+ g_hash_table_insert (priv->request_types, g_strdup ("file"),
+ GSIZE_TO_POINTER (WEBKIT_TYPE_SOUP_REQUEST_FILE));
+ g_hash_table_insert (priv->request_types, g_strdup ("data"),
+ GSIZE_TO_POINTER (WEBKIT_TYPE_SOUP_REQUEST_DATA));
+ g_hash_table_insert (priv->request_types, g_strdup ("http"),
+ GSIZE_TO_POINTER (WEBKIT_TYPE_SOUP_REQUEST_HTTP));
+ g_hash_table_insert (priv->request_types, g_strdup ("https"),
+ GSIZE_TO_POINTER (WEBKIT_TYPE_SOUP_REQUEST_HTTP));
+ g_hash_table_insert (priv->request_types, g_strdup ("ftp"),
+ GSIZE_TO_POINTER (WEBKIT_TYPE_SOUP_REQUEST_FILE));
+}
+
+WebKitSoupRequester *webkit_soup_requester_new (void)
+{
+ return (WebKitSoupRequester *)g_object_new (WEBKIT_TYPE_SOUP_REQUESTER, NULL);
+}
+
+WebKitSoupRequest *webkit_soup_requester_request (WebKitSoupRequester *requester, const char *uriString, SoupSession *session, GError **error)
+{
+ SoupURI *uri = NULL;
+ WebKitSoupRequest *req;
+
+ uri = soup_uri_new (uriString);
+ if (!uri) {
+ g_set_error (error, WEBKIT_SOUP_ERROR, WEBKIT_SOUP_ERROR_BAD_URI,
+ _ ("Could not parse URI '%s'"), uriString);
+ return 0;
+ }
+
+ req = webkit_soup_requester_request_uri (requester, uri, session, error);
+ soup_uri_free (uri);
+ return req;
+}
+
+WebKitSoupRequest *webkit_soup_requester_request_uri (WebKitSoupRequester *requester, SoupURI *uri, SoupSession *session, GError **error)
+{
+ GType requestType;
+
+ g_return_val_if_fail (WEBKIT_IS_SOUP_REQUESTER (requester), 0);
+
+ init_request_types (requester->priv);
+ requestType = (GType)GPOINTER_TO_SIZE (g_hash_table_lookup (requester->priv->request_types, uri->scheme));
+ if (!requestType) {
+ g_set_error (error, WEBKIT_SOUP_ERROR, WEBKIT_SOUP_ERROR_UNSUPPORTED_URI_SCHEME,
+ _ ("Unsupported URI scheme '%s'"), uri->scheme);
+ return 0;
+ }
+
+ if (g_type_is_a (requestType, G_TYPE_INITABLE)) {
+ return (WebKitSoupRequest *)g_initable_new (requestType, 0, error,
+ "uri", uri,
+ "session", session,
+ NULL);
+ } else {
+ return (WebKitSoupRequest *)g_object_new (requestType,
+ "uri", uri,
+ "session", session,
+ NULL);
+ }
+}
+
+/* RFC 2396, 3.1 */
+static gboolean
+soup_scheme_is_valid (const char *scheme)
+{
+ if (scheme == NULL ||
+ !g_ascii_isalpha (*scheme))
+ return FALSE;
+
+ scheme++;
+ while (*scheme) {
+ if (!g_ascii_isalpha (*scheme) &&
+ !g_ascii_isdigit (*scheme) &&
+ *scheme != '+' &&
+ *scheme != '-' &&
+ *scheme != '.')
+ return FALSE;
+ scheme++;
+ }
+ return TRUE;
+}
+
+void
+webkit_soup_requester_add_protocol (WebKitSoupRequester *requester,
+ const char *scheme,
+ GType request_type)
+{
+ g_return_if_fail (WEBKIT_IS_SOUP_REQUESTER (requester));
+ g_return_if_fail (soup_scheme_is_valid (scheme));
+
+ init_request_types (requester->priv);
+ g_hash_table_insert (requester->priv->request_types, g_strdup (scheme),
+ GSIZE_TO_POINTER (request_type));
+}
+
+void
+webkit_soup_requester_remove_protocol (WebKitSoupRequester *requester,
+ const char *scheme)
+{
+ g_return_if_fail (WEBKIT_IS_SOUP_REQUESTER (requester));
+ g_return_if_fail (soup_scheme_is_valid (scheme));
+
+ init_request_types (requester->priv);
+ g_hash_table_remove (requester->priv->request_types, scheme);
+}
+
+GQuark
+webkit_soup_error_quark (void)
+{
+ static GQuark error;
+ if (!error)
+ error = g_quark_from_static_string ("webkit_soup_error_quark");
+ return error;
+}
diff --git a/WebCore/platform/network/soup/cache/soup-requester.h b/WebCore/platform/network/soup/cache/soup-requester.h
new file mode 100644
index 0000000..71ff103
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/soup-requester.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * 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 WEBKIT_SOUP_REQUESTER_H
+#define WEBKIT_SOUP_REQUESTER_H 1
+
+#include "soup-request.h"
+#include <libsoup/soup.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_SOUP_REQUESTER (webkit_soup_requester_get_type ())
+#define WEBKIT_SOUP_REQUESTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_SOUP_REQUESTER, WebKitSoupRequester))
+#define WEBKIT_SOUP_REQUESTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_SOUP_REQUESTER, WebKitSoupRequesterClass))
+#define WEBKIT_IS_SOUP_REQUESTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_SOUP_REQUESTER))
+#define WEBKIT_IS_SOUP_REQUESTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), WEBKIT_TYPE_SOUP_REQUESTER))
+#define WEBKIT_SOUP_REQUESTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), WEBKIT_TYPE_SOUP_REQUESTER, WebKitSoupRequesterClass))
+
+#define WEBKIT_SOUP_ERROR webkit_soup_error_quark ()
+
+typedef enum {
+ WEBKIT_SOUP_ERROR_BAD_URI,
+ WEBKIT_SOUP_ERROR_UNSUPPORTED_URI_SCHEME
+} WebKitSoupError;
+
+typedef struct _WebKitSoupRequester WebKitSoupRequester;
+typedef struct _WebKitSoupRequesterPrivate WebKitSoupRequesterPrivate;
+
+struct _WebKitSoupRequester {
+ GObject parent;
+
+ WebKitSoupRequesterPrivate *priv;
+};
+
+typedef struct {
+ GObjectClass parent_class;
+} WebKitSoupRequesterClass;
+
+GType webkit_soup_requester_get_type (void);
+
+WebKitSoupRequester *webkit_soup_requester_new (void);
+
+GQuark webkit_soup_error_quark (void);
+
+WebKitSoupRequest *webkit_soup_requester_request (WebKitSoupRequester *requester,
+ const char *uriString,
+ SoupSession *session,
+ GError **error);
+
+WebKitSoupRequest *webkit_soup_requester_request_uri (WebKitSoupRequester *requester,
+ SoupURI *uri,
+ SoupSession *session,
+ GError **error);
+
+void webkit_soup_requester_add_protocol (WebKitSoupRequester *requester,
+ const char *scheme,
+ GType request_type);
+
+void webkit_soup_requester_remove_protocol (WebKitSoupRequester *requester,
+ const char *scheme);
+
+G_END_DECLS
+
+#endif /* WEBKIT_SOUP_REQUESTER_H */
diff --git a/WebCore/platform/network/soup/cache/webkit/soup-cache-private.h b/WebCore/platform/network/soup/cache/webkit/soup-cache-private.h
new file mode 100644
index 0000000..8af8de2
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/webkit/soup-cache-private.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-cache-private.h:
+ *
+ * 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 WEBKIT_SOUP_CACHE_PRIVATE_H
+#define WEBKIT_SOUP_CACHE_PRIVATE_H 1
+
+#include "soup-cache.h"
+#include <libsoup/soup-message.h>
+
+G_BEGIN_DECLS
+
+WebKitSoupCacheResponse webkit_soup_cache_has_response (WebKitSoupCache *cache,
+ SoupMessage *msg);
+GInputStream *webkit_soup_cache_send_response (WebKitSoupCache *cache,
+ SoupMessage *msg);
+WebKitSoupCacheability webkit_soup_cache_get_cacheability (WebKitSoupCache *cache,
+ SoupMessage *msg);
+SoupMessage *webkit_soup_cache_generate_conditional_request (WebKitSoupCache *cache,
+ SoupMessage *original);
+
+G_END_DECLS
+
+#endif /* WEBKIT_SOUP_CACHE_PRIVATE_H */
diff --git a/WebCore/platform/network/soup/cache/webkit/soup-cache.c b/WebCore/platform/network/soup/cache/webkit/soup-cache.c
new file mode 100644
index 0000000..73b15ba
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/webkit/soup-cache.c
@@ -0,0 +1,1653 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-cache.c
+ *
+ * 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
+ * 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.
+ */
+
+/* TODO:
+ * - Need to hook the feature in the sync SoupSession.
+ * - Need more tests.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-cache.h"
+#include "soup-cache-private.h"
+#include <libsoup/soup.h>
+#include <gio/gio.h>
+#include <stdlib.h>
+
+static SoupSessionFeatureInterface *webkit_soup_cache_default_feature_interface;
+static void webkit_soup_cache_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data);
+
+#define DEFAULT_MAX_SIZE 50 * 1024 * 1024
+#define MAX_ENTRY_DATA_PERCENTAGE 10 /* Percentage of the total size
+ of the cache that can be
+ filled by a single entry */
+
+typedef struct _WebKitSoupCacheEntry {
+ char *key;
+ char *filename;
+ guint freshness_lifetime;
+ gboolean must_revalidate;
+ GString *data;
+ gsize pos;
+ gsize length;
+ time_t corrected_initial_age;
+ time_t response_time;
+ gboolean writing;
+ gboolean dirty;
+ gboolean got_body;
+ gboolean being_validated;
+ SoupMessageHeaders *headers;
+ GOutputStream *stream;
+ GError *error;
+ guint hits;
+ GCancellable *cancellable;
+} WebKitSoupCacheEntry;
+
+struct _WebKitSoupCachePrivate {
+ char *cache_dir;
+ GHashTable *cache;
+ guint n_pending;
+ SoupSession *session;
+ WebKitSoupCacheType cache_type;
+ guint size;
+ guint max_size;
+ guint max_entry_data_size; /* Computed value. Here for performance reasons */
+ GList *lru_start;
+};
+
+typedef struct {
+ WebKitSoupCache *cache;
+ WebKitSoupCacheEntry *entry;
+ SoupMessage *msg;
+ gulong got_chunk_handler;
+ gulong got_body_handler;
+ gulong restarted_handler;
+} WebKitSoupCacheWritingFixture;
+
+enum {
+ PROP_0,
+ PROP_CACHE_DIR,
+ PROP_CACHE_TYPE
+};
+
+#define WEBKIT_SOUP_CACHE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), WEBKIT_TYPE_SOUP_CACHE, WebKitSoupCachePrivate))
+
+G_DEFINE_TYPE_WITH_CODE (WebKitSoupCache, webkit_soup_cache, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
+ webkit_soup_cache_session_feature_init))
+
+static gboolean webkit_soup_cache_entry_remove (WebKitSoupCache *cache, WebKitSoupCacheEntry *entry);
+static void make_room_for_new_entry (WebKitSoupCache *cache, guint length_to_add);
+static gboolean cache_accepts_entries_of_size (WebKitSoupCache *cache, guint length_to_add);
+
+static WebKitSoupCacheability
+get_cacheability (WebKitSoupCache *cache, SoupMessage *msg)
+{
+ WebKitSoupCacheability cacheability;
+ const char *cache_control;
+
+ /* 1. The request method must be cacheable */
+ if (msg->method == SOUP_METHOD_GET)
+ cacheability = WEBKIT_SOUP_CACHE_CACHEABLE;
+ else if (msg->method == SOUP_METHOD_HEAD ||
+ msg->method == SOUP_METHOD_TRACE ||
+ msg->method == SOUP_METHOD_CONNECT)
+ return WEBKIT_SOUP_CACHE_UNCACHEABLE;
+ else
+ return (WEBKIT_SOUP_CACHE_UNCACHEABLE | WEBKIT_SOUP_CACHE_INVALIDATES);
+
+ cache_control = soup_message_headers_get (msg->response_headers, "Cache-Control");
+ if (cache_control) {
+ GHashTable *hash;
+ WebKitSoupCachePrivate *priv = WEBKIT_SOUP_CACHE_GET_PRIVATE (cache);
+
+ hash = soup_header_parse_param_list (cache_control);
+
+ /* Shared caches MUST NOT store private resources */
+ if (priv->cache_type == WEBKIT_SOUP_CACHE_SHARED) {
+ if (g_hash_table_lookup_extended (hash, "private", NULL, NULL)) {
+ soup_header_free_param_list (hash);
+ return WEBKIT_SOUP_CACHE_UNCACHEABLE;
+ }
+ }
+
+ /* 2. The 'no-store' cache directive does not appear in the
+ * headers
+ */
+ if (g_hash_table_lookup_extended (hash, "no-store", NULL, NULL)) {
+ soup_header_free_param_list (hash);
+ return WEBKIT_SOUP_CACHE_UNCACHEABLE;
+ }
+
+ /* This does not appear in section 2.1, but I think it makes
+ * sense to check it too?
+ */
+ if (g_hash_table_lookup_extended (hash, "no-cache", NULL, NULL)) {
+ soup_header_free_param_list (hash);
+ return WEBKIT_SOUP_CACHE_UNCACHEABLE;
+ }
+ }
+
+ switch (msg->status_code) {
+ case SOUP_STATUS_PARTIAL_CONTENT:
+ /* We don't cache partial responses, but they only
+ * invalidate cached full responses if the headers
+ * don't match.
+ */
+ cacheability = WEBKIT_SOUP_CACHE_UNCACHEABLE;
+ break;
+
+ case SOUP_STATUS_NOT_MODIFIED:
+ /* A 304 response validates an existing cache entry */
+ cacheability = WEBKIT_SOUP_CACHE_VALIDATES;
+ break;
+
+ case SOUP_STATUS_MULTIPLE_CHOICES:
+ case SOUP_STATUS_MOVED_PERMANENTLY:
+ case SOUP_STATUS_GONE:
+ /* FIXME: cacheable unless indicated otherwise */
+ cacheability = WEBKIT_SOUP_CACHE_UNCACHEABLE;
+ break;
+
+ case SOUP_STATUS_FOUND:
+ case SOUP_STATUS_TEMPORARY_REDIRECT:
+ /* FIXME: cacheable if explicitly indicated */
+ cacheability = WEBKIT_SOUP_CACHE_UNCACHEABLE;
+ break;
+
+ case SOUP_STATUS_SEE_OTHER:
+ case SOUP_STATUS_FORBIDDEN:
+ case SOUP_STATUS_NOT_FOUND:
+ case SOUP_STATUS_METHOD_NOT_ALLOWED:
+ return (WEBKIT_SOUP_CACHE_UNCACHEABLE | WEBKIT_SOUP_CACHE_INVALIDATES);
+
+ default:
+ /* Any 5xx status or any 4xx status not handled above
+ * is uncacheable but doesn't break the cache.
+ */
+ if ((msg->status_code >= SOUP_STATUS_BAD_REQUEST &&
+ msg->status_code <= SOUP_STATUS_FAILED_DEPENDENCY) ||
+ msg->status_code >= SOUP_STATUS_INTERNAL_SERVER_ERROR)
+ return WEBKIT_SOUP_CACHE_UNCACHEABLE;
+
+ /* An unrecognized 2xx, 3xx, or 4xx response breaks
+ * the cache.
+ */
+ if ((msg->status_code > SOUP_STATUS_PARTIAL_CONTENT &&
+ msg->status_code < SOUP_STATUS_MULTIPLE_CHOICES) ||
+ (msg->status_code > SOUP_STATUS_TEMPORARY_REDIRECT &&
+ msg->status_code < SOUP_STATUS_INTERNAL_SERVER_ERROR))
+ return (WEBKIT_SOUP_CACHE_UNCACHEABLE | WEBKIT_SOUP_CACHE_INVALIDATES);
+ break;
+ }
+
+ return cacheability;
+}
+
+static void
+webkit_soup_cache_entry_free (WebKitSoupCacheEntry *entry, gboolean purge)
+{
+ if (purge) {
+ GFile *file = g_file_new_for_path (entry->filename);
+ g_file_delete (file, NULL, NULL);
+ g_object_unref (file);
+ }
+
+ g_free (entry->filename);
+ entry->filename = NULL;
+ g_free (entry->key);
+ entry->key = NULL;
+
+ if (entry->headers) {
+ soup_message_headers_free (entry->headers);
+ entry->headers = NULL;
+ }
+
+ if (entry->data) {
+ g_string_free (entry->data, TRUE);
+ entry->data = NULL;
+ }
+ if (entry->error) {
+ g_error_free (entry->error);
+ entry->error = NULL;
+ }
+ if (entry->cancellable) {
+ g_object_unref (entry->cancellable);
+ entry->cancellable = NULL;
+ }
+
+ g_slice_free (WebKitSoupCacheEntry, entry);
+}
+
+static void
+copy_headers (const char *name, const char *value, SoupMessageHeaders *headers)
+{
+ soup_message_headers_append (headers, name, value);
+}
+
+static void
+update_headers (const char *name, const char *value, SoupMessageHeaders *headers)
+{
+ if (soup_message_headers_get (headers, name))
+ soup_message_headers_replace (headers, name, value);
+ else
+ soup_message_headers_append (headers, name, value);
+}
+
+static guint
+webkit_soup_cache_entry_get_current_age (WebKitSoupCacheEntry *entry)
+{
+ time_t now = time (NULL);
+ time_t resident_time;
+
+ resident_time = now - entry->response_time;
+ return entry->corrected_initial_age + resident_time;
+}
+
+static gboolean
+webkit_soup_cache_entry_is_fresh_enough (WebKitSoupCacheEntry *entry, gint min_fresh)
+{
+ guint limit = (min_fresh == -1) ? webkit_soup_cache_entry_get_current_age (entry) : (guint) min_fresh;
+ return entry->freshness_lifetime > limit;
+}
+
+static char *
+soup_message_get_cache_key (SoupMessage *msg)
+{
+ SoupURI *uri = soup_message_get_uri (msg);
+ return soup_uri_to_string (uri, FALSE);
+}
+
+static void
+webkit_soup_cache_entry_set_freshness (WebKitSoupCacheEntry *entry, SoupMessage *msg, WebKitSoupCache *cache)
+{
+ const char *cache_control;
+ const char *expires, *date, *last_modified;
+ GHashTable *hash;
+
+ hash = NULL;
+
+ cache_control = soup_message_headers_get (entry->headers, "Cache-Control");
+ if (cache_control) {
+ const char *max_age, *s_maxage;
+ gint64 freshness_lifetime = 0;
+ WebKitSoupCachePrivate *priv = WEBKIT_SOUP_CACHE_GET_PRIVATE (cache);
+
+ hash = soup_header_parse_param_list (cache_control);
+
+ /* Should we re-validate the entry when it goes stale */
+ entry->must_revalidate = g_hash_table_lookup_extended (hash, "must-revalidate", NULL, NULL);
+
+ /* Section 2.3.1 */
+ if (priv->cache_type == WEBKIT_SOUP_CACHE_SHARED) {
+ s_maxage = g_hash_table_lookup (hash, "s-maxage");
+ if (s_maxage) {
+ freshness_lifetime = g_ascii_strtoll (s_maxage, NULL, 10);
+ if (freshness_lifetime) {
+ /* Implies proxy-revalidate. TODO: is it true? */
+ entry->must_revalidate = TRUE;
+ soup_header_free_param_list (hash);
+ return;
+ }
+ }
+ }
+
+ /* If 'max-age' cache directive is present, use that */
+ max_age = g_hash_table_lookup (hash, "max-age");
+ if (max_age)
+ freshness_lifetime = g_ascii_strtoll (max_age, NULL, 10);
+
+ if (freshness_lifetime) {
+ entry->freshness_lifetime = (guint)MIN (freshness_lifetime, G_MAXUINT32);
+ soup_header_free_param_list (hash);
+ return;
+ }
+ }
+
+ if (hash != NULL)
+ soup_header_free_param_list (hash);
+
+ /* If the 'Expires' response header is present, use its value
+ * minus the value of the 'Date' response header
+ */
+ expires = soup_message_headers_get (entry->headers, "Expires");
+ date = soup_message_headers_get (entry->headers, "Date");
+ if (expires && date) {
+ SoupDate *expires_d, *date_d;
+ time_t expires_t, date_t;
+
+ expires_d = soup_date_new_from_string (expires);
+ if (expires_d) {
+ date_d = soup_date_new_from_string (date);
+
+ expires_t = soup_date_to_time_t (expires_d);
+ date_t = soup_date_to_time_t (date_d);
+
+ soup_date_free (expires_d);
+ soup_date_free (date_d);
+
+ if (expires_t && date_t) {
+ entry->freshness_lifetime = (guint)MAX (expires_t - date_t, 0);
+ return;
+ }
+ } else {
+ /* If Expires is not a valid date we should
+ treat it as already expired, see section
+ 3.3 */
+ entry->freshness_lifetime = 0;
+ return;
+ }
+ }
+
+ /* Otherwise an heuristic may be used */
+
+ /* Heuristics MUST NOT be used with these status codes
+ (section 2.3.1.1) */
+ if (msg->status_code != SOUP_STATUS_OK &&
+ msg->status_code != SOUP_STATUS_NON_AUTHORITATIVE &&
+ msg->status_code != SOUP_STATUS_PARTIAL_CONTENT &&
+ msg->status_code != SOUP_STATUS_MULTIPLE_CHOICES &&
+ msg->status_code != SOUP_STATUS_MOVED_PERMANENTLY &&
+ msg->status_code != SOUP_STATUS_GONE)
+ goto expire;
+
+ /* TODO: attach warning 113 if response's current_age is more
+ than 24h (section 2.3.1.1) when using heuristics */
+
+ /* Last-Modified based heuristic */
+ last_modified = soup_message_headers_get (entry->headers, "Last-Modified");
+ if (last_modified) {
+ SoupDate *soup_date;
+ time_t now, last_modified_t;
+
+ soup_date = soup_date_new_from_string (last_modified);
+ last_modified_t = soup_date_to_time_t (soup_date);
+ now = time (NULL);
+
+#define HEURISTIC_FACTOR 0.1 /* From Section 2.3.1.1 */
+
+ entry->freshness_lifetime = MAX (0, (now - last_modified_t) * HEURISTIC_FACTOR);
+ soup_date_free (soup_date);
+ }
+
+ return;
+
+ expire:
+ /* If all else fails, make the entry expire immediately */
+ entry->freshness_lifetime = 0;
+}
+
+static WebKitSoupCacheEntry *
+webkit_soup_cache_entry_new (WebKitSoupCache *cache, SoupMessage *msg, time_t request_time, time_t response_time)
+{
+ WebKitSoupCacheEntry *entry;
+ SoupMessageHeaders *headers;
+ const char *date;
+ char *md5;
+
+ entry = g_slice_new0 (WebKitSoupCacheEntry);
+ entry->dirty = FALSE;
+ entry->writing = FALSE;
+ entry->got_body = FALSE;
+ entry->being_validated = FALSE;
+ entry->data = g_string_new (NULL);
+ entry->pos = 0;
+ entry->error = NULL;
+
+ /* key & filename */
+ entry->key = soup_message_get_cache_key (msg);
+ md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, entry->key, -1);
+ entry->filename = g_build_filename (cache->priv->cache_dir, md5, NULL);
+ g_free (md5);
+
+ /* Headers */
+ headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
+ soup_message_headers_foreach (msg->response_headers,
+ (SoupMessageHeadersForeachFunc)copy_headers,
+ headers);
+ entry->headers = headers;
+
+ /* LRU list */
+ entry->hits = 0;
+
+ /* Section 2.3.1, Freshness Lifetime */
+ webkit_soup_cache_entry_set_freshness (entry, msg, cache);
+
+ /* Section 2.3.2, Calculating Age */
+ date = soup_message_headers_get (entry->headers, "Date");
+
+ if (date) {
+ SoupDate *soup_date;
+ const char *age;
+ time_t date_value, apparent_age, corrected_received_age, response_delay, age_value = 0;
+
+ soup_date = soup_date_new_from_string (date);
+ date_value = soup_date_to_time_t (soup_date);
+ soup_date_free (soup_date);
+
+ age = soup_message_headers_get (entry->headers, "Age");
+ if (age)
+ age_value = g_ascii_strtoll (age, NULL, 10);
+
+ entry->response_time = response_time;
+ apparent_age = MAX (0, entry->response_time - date_value);
+ corrected_received_age = MAX (apparent_age, age_value);
+ response_delay = entry->response_time - request_time;
+ entry->corrected_initial_age = corrected_received_age + response_delay;
+ } else {
+ /* Is this correct ? */
+ entry->corrected_initial_age = time (NULL);
+ }
+
+ return entry;
+}
+
+static void
+webkit_soup_cache_writing_fixture_free (WebKitSoupCacheWritingFixture *fixture)
+{
+ /* Free fixture. And disconnect signals, we don't want to
+ listen to more SoupMessage events as we're finished with
+ this resource */
+ if (g_signal_handler_is_connected (fixture->msg, fixture->got_chunk_handler))
+ g_signal_handler_disconnect (fixture->msg, fixture->got_chunk_handler);
+ if (g_signal_handler_is_connected (fixture->msg, fixture->got_body_handler))
+ g_signal_handler_disconnect (fixture->msg, fixture->got_body_handler);
+ if (g_signal_handler_is_connected (fixture->msg, fixture->restarted_handler))
+ g_signal_handler_disconnect (fixture->msg, fixture->restarted_handler);
+ g_object_unref (fixture->msg);
+ g_object_unref (fixture->cache);
+ g_slice_free (WebKitSoupCacheWritingFixture, fixture);
+}
+
+static void
+close_ready_cb (GObject *source, GAsyncResult *result, WebKitSoupCacheWritingFixture *fixture)
+{
+ WebKitSoupCacheEntry *entry = fixture->entry;
+ WebKitSoupCache *cache = fixture->cache;
+ GOutputStream *stream = G_OUTPUT_STREAM (source);
+ goffset content_length;
+
+ g_warn_if_fail (entry->error == NULL);
+
+ /* FIXME: what do we do on error ? */
+
+ if (stream) {
+ g_output_stream_close_finish (stream, result, NULL);
+ g_object_unref (stream);
+ }
+ entry->stream = NULL;
+
+ content_length = soup_message_headers_get_content_length (entry->headers);
+
+ /* If the process was cancelled, then delete the entry from
+ the cache. Do it also if the size of a chunked resource is
+ too much for the cache */
+ if (g_cancellable_is_cancelled (entry->cancellable)) {
+ entry->dirty = FALSE;
+ webkit_soup_cache_entry_remove (cache, entry);
+ webkit_soup_cache_entry_free (entry, TRUE);
+ entry = NULL;
+ } else if ((soup_message_headers_get_encoding (entry->headers) == SOUP_ENCODING_CHUNKED) ||
+ entry->length != (gsize) content_length) {
+ /** Two options here:
+ *
+ * 1. "chunked" data, entry was temporarily added to
+ * cache (as content-length is 0) and now that we have
+ * the actual size we have to evaluate if we want it
+ * in the cache or not
+ *
+ * 2. Content-Length has a different value than actual
+ * length, means that the content was encoded for
+ * transmission (typically compressed) and thus we
+ * have to substract the content-length value that was
+ * added to the cache and add the unencoded length
+ **/
+ gint length_to_add = entry->length - content_length;
+
+ /* Make room in cache if needed */
+ if (cache_accepts_entries_of_size (cache, length_to_add)) {
+ make_room_for_new_entry (cache, length_to_add);
+
+ cache->priv->size += length_to_add;
+ } else {
+ entry->dirty = FALSE;
+ webkit_soup_cache_entry_remove (cache, entry);
+ webkit_soup_cache_entry_free (entry, TRUE);
+ entry = NULL;
+ }
+ }
+
+ if (entry) {
+ /* Get rid of the GString in memory for the resource now */
+ if (entry->data) {
+ g_string_free (entry->data, TRUE);
+ entry->data = NULL;
+ }
+
+ entry->dirty = FALSE;
+ entry->writing = FALSE;
+ entry->got_body = FALSE;
+ entry->pos = 0;
+
+ g_object_unref (entry->cancellable);
+ entry->cancellable = NULL;
+ }
+
+ cache->priv->n_pending--;
+
+ /* Frees */
+ webkit_soup_cache_writing_fixture_free (fixture);
+}
+
+static void
+write_ready_cb (GObject *source, GAsyncResult *result, WebKitSoupCacheWritingFixture *fixture)
+{
+ GOutputStream *stream = G_OUTPUT_STREAM (source);
+ GError *error = NULL;
+ gssize write_size;
+ WebKitSoupCacheEntry *entry = fixture->entry;
+
+ if (g_cancellable_is_cancelled (entry->cancellable)) {
+ g_output_stream_close_async (stream,
+ G_PRIORITY_LOW,
+ entry->cancellable,
+ (GAsyncReadyCallback)close_ready_cb,
+ fixture);
+ return;
+ }
+
+ write_size = g_output_stream_write_finish (stream, result, &error);
+ if (write_size <= 0 || error) {
+ if (error)
+ entry->error = error;
+ g_output_stream_close_async (stream,
+ G_PRIORITY_LOW,
+ entry->cancellable,
+ (GAsyncReadyCallback)close_ready_cb,
+ fixture);
+ /* FIXME: We should completely stop caching the
+ resource at this point */
+ } else {
+ entry->pos += write_size;
+
+ /* Are we still writing and is there new data to write
+ already ? */
+ if (entry->data && entry->pos < entry->data->len) {
+ g_output_stream_write_async (entry->stream,
+ entry->data->str + entry->pos,
+ entry->data->len - entry->pos,
+ G_PRIORITY_LOW,
+ entry->cancellable,
+ (GAsyncReadyCallback)write_ready_cb,
+ fixture);
+ } else {
+ entry->writing = FALSE;
+
+ if (entry->got_body) {
+ /* If we already received 'got-body'
+ and we have written all the data,
+ we can close the stream */
+ g_output_stream_close_async (entry->stream,
+ G_PRIORITY_LOW,
+ entry->cancellable,
+ (GAsyncReadyCallback)close_ready_cb,
+ fixture);
+ }
+ }
+ }
+}
+
+static void
+msg_got_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, WebKitSoupCacheWritingFixture *fixture)
+{
+ WebKitSoupCacheEntry *entry = fixture->entry;
+
+ g_return_if_fail (chunk->data && chunk->length);
+ g_return_if_fail (entry);
+
+ /* Ignore this if the writing or appending was cancelled */
+ if (!g_cancellable_is_cancelled (entry->cancellable)) {
+ g_string_append_len (entry->data, chunk->data, chunk->length);
+ entry->length = entry->data->len;
+
+ if (!cache_accepts_entries_of_size (fixture->cache, entry->length)) {
+ /* Quickly cancel the caching of the resource */
+ g_cancellable_cancel (entry->cancellable);
+ }
+ }
+
+ /* FIXME: remove the error check when we cancel the caching at
+ the first write error */
+ /* Only write if the entry stream is ready */
+ if (entry->writing == FALSE && entry->error == NULL && entry->stream) {
+ GString *data = entry->data;
+ entry->writing = TRUE;
+ g_output_stream_write_async (entry->stream,
+ data->str + entry->pos,
+ data->len - entry->pos,
+ G_PRIORITY_LOW,
+ entry->cancellable,
+ (GAsyncReadyCallback)write_ready_cb,
+ fixture);
+ }
+}
+
+static void
+msg_got_body_cb (SoupMessage *msg, WebKitSoupCacheWritingFixture *fixture)
+{
+ WebKitSoupCacheEntry *entry = fixture->entry;
+ g_return_if_fail (entry);
+
+ entry->got_body = TRUE;
+
+ if (!entry->stream && entry->pos != entry->length)
+ /* The stream is not ready to be written but we still
+ have data to write, we'll write it when the stream
+ is opened for writing */
+ return;
+
+
+ if (entry->pos != entry->length) {
+ /* If we still have data to write, write it,
+ write_ready_cb will close the stream */
+ if (entry->writing == FALSE && entry->error == NULL && entry->stream) {
+ g_output_stream_write_async (entry->stream,
+ entry->data->str + entry->pos,
+ entry->data->len - entry->pos,
+ G_PRIORITY_LOW,
+ entry->cancellable,
+ (GAsyncReadyCallback)write_ready_cb,
+ fixture);
+ }
+ return;
+ }
+
+ if (entry->stream && !entry->writing)
+ g_output_stream_close_async (entry->stream,
+ G_PRIORITY_LOW,
+ entry->cancellable,
+ (GAsyncReadyCallback)close_ready_cb,
+ fixture);
+}
+
+static gboolean
+webkit_soup_cache_entry_remove (WebKitSoupCache *cache, WebKitSoupCacheEntry *entry)
+{
+ GList *lru_item;
+
+ /* if (entry->dirty && !g_cancellable_is_cancelled (entry->cancellable)) { */
+ if (entry->dirty) {
+ g_cancellable_cancel (entry->cancellable);
+ return FALSE;
+ }
+
+ g_assert (g_list_length (cache->priv->lru_start) == g_hash_table_size (cache->priv->cache));
+
+ /* Remove from cache */
+ if (!g_hash_table_remove (cache->priv->cache, entry->key))
+ return FALSE;
+
+ /* Remove from LRU */
+ lru_item = g_list_find (cache->priv->lru_start, entry);
+ cache->priv->lru_start = g_list_delete_link (cache->priv->lru_start, lru_item);
+
+ /* Adjust cache size */
+ cache->priv->size -= entry->length;
+
+ g_assert (g_list_length (cache->priv->lru_start) == g_hash_table_size (cache->priv->cache));
+
+ return TRUE;
+}
+
+static gint
+lru_compare_func (gconstpointer a, gconstpointer b)
+{
+ WebKitSoupCacheEntry *entry_a = (WebKitSoupCacheEntry *)a;
+ WebKitSoupCacheEntry *entry_b = (WebKitSoupCacheEntry *)b;
+
+ /** The rationale of this sorting func is
+ *
+ * 1. sort by hits -> LRU algorithm, then
+ *
+ * 2. sort by freshness lifetime, we better discard first
+ * entries that are close to expire
+ *
+ * 3. sort by size, replace first small size resources as they
+ * are cheaper to download
+ **/
+
+ /* Sort by hits */
+ if (entry_a->hits != entry_b->hits)
+ return entry_a->hits - entry_b->hits;
+
+ /* Sort by freshness_lifetime */
+ if (entry_a->freshness_lifetime != entry_b->freshness_lifetime)
+ return entry_a->freshness_lifetime - entry_b->freshness_lifetime;
+
+ /* Sort by size */
+ return entry_a->length - entry_b->length;
+}
+
+static gboolean
+cache_accepts_entries_of_size (WebKitSoupCache *cache, guint length_to_add)
+{
+ /* We could add here some more heuristics. TODO: review how
+ this is done by other HTTP caches */
+
+ return length_to_add <= cache->priv->max_entry_data_size;
+}
+
+static void
+make_room_for_new_entry (WebKitSoupCache *cache, guint length_to_add)
+{
+ GList *lru_entry = cache->priv->lru_start;
+
+ /* Check that there is enough room for the new entry. This is
+ an approximation as we're not working out the size of the
+ cache file or the size of the headers for performance
+ reasons. TODO: check if that would be really that expensive */
+
+ while (lru_entry &&
+ (length_to_add + cache->priv->size > cache->priv->max_size)) {
+ WebKitSoupCacheEntry *old_entry = (WebKitSoupCacheEntry *)lru_entry->data;
+
+ /* Discard entries. Once cancelled resources will be
+ * freed in close_ready_cb
+ */
+ if (webkit_soup_cache_entry_remove (cache, old_entry)) {
+ webkit_soup_cache_entry_free (old_entry, TRUE);
+ lru_entry = cache->priv->lru_start;
+ } else
+ lru_entry = g_list_next (lru_entry);
+ }
+}
+
+static gboolean
+webkit_soup_cache_entry_insert_by_key (WebKitSoupCache *cache,
+ const char *key,
+ WebKitSoupCacheEntry *entry,
+ gboolean sort)
+{
+ guint length_to_add = 0;
+
+ if (soup_message_headers_get_encoding (entry->headers) != SOUP_ENCODING_CHUNKED)
+ length_to_add = soup_message_headers_get_content_length (entry->headers);
+
+ /* Check if we are going to store the resource depending on its size */
+ if (length_to_add) {
+ if (!cache_accepts_entries_of_size (cache, length_to_add))
+ return FALSE;
+
+ /* Make room for new entry if needed */
+ make_room_for_new_entry (cache, length_to_add);
+ }
+
+ g_hash_table_insert (cache->priv->cache, g_strdup (key), entry);
+
+ /* Compute new cache size */
+ cache->priv->size += length_to_add;
+
+ /* Update LRU */
+ if (sort)
+ cache->priv->lru_start = g_list_insert_sorted (cache->priv->lru_start, entry, lru_compare_func);
+ else
+ cache->priv->lru_start = g_list_prepend (cache->priv->lru_start, entry);
+
+ g_assert (g_list_length (cache->priv->lru_start) == g_hash_table_size (cache->priv->cache));
+
+ return TRUE;
+}
+
+static void
+msg_restarted_cb (SoupMessage *msg, WebKitSoupCacheEntry *entry)
+{
+ /* FIXME: What should we do here exactly? */
+}
+
+static void
+append_to_ready_cb (GObject *source, GAsyncResult *result, WebKitSoupCacheWritingFixture *fixture)
+{
+ GFile *file = (GFile *)source;
+ GOutputStream *stream;
+ WebKitSoupCacheEntry *entry = fixture->entry;
+
+ stream = (GOutputStream *)g_file_append_to_finish (file, result, &entry->error);
+
+ if (g_cancellable_is_cancelled (entry->cancellable) || entry->error) {
+ fixture->cache->priv->n_pending--;
+ entry->dirty = FALSE;
+ webkit_soup_cache_entry_remove (fixture->cache, entry);
+ webkit_soup_cache_entry_free (entry, TRUE);
+ webkit_soup_cache_writing_fixture_free (fixture);
+ return;
+ }
+
+ entry->stream = g_object_ref (stream);
+ g_object_unref (file);
+
+ /* If we already got all the data we have to initiate the
+ writing here, since we won't get more 'got-chunk'
+ signals */
+ if (entry->got_body) {
+ GString *data = entry->data;
+
+ /* It could happen that reading the data from server
+ was completed before this happens. In that case
+ there is no data */
+ if (data) {
+ entry->writing = TRUE;
+ g_output_stream_write_async (entry->stream,
+ data->str + entry->pos,
+ data->len - entry->pos,
+ G_PRIORITY_LOW,
+ entry->cancellable,
+ (GAsyncReadyCallback)write_ready_cb,
+ fixture);
+ }
+ }
+}
+
+typedef struct {
+ time_t request_time;
+ SoupSessionFeature *feature;
+ gulong got_headers_handler;
+} RequestHelper;
+
+static void
+msg_got_headers_cb (SoupMessage *msg, gpointer user_data)
+{
+ WebKitSoupCache *cache;
+ WebKitSoupCacheability cacheable;
+ RequestHelper *helper;
+ time_t request_time, response_time;
+
+ response_time = time (NULL);
+
+ helper = (RequestHelper *)user_data;
+ cache = WEBKIT_SOUP_CACHE (helper->feature);
+ request_time = helper->request_time;
+ g_signal_handlers_disconnect_by_func (msg, msg_got_headers_cb, user_data);
+ g_slice_free (RequestHelper, helper);
+
+ cacheable = webkit_soup_cache_get_cacheability (cache, msg);
+
+ if (cacheable & WEBKIT_SOUP_CACHE_CACHEABLE) {
+ WebKitSoupCacheEntry *entry;
+ char *key;
+ GFile *file;
+ WebKitSoupCacheWritingFixture *fixture;
+
+ /* Check if we are already caching this resource */
+ key = soup_message_get_cache_key (msg);
+ entry = g_hash_table_lookup (cache->priv->cache, key);
+ g_free (key);
+
+ if (entry && entry->dirty)
+ return;
+
+ /* Create a new entry, deleting any old one if present */
+ if (entry) {
+ webkit_soup_cache_entry_remove (cache, entry);
+ webkit_soup_cache_entry_free (entry, TRUE);
+ }
+
+ entry = webkit_soup_cache_entry_new (cache, msg, request_time, response_time);
+ entry->hits = 1;
+
+ /* Do not continue if it can not be stored */
+ if (!webkit_soup_cache_entry_insert_by_key (cache, (const gchar *)entry->key, entry, TRUE)) {
+ webkit_soup_cache_entry_free (entry, TRUE);
+ return;
+ }
+
+ fixture = g_slice_new0 (WebKitSoupCacheWritingFixture);
+ fixture->cache = g_object_ref (cache);
+ fixture->entry = entry;
+ fixture->msg = g_object_ref (msg);
+
+ /* We connect now to these signals and buffer the data
+ if it comes before the file is ready for writing */
+ fixture->got_chunk_handler =
+ g_signal_connect (msg, "got-chunk", G_CALLBACK (msg_got_chunk_cb), fixture);
+ fixture->got_body_handler =
+ g_signal_connect (msg, "got-body", G_CALLBACK (msg_got_body_cb), fixture);
+ fixture->restarted_handler =
+ g_signal_connect (msg, "restarted", G_CALLBACK (msg_restarted_cb), entry);
+
+ /* Prepare entry */
+ file = g_file_new_for_path (entry->filename);
+ cache->priv->n_pending++;
+
+ entry->dirty = TRUE;
+ entry->cancellable = g_cancellable_new ();
+ g_file_append_to_async (file, 0,
+ G_PRIORITY_LOW, entry->cancellable,
+ (GAsyncReadyCallback)append_to_ready_cb,
+ fixture);
+ } else if (cacheable & WEBKIT_SOUP_CACHE_INVALIDATES) {
+ char *key;
+ WebKitSoupCacheEntry *entry;
+
+ key = soup_message_get_cache_key (msg);
+ entry = g_hash_table_lookup (cache->priv->cache, key);
+ g_free (key);
+
+ if (entry) {
+ if (webkit_soup_cache_entry_remove (cache, entry))
+ webkit_soup_cache_entry_free (entry, TRUE);
+ }
+ } else if (cacheable & WEBKIT_SOUP_CACHE_VALIDATES) {
+ char *key;
+ WebKitSoupCacheEntry *entry;
+
+ key = soup_message_get_cache_key (msg);
+ entry = g_hash_table_lookup (cache->priv->cache, key);
+ g_free (key);
+
+ g_return_if_fail (entry);
+
+ entry->being_validated = FALSE;
+
+ /* We update the headers of the existing cache item,
+ plus its age */
+ soup_message_headers_foreach (msg->response_headers,
+ (SoupMessageHeadersForeachFunc)update_headers,
+ entry->headers);
+ webkit_soup_cache_entry_set_freshness (entry, msg, cache);
+ }
+}
+
+GInputStream *
+webkit_soup_cache_send_response (WebKitSoupCache *cache, SoupMessage *msg)
+{
+ char *key;
+ WebKitSoupCacheEntry *entry;
+ char *current_age;
+ GInputStream *stream = NULL;
+ GFile *file;
+
+ g_return_val_if_fail (WEBKIT_IS_SOUP_CACHE (cache), NULL);
+ g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
+
+ key = soup_message_get_cache_key (msg);
+ entry = g_hash_table_lookup (cache->priv->cache, key);
+ g_return_val_if_fail (entry, NULL);
+
+ /* If we are told to send a response from cache any validation
+ in course is over by now */
+ entry->being_validated = FALSE;
+
+ /* Headers */
+ soup_message_headers_foreach (entry->headers,
+ (SoupMessageHeadersForeachFunc)update_headers,
+ msg->response_headers);
+
+ /* Add 'Age' header with the current age */
+ current_age = g_strdup_printf ("%d", webkit_soup_cache_entry_get_current_age (entry));
+ soup_message_headers_replace (msg->response_headers,
+ "Age",
+ current_age);
+ g_free (current_age);
+
+ /* TODO: the original idea was to save reads, but current code
+ assumes that a stream is always returned. Need to reach
+ some agreement here. Also we have to handle the situation
+ were the file was no longer there (for example files
+ removed without notifying the cache */
+ file = g_file_new_for_path (entry->filename);
+ stream = (GInputStream *)g_file_read (file, NULL, NULL);
+
+ return stream;
+}
+
+static void
+request_started (SoupSessionFeature *feature, SoupSession *session,
+ SoupMessage *msg, SoupSocket *socket)
+{
+ RequestHelper *helper = g_slice_new0 (RequestHelper);
+ helper->request_time = time (NULL);
+ helper->feature = feature;
+ helper->got_headers_handler = g_signal_connect (msg, "got-headers",
+ G_CALLBACK (msg_got_headers_cb),
+ helper);
+}
+
+static void
+attach (SoupSessionFeature *feature, SoupSession *session)
+{
+ WebKitSoupCache *cache = WEBKIT_SOUP_CACHE (feature);
+ cache->priv->session = session;
+
+ webkit_soup_cache_default_feature_interface->attach (feature, session);
+}
+
+static void
+webkit_soup_cache_session_feature_init (SoupSessionFeatureInterface *feature_interface,
+ gpointer interface_data)
+{
+ webkit_soup_cache_default_feature_interface =
+ g_type_default_interface_peek (SOUP_TYPE_SESSION_FEATURE);
+
+ feature_interface->attach = attach;
+ feature_interface->request_started = request_started;
+}
+
+static void
+webkit_soup_cache_init (WebKitSoupCache *cache)
+{
+ WebKitSoupCachePrivate *priv;
+
+ priv = cache->priv = WEBKIT_SOUP_CACHE_GET_PRIVATE (cache);
+
+ priv->cache = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ NULL);
+
+ /* LRU */
+ priv->lru_start = NULL;
+
+ /* */
+ priv->n_pending = 0;
+
+ /* Cache size */
+ priv->max_size = DEFAULT_MAX_SIZE;
+ priv->max_entry_data_size = priv->max_size / MAX_ENTRY_DATA_PERCENTAGE;
+ priv->size = 0;
+}
+
+static void
+remove_cache_item (gpointer key,
+ gpointer value,
+ WebKitSoupCache *cache)
+{
+ WebKitSoupCacheEntry *entry = g_hash_table_lookup (cache->priv->cache, (const gchar *)key);
+ if (webkit_soup_cache_entry_remove (cache, entry))
+ webkit_soup_cache_entry_free (entry, FALSE);
+}
+
+static void
+webkit_soup_cache_finalize (GObject *object)
+{
+ WebKitSoupCachePrivate *priv;
+
+ priv = WEBKIT_SOUP_CACHE (object)->priv;
+
+ g_hash_table_foreach (priv->cache, (GHFunc)remove_cache_item, object);
+ g_hash_table_destroy (priv->cache);
+ g_free (priv->cache_dir);
+
+ g_list_free (priv->lru_start);
+ priv->lru_start = NULL;
+
+ G_OBJECT_CLASS (webkit_soup_cache_parent_class)->finalize (object);
+}
+
+static void
+webkit_soup_cache_set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ WebKitSoupCachePrivate *priv = WEBKIT_SOUP_CACHE (object)->priv;
+
+ switch (prop_id) {
+ case PROP_CACHE_DIR:
+ priv->cache_dir = g_value_dup_string (value);
+ /* Create directory if it does not exist (FIXME: should we?) */
+ if (!g_file_test (priv->cache_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
+ g_mkdir_with_parents (priv->cache_dir, 0700);
+ break;
+ case PROP_CACHE_TYPE:
+ priv->cache_type = g_value_get_enum (value);
+ /* TODO: clear private entries and issue a warning if moving to shared? */
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+webkit_soup_cache_get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ WebKitSoupCachePrivate *priv = WEBKIT_SOUP_CACHE (object)->priv;
+
+ switch (prop_id) {
+ case PROP_CACHE_DIR:
+ g_value_set_string (value, priv->cache_dir);
+ break;
+ case PROP_CACHE_TYPE:
+ g_value_set_enum (value, priv->cache_type);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+webkit_soup_cache_constructed (GObject *object)
+{
+ WebKitSoupCachePrivate *priv;
+
+ priv = WEBKIT_SOUP_CACHE (object)->priv;
+
+ if (!priv->cache_dir) {
+ /* Set a default cache dir, different for each user */
+ priv->cache_dir = g_build_filename (g_get_user_cache_dir (),
+ "httpcache",
+ NULL);
+ if (!g_file_test (priv->cache_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
+ g_mkdir_with_parents (priv->cache_dir, 0700);
+ }
+
+ if (G_OBJECT_CLASS (webkit_soup_cache_parent_class)->constructed)
+ G_OBJECT_CLASS (webkit_soup_cache_parent_class)->constructed (object);
+}
+
+#define WEBKIT_SOUP_CACHE_TYPE_TYPE (webkit_soup_cache_type_get_type ())
+static GType
+webkit_soup_cache_type_get_type (void)
+{
+ static GType cache_type = 0;
+
+ static const GEnumValue cache_types[] = {
+ { WEBKIT_SOUP_CACHE_SINGLE_USER, "Single user cache", "user" },
+ { WEBKIT_SOUP_CACHE_SHARED, "Shared cache", "shared" },
+ { 0, NULL, NULL }
+ };
+
+ if (!cache_type) {
+ cache_type = g_enum_register_static ("WebKitSoupCacheTypeType", cache_types);
+ }
+ return cache_type;
+}
+
+static void
+webkit_soup_cache_class_init (WebKitSoupCacheClass *cache_class)
+{
+ GObjectClass *gobject_class = (GObjectClass *)cache_class;
+
+ gobject_class->finalize = webkit_soup_cache_finalize;
+ gobject_class->constructed = webkit_soup_cache_constructed;
+ gobject_class->set_property = webkit_soup_cache_set_property;
+ gobject_class->get_property = webkit_soup_cache_get_property;
+
+ cache_class->get_cacheability = get_cacheability;
+
+ g_object_class_install_property (gobject_class, PROP_CACHE_DIR,
+ g_param_spec_string ("cache-dir",
+ "Cache directory",
+ "The directory to store the cache files",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (gobject_class, PROP_CACHE_TYPE,
+ g_param_spec_enum ("cache-type",
+ "Cache type",
+ "Whether the cache is private or shared",
+ WEBKIT_SOUP_CACHE_TYPE_TYPE,
+ WEBKIT_SOUP_CACHE_SINGLE_USER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_type_class_add_private (cache_class, sizeof (WebKitSoupCachePrivate));
+}
+
+/**
+ * webkit_soup_cache_new:
+ * @cache_dir: the directory to store the cached data, or %NULL to use the default one
+ * @cache_type: the #WebKitSoupCacheType of the cache
+ *
+ * Creates a new #WebKitSoupCache.
+ *
+ * Returns: a new #WebKitSoupCache
+ *
+ * Since: 2.28
+ **/
+WebKitSoupCache *
+webkit_soup_cache_new (const char *cache_dir, WebKitSoupCacheType cache_type)
+{
+ return g_object_new (WEBKIT_TYPE_SOUP_CACHE,
+ "cache-dir", cache_dir,
+ "cache-type", cache_type,
+ NULL);
+}
+
+/**
+ * webkit_soup_cache_has_response:
+ * @cache: a #WebKitSoupCache
+ * @msg: a #SoupMessage
+ *
+ * This function calculates whether the @cache object has a proper
+ * response for the request @msg given the flags both in the request
+ * and the cached reply and the time ellapsed since it was cached.
+ *
+ * Returns: whether or not the @cache has a valid response for @msg
+ **/
+WebKitSoupCacheResponse
+webkit_soup_cache_has_response (WebKitSoupCache *cache, SoupMessage *msg)
+{
+ char *key;
+ WebKitSoupCacheEntry *entry;
+ const char *cache_control;
+ GHashTable *hash;
+ gpointer value;
+ gboolean must_revalidate;
+ int max_age, max_stale, min_fresh;
+ GList *lru_item, *item;
+
+ key = soup_message_get_cache_key (msg);
+ entry = g_hash_table_lookup (cache->priv->cache, key);
+
+ /* 1. The presented Request-URI and that of stored response
+ * match
+ */
+ if (!entry)
+ return WEBKIT_SOUP_CACHE_RESPONSE_STALE;
+
+ /* Increase hit count. Take sorting into account */
+ entry->hits++;
+ lru_item = g_list_find (cache->priv->lru_start, entry);
+ item = lru_item;
+ while (item->next && lru_compare_func (item->data, item->next->data) > 0)
+ item = g_list_next (item);
+
+ if (item != lru_item) {
+ cache->priv->lru_start = g_list_remove_link (cache->priv->lru_start, lru_item);
+ item = g_list_insert_sorted (item, lru_item->data, lru_compare_func);
+ g_list_free (lru_item);
+ }
+
+ if (entry->dirty || entry->being_validated)
+ return WEBKIT_SOUP_CACHE_RESPONSE_STALE;
+
+ /* 2. The request method associated with the stored response
+ * allows it to be used for the presented request
+ */
+
+ /* In practice this means we only return our resource for GET,
+ * cacheability for other methods is a TODO in the RFC
+ * (TODO: although we could return the headers for HEAD
+ * probably).
+ */
+ if (msg->method != SOUP_METHOD_GET)
+ return WEBKIT_SOUP_CACHE_RESPONSE_STALE;
+
+ /* 3. Selecting request-headers nominated by the stored
+ * response (if any) match those presented.
+ */
+
+ /* TODO */
+
+ /* 4. The presented request and stored response are free from
+ * directives that would prevent its use.
+ */
+
+ must_revalidate = FALSE;
+ max_age = max_stale = min_fresh = -1;
+
+ cache_control = soup_message_headers_get (msg->request_headers, "Cache-Control");
+ if (cache_control) {
+ hash = soup_header_parse_param_list (cache_control);
+
+ if (g_hash_table_lookup_extended (hash, "no-store", NULL, NULL)) {
+ g_hash_table_destroy (hash);
+ return WEBKIT_SOUP_CACHE_RESPONSE_STALE;
+ }
+
+ if (g_hash_table_lookup_extended (hash, "no-cache", NULL, NULL)) {
+ entry->must_revalidate = TRUE;
+ }
+
+ if (g_hash_table_lookup_extended (hash, "max-age", NULL, &value)) {
+ max_age = (int)MIN (g_ascii_strtoll (value, NULL, 10), G_MAXINT32);
+ }
+
+ /* max-stale can have no value set, we need to use _extended */
+ if (g_hash_table_lookup_extended (hash, "max-stale", NULL, &value)) {
+ if (value)
+ max_stale = (int)MIN (g_ascii_strtoll (value, NULL, 10), G_MAXINT32);
+ else
+ max_stale = G_MAXINT32;
+ }
+
+ value = g_hash_table_lookup (hash, "min-fresh");
+ if (value)
+ min_fresh = (int)MIN (g_ascii_strtoll (value, NULL, 10), G_MAXINT32);
+
+ g_hash_table_destroy (hash);
+
+ if (max_age != -1) {
+ guint current_age = webkit_soup_cache_entry_get_current_age (entry);
+
+ /* If we are over max-age and max-stale is not
+ set, do not use the value from the cache
+ without validation */
+ if ((guint) max_age <= current_age && max_stale == -1)
+ return WEBKIT_SOUP_CACHE_RESPONSE_NEEDS_VALIDATION;
+ }
+ }
+
+ /* 5. The stored response is either: fresh, allowed to be
+ * served stale or succesfully validated
+ */
+ /* TODO consider also proxy-revalidate & s-maxage */
+ if (entry->must_revalidate)
+ return WEBKIT_SOUP_CACHE_RESPONSE_NEEDS_VALIDATION;
+
+ if (!webkit_soup_cache_entry_is_fresh_enough (entry, min_fresh)) {
+ /* Not fresh, can it be served stale? */
+ if (max_stale != -1) {
+ /* G_MAXINT32 means we accept any staleness */
+ if (max_stale == G_MAXINT32)
+ return WEBKIT_SOUP_CACHE_RESPONSE_FRESH;
+
+ if ((webkit_soup_cache_entry_get_current_age (entry) - entry->freshness_lifetime) <= (guint) max_stale)
+ return WEBKIT_SOUP_CACHE_RESPONSE_FRESH;
+ }
+
+ return WEBKIT_SOUP_CACHE_RESPONSE_NEEDS_VALIDATION;
+ }
+
+ return WEBKIT_SOUP_CACHE_RESPONSE_FRESH;
+}
+
+/**
+ * webkit_soup_cache_get_cacheability:
+ * @cache: a #WebKitSoupCache
+ * @msg: a #SoupMessage
+ *
+ * Calculates whether the @msg can be cached or not.
+ *
+ * Returns: a #WebKitSoupCacheability value indicating whether the @msg can be cached or not.
+ **/
+WebKitSoupCacheability
+webkit_soup_cache_get_cacheability (WebKitSoupCache *cache, SoupMessage *msg)
+{
+ g_return_val_if_fail (WEBKIT_IS_SOUP_CACHE (cache), WEBKIT_SOUP_CACHE_UNCACHEABLE);
+ g_return_val_if_fail (SOUP_IS_MESSAGE (msg), WEBKIT_SOUP_CACHE_UNCACHEABLE);
+
+ return WEBKIT_SOUP_CACHE_GET_CLASS (cache)->get_cacheability (cache, msg);
+}
+
+static gboolean
+force_flush_timeout (gpointer data)
+{
+ gboolean *forced = (gboolean *)data;
+ *forced = TRUE;
+
+ return FALSE;
+}
+
+/**
+ * webkit_soup_cache_flush:
+ * @cache: a #WebKitSoupCache
+ * @session: the #SoupSession associated with the @cache
+ *
+ * This function will force all pending writes in the @cache to be
+ * committed to disk. For doing so it will iterate the #GMainContext
+ * associated with the @session (which can be the default one) as long
+ * as needed.
+ **/
+void
+webkit_soup_cache_flush (WebKitSoupCache *cache)
+{
+ GMainContext *async_context;
+ SoupSession *session;
+ guint timeout_id;
+ gboolean forced = FALSE;
+
+ g_return_if_fail (WEBKIT_IS_SOUP_CACHE (cache));
+
+ session = cache->priv->session;
+ g_return_if_fail (SOUP_IS_SESSION (session));
+ async_context = soup_session_get_async_context (session);
+
+ /* We give cache 10 secs to finish */
+ timeout_id = g_timeout_add (10000, force_flush_timeout, &forced);
+
+ while (!forced && cache->priv->n_pending > 0)
+ g_main_context_iteration (async_context, FALSE);
+
+ if (!forced)
+ g_source_remove (timeout_id);
+ else
+ g_warning ("Cache flush finished despite %d pending requests", cache->priv->n_pending);
+}
+
+static void
+clear_cache_item (gpointer key,
+ gpointer value,
+ WebKitSoupCache *cache)
+{
+ WebKitSoupCacheEntry *entry = g_hash_table_lookup (cache->priv->cache, (const gchar *)key);
+ if (webkit_soup_cache_entry_remove (cache, entry))
+ webkit_soup_cache_entry_free (entry, TRUE);
+}
+
+/**
+ * webkit_soup_cache_clear:
+ * @cache: a #WebKitSoupCache
+ *
+ * Will remove all entries in the @cache plus all the cache files
+ * associated with them.
+ **/
+void
+webkit_soup_cache_clear (WebKitSoupCache *cache)
+{
+ GHashTable *hash;
+
+ g_return_if_fail (WEBKIT_IS_SOUP_CACHE (cache));
+
+ hash = cache->priv->cache;
+ g_return_if_fail (hash);
+
+ g_hash_table_foreach (hash, (GHFunc)clear_cache_item, cache);
+}
+
+SoupMessage *
+webkit_soup_cache_generate_conditional_request (WebKitSoupCache *cache, SoupMessage *original)
+{
+ SoupMessage *msg;
+ SoupURI *uri;
+ WebKitSoupCacheEntry *entry;
+ char *key;
+ const char *value;
+
+ g_return_val_if_fail (WEBKIT_IS_SOUP_CACHE (cache), NULL);
+ g_return_val_if_fail (SOUP_IS_MESSAGE (original), NULL);
+
+ /* First copy the data we need from the original message */
+ uri = soup_message_get_uri (original);
+ msg = soup_message_new_from_uri (original->method, uri);
+
+ soup_message_headers_foreach (original->request_headers,
+ (SoupMessageHeadersForeachFunc)copy_headers,
+ msg->request_headers);
+
+ /* Now add the validator entries in the header from the cached
+ data */
+ key = soup_message_get_cache_key (original);
+ entry = g_hash_table_lookup (cache->priv->cache, key);
+ g_free (key);
+
+ g_return_val_if_fail (entry, NULL);
+
+ entry->being_validated = TRUE;
+
+ value = soup_message_headers_get (entry->headers, "Last-Modified");
+ if (value)
+ soup_message_headers_append (msg->request_headers,
+ "If-Modified-Since",
+ value);
+ value = soup_message_headers_get (entry->headers, "ETag");
+ if (value)
+ soup_message_headers_append (msg->request_headers,
+ "If-None-Match",
+ value);
+ return msg;
+}
+
+#define WEBKIT_SOUP_CACHE_FILE "soup.cache"
+
+#define WEBKIT_SOUP_CACHE_HEADERS_FORMAT "{ss}"
+#define WEBKIT_SOUP_CACHE_PHEADERS_FORMAT "(ssbuuuuua" WEBKIT_SOUP_CACHE_HEADERS_FORMAT ")"
+#define WEBKIT_SOUP_CACHE_ENTRIES_FORMAT "a" WEBKIT_SOUP_CACHE_PHEADERS_FORMAT
+
+/* Basically the same format than above except that some strings are
+ prepended with &. This way the GVariant returns a pointer to the
+ data instead of duplicating the string */
+#define WEBKIT_SOUP_CACHE_DECODE_HEADERS_FORMAT "{&s&s}"
+
+static void
+pack_entry (gpointer data,
+ gpointer user_data)
+{
+ WebKitSoupCacheEntry *entry = (WebKitSoupCacheEntry *) data;
+ SoupMessageHeadersIter iter;
+ const gchar *header_key, *header_value;
+ GVariantBuilder *headers_builder;
+ GVariantBuilder *entries_builder = (GVariantBuilder *)user_data;
+
+ /* Do not store non-consolidated entries */
+ if (entry->dirty || entry->writing || !entry->key)
+ return;
+
+ /* Pack headers */
+ headers_builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ soup_message_headers_iter_init (&iter, entry->headers);
+ while (soup_message_headers_iter_next (&iter, &header_key, &header_value)) {
+ if (g_utf8_validate (header_value, -1, NULL))
+ g_variant_builder_add (headers_builder, WEBKIT_SOUP_CACHE_HEADERS_FORMAT,
+ header_key, header_value);
+ }
+
+ /* Entry data */
+ g_variant_builder_add (entries_builder, WEBKIT_SOUP_CACHE_PHEADERS_FORMAT,
+ entry->key, entry->filename, entry->must_revalidate,
+ entry->freshness_lifetime, entry->corrected_initial_age,
+ entry->response_time, entry->hits, entry->length, headers_builder);
+
+ g_variant_builder_unref (headers_builder);
+}
+
+void
+webkit_soup_cache_dump (WebKitSoupCache *cache)
+{
+ WebKitSoupCachePrivate *priv = WEBKIT_SOUP_CACHE_GET_PRIVATE (cache);
+ gchar *filename;
+ GVariantBuilder *entries_builder;
+ GVariant *cache_variant;
+
+ if (!g_list_length (cache->priv->lru_start))
+ return;
+
+ /* Create the builder and iterate over all entries */
+ entries_builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ g_list_foreach (cache->priv->lru_start, pack_entry, entries_builder);
+
+ /* Serialize and dump */
+ cache_variant = g_variant_new (WEBKIT_SOUP_CACHE_ENTRIES_FORMAT, entries_builder);
+ g_variant_builder_unref (entries_builder);
+
+ filename = g_build_filename (priv->cache_dir, WEBKIT_SOUP_CACHE_FILE, NULL);
+ g_file_set_contents (filename, (const gchar *)g_variant_get_data (cache_variant),
+ g_variant_get_size (cache_variant), NULL);
+ g_free (filename);
+ g_variant_unref (cache_variant);
+}
+
+void
+webkit_soup_cache_load (WebKitSoupCache *cache)
+{
+ gchar *filename = NULL, *contents = NULL;
+ GVariant *cache_variant;
+ GVariantIter *entries_iter, *headers_iter;
+ GVariantType *variant_format;
+ gsize length;
+ WebKitSoupCacheEntry *entry;
+ WebKitSoupCachePrivate *priv = cache->priv;
+
+ filename = g_build_filename (priv->cache_dir, WEBKIT_SOUP_CACHE_FILE, NULL);
+ if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+ g_free (filename);
+ return;
+ }
+ g_free (filename);
+
+ variant_format = g_variant_type_new (WEBKIT_SOUP_CACHE_ENTRIES_FORMAT);
+ cache_variant = g_variant_new_from_data (variant_format, (const gchar *)contents, length, FALSE, NULL, NULL);
+ g_variant_type_free (variant_format);
+
+ g_variant_get (cache_variant, WEBKIT_SOUP_CACHE_ENTRIES_FORMAT, &entries_iter);
+ entry = g_slice_new0 (WebKitSoupCacheEntry);
+
+ while (g_variant_iter_loop (entries_iter, WEBKIT_SOUP_CACHE_PHEADERS_FORMAT,
+ &entry->key, &entry->filename, &entry->must_revalidate,
+ &entry->freshness_lifetime, &entry->corrected_initial_age,
+ &entry->response_time, &entry->hits, &entry->length,
+ &headers_iter)) {
+ const gchar *header_key, *header_value;
+
+ /* SoupMessage Headers */
+ entry->headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
+ while (g_variant_iter_loop (headers_iter, WEBKIT_SOUP_CACHE_DECODE_HEADERS_FORMAT, &header_key, &header_value))
+ soup_message_headers_append (entry->headers, header_key, header_value);
+
+ /* Insert in cache */
+ if (!webkit_soup_cache_entry_insert_by_key (cache, (const gchar *)entry->key, entry, FALSE))
+ webkit_soup_cache_entry_free (entry, TRUE);
+
+ /* New entry for the next iteration. This creates an
+ extra object the last iteration but it's worth it
+ as we save several if's */
+ entry = g_slice_new0 (WebKitSoupCacheEntry);
+ }
+ /* Remove last created entry */
+ g_slice_free (WebKitSoupCacheEntry, entry);
+
+ /* Sort LRU (shouldn't be needed). First reverse as elements
+ * are always prepended when inserting
+ */
+ cache->priv->lru_start = g_list_reverse (cache->priv->lru_start);
+ cache->priv->lru_start = g_list_sort (cache->priv->lru_start, lru_compare_func);
+
+ /* frees */
+ g_variant_iter_free (entries_iter);
+ g_variant_unref (cache_variant);
+}
+
+void
+webkit_soup_cache_set_max_size (WebKitSoupCache *cache,
+ guint max_size)
+{
+ cache->priv->max_size = max_size;
+ cache->priv->max_entry_data_size = cache->priv->max_size / MAX_ENTRY_DATA_PERCENTAGE;
+}
+
+guint
+webkit_soup_cache_get_max_size (WebKitSoupCache *cache)
+{
+ return cache->priv->max_size;
+}
diff --git a/WebCore/platform/network/soup/cache/webkit/soup-cache.h b/WebCore/platform/network/soup/cache/webkit/soup-cache.h
new file mode 100644
index 0000000..e447cfc
--- /dev/null
+++ b/WebCore/platform/network/soup/cache/webkit/soup-cache.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-cache.h:
+ *
+ * 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
+ * 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 WEBKIT_SOUP_CACHE_H
+#define WEBKIT_SOUP_CACHE_H 1
+
+#if BUILDING_GTK__
+#include <webkit/webkitdefines.h>
+#else
+#ifndef WEBKIT_API
+#define WEBKIT_API
+#endif
+#endif
+
+#include <libsoup/soup-types.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_SOUP_CACHE (webkit_soup_cache_get_type ())
+#define WEBKIT_SOUP_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_SOUP_CACHE, WebKitSoupCache))
+#define WEBKIT_SOUP_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_SOUP_CACHE, WebKitSoupCacheClass))
+#define WEBKIT_IS_SOUP_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_SOUP_CACHE))
+#define WEBKIT_IS_SOUP_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), WEBKIT_TYPE_SOUP_CACHE))
+#define WEBKIT_SOUP_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), WEBKIT_TYPE_SOUP_CACHE, WebKitSoupCacheClass))
+
+typedef struct _WebKitSoupCache WebKitSoupCache;
+typedef struct _WebKitSoupCachePrivate WebKitSoupCachePrivate;
+
+typedef enum {
+ WEBKIT_SOUP_CACHE_CACHEABLE = (1 << 0),
+ WEBKIT_SOUP_CACHE_UNCACHEABLE = (1 << 1),
+ WEBKIT_SOUP_CACHE_INVALIDATES = (1 << 2),
+ WEBKIT_SOUP_CACHE_VALIDATES = (1 << 3)
+} WebKitSoupCacheability;
+
+typedef enum {
+ WEBKIT_SOUP_CACHE_RESPONSE_FRESH,
+ WEBKIT_SOUP_CACHE_RESPONSE_NEEDS_VALIDATION,
+ WEBKIT_SOUP_CACHE_RESPONSE_STALE
+} WebKitSoupCacheResponse;
+
+typedef enum {
+ WEBKIT_SOUP_CACHE_SINGLE_USER,
+ WEBKIT_SOUP_CACHE_SHARED
+} WebKitSoupCacheType;
+
+struct _WebKitSoupCache {
+ GObject parent_instance;
+
+ WebKitSoupCachePrivate *priv;
+};
+
+typedef struct {
+ GObjectClass parent_class;
+
+ /* methods */
+ WebKitSoupCacheability (*get_cacheability)(WebKitSoupCache *cache, SoupMessage *msg);
+
+ /* Padding for future expansion */
+ void (*_libsoup_reserved1)(void);
+ void (*_libsoup_reserved2)(void);
+ void (*_libsoup_reserved3)(void);
+} WebKitSoupCacheClass;
+
+WEBKIT_API GType webkit_soup_cache_get_type (void);
+WEBKIT_API WebKitSoupCache *webkit_soup_cache_new (const char *cache_dir,
+ WebKitSoupCacheType cache_type);
+WEBKIT_API void webkit_soup_cache_flush (WebKitSoupCache *cache);
+WEBKIT_API void webkit_soup_cache_clear (WebKitSoupCache *cache);
+
+WEBKIT_API void webkit_soup_cache_dump (WebKitSoupCache *cache);
+WEBKIT_API void webkit_soup_cache_load (WebKitSoupCache *cache);
+
+WEBKIT_API void webkit_soup_cache_set_max_size (WebKitSoupCache *cache,
+ guint max_size);
+WEBKIT_API guint webkit_soup_cache_get_max_size (WebKitSoupCache *cache);
+
+G_END_DECLS
+
+
+#endif /* WEBKIT_SOUP_CACHE_H */
+
diff --git a/WebCore/platform/network/win/CookieJarWin.cpp b/WebCore/platform/network/win/CookieJarWin.cpp
index 2bdd6b3..a2afbc6 100644
--- a/WebCore/platform/network/win/CookieJarWin.cpp
+++ b/WebCore/platform/network/win/CookieJarWin.cpp
@@ -48,13 +48,17 @@ String cookies(const Document* /*document*/, const KURL& url)
{
String str = url.string();
- DWORD count = str.length() + 1;
- InternetGetCookie(str.charactersWithNullTermination(), 0, 0, &count);
+ DWORD count = 0;
+ if (!InternetGetCookie(str.charactersWithNullTermination(), 0, 0, &count))
+ return String();
+
if (count <= 1) // Null terminator counts as 1.
return String();
Vector<UChar> buffer(count);
- InternetGetCookie(str.charactersWithNullTermination(), 0, buffer.data(), &count);
+ if (!InternetGetCookie(str.charactersWithNullTermination(), 0, buffer.data(), &count))
+ return String();
+
buffer.shrink(count - 1); // Ignore the null terminator.
return String::adopt(buffer);
}
diff --git a/WebCore/platform/network/win/ResourceHandleWin.cpp b/WebCore/platform/network/win/ResourceHandleWin.cpp
index 5de2e1b..28035b9 100644
--- a/WebCore/platform/network/win/ResourceHandleWin.cpp
+++ b/WebCore/platform/network/win/ResourceHandleWin.cpp
@@ -27,6 +27,7 @@
#include "config.h"
#include "ResourceHandle.h"
+#include "DataURL.h"
#include "HTTPParsers.h"
#include "MIMETypeRegistry.h"
#include "MainThread.h"
@@ -259,7 +260,7 @@ bool ResourceHandle::onRequestComplete()
bool ResourceHandle::start(NetworkingContext* context)
{
- if (request().url().isLocalFile()) {
+ if (firstRequest().url().isLocalFile() || firstRequest().url().protocolIsData()) {
ref(); // balanced by deref in fileLoadTimer
if (d->m_loadSynchronously)
fileLoadTimer(0);
@@ -349,6 +350,11 @@ void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*)
RefPtr<ResourceHandle> protector(this);
deref(); // balances ref in start
+ if (firstRequest().url().protocolIsData()) {
+ handleDataURL(this);
+ return;
+ }
+
String fileName = firstRequest().url().fileSystemPath();
HANDLE fileHandle = CreateFileW(fileName.charactersWithNullTermination(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
diff --git a/WebCore/platform/qt/ClipboardQt.cpp b/WebCore/platform/qt/ClipboardQt.cpp
index 90e3bfe..20cf62b 100644
--- a/WebCore/platform/qt/ClipboardQt.cpp
+++ b/WebCore/platform/qt/ClipboardQt.cpp
@@ -28,7 +28,6 @@
#include "config.h"
#include "ClipboardQt.h"
-#include "CSSHelper.h"
#include "CachedImage.h"
#include "Document.h"
#include "DragData.h"
@@ -36,6 +35,7 @@
#include "FileList.h"
#include "Frame.h"
#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
#include "Image.h"
#include "IntPoint.h"
#include "KURL.h"
@@ -276,7 +276,7 @@ void ClipboardQt::declareAndWriteDragImage(Element* element, const KURL& url, co
if (imageURL.isEmpty())
return;
- KURL fullURL = frame->document()->completeURL(deprecatedParseURL(imageURL));
+ KURL fullURL = frame->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(imageURL));
if (fullURL.isEmpty())
return;
diff --git a/WebCore/platform/qt/CursorQt.cpp b/WebCore/platform/qt/CursorQt.cpp
index 227b80c..5883600 100644
--- a/WebCore/platform/qt/CursorQt.cpp
+++ b/WebCore/platform/qt/CursorQt.cpp
@@ -72,15 +72,13 @@ Cursor& Cursor::operator=(const Cursor& other)
return *this;
}
+#ifndef QT_NO_CURSOR
static QCursor* createCustomCursor(Image* image, const IntPoint& hotSpot)
{
-#ifndef QT_NO_CURSOR
IntPoint effectiveHotSpot = determineHotSpot(image, hotSpot);
return new QCursor(*(image->nativeImageForCurrentFrame()), effectiveHotSpot.x(), effectiveHotSpot.y());
-#else
- return 0;
-#endif
}
+#endif
void Cursor::ensurePlatformCursor() const
{
diff --git a/WebCore/platform/qt/Language.cpp b/WebCore/platform/qt/LanguageQt.cpp
index 0d2900b..71e554f 100644
--- a/WebCore/platform/qt/Language.cpp
+++ b/WebCore/platform/qt/LanguageQt.cpp
@@ -32,7 +32,7 @@
namespace WebCore {
-String defaultLanguage()
+String platformDefaultLanguage()
{
QLocale locale;
return locale.name().replace("_", "-");
diff --git a/WebCore/platform/qt/PlatformBridge.h b/WebCore/platform/qt/PlatformBridge.h
index 918e139..e478d8f 100644
--- a/WebCore/platform/qt/PlatformBridge.h
+++ b/WebCore/platform/qt/PlatformBridge.h
@@ -27,7 +27,6 @@
#define PlatformBridge_h
#include "KURL.h"
-#include "npapi.h"
#include "PlatformString.h"
#include <wtf/Vector.h>
@@ -77,7 +76,9 @@
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-class NPObject;
+typedef struct NPObject NPObject;
+typedef struct _NPP NPP_t;
+typedef NPP_t* NPP;
namespace WebCore {
diff --git a/WebCore/platform/qt/PlatformKeyboardEventQt.cpp b/WebCore/platform/qt/PlatformKeyboardEventQt.cpp
index 33e9552..498bb88 100644
--- a/WebCore/platform/qt/PlatformKeyboardEventQt.cpp
+++ b/WebCore/platform/qt/PlatformKeyboardEventQt.cpp
@@ -505,6 +505,79 @@ int windowsKeyCodeForKeyEvent(unsigned int keycode, bool isKeypad)
}
}
+static bool isVirtualKeyCodeRepresentingCharacter(int code)
+{
+ switch (code) {
+ case VK_SPACE:
+ case VK_0:
+ case VK_1:
+ case VK_2:
+ case VK_3:
+ case VK_4:
+ case VK_5:
+ case VK_6:
+ case VK_7:
+ case VK_8:
+ case VK_9:
+ case VK_A:
+ case VK_B:
+ case VK_C:
+ case VK_D:
+ case VK_E:
+ case VK_F:
+ case VK_G:
+ case VK_H:
+ case VK_I:
+ case VK_J:
+ case VK_K:
+ case VK_L:
+ case VK_M:
+ case VK_N:
+ case VK_O:
+ case VK_P:
+ case VK_Q:
+ case VK_R:
+ case VK_S:
+ case VK_T:
+ case VK_U:
+ case VK_V:
+ case VK_W:
+ case VK_X:
+ case VK_Y:
+ case VK_Z:
+ case VK_NUMPAD0:
+ case VK_NUMPAD1:
+ case VK_NUMPAD2:
+ case VK_NUMPAD3:
+ case VK_NUMPAD4:
+ case VK_NUMPAD5:
+ case VK_NUMPAD6:
+ case VK_NUMPAD7:
+ case VK_NUMPAD8:
+ case VK_NUMPAD9:
+ case VK_MULTIPLY:
+ case VK_ADD:
+ case VK_SEPARATOR:
+ case VK_SUBTRACT:
+ case VK_DECIMAL:
+ case VK_DIVIDE:
+ case VK_OEM_1:
+ case VK_OEM_PLUS:
+ case VK_OEM_COMMA:
+ case VK_OEM_MINUS:
+ case VK_OEM_PERIOD:
+ case VK_OEM_2:
+ case VK_OEM_3:
+ case VK_OEM_4:
+ case VK_OEM_5:
+ case VK_OEM_6:
+ case VK_OEM_7:
+ return true;
+ default:
+ return false;
+ }
+}
+
PlatformKeyboardEvent::PlatformKeyboardEvent(QKeyEvent* event)
{
const int state = event->modifiers();
@@ -539,7 +612,7 @@ void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool)
we try to detect this situation and still set the text, to ensure that the
general event handling sends a key press event after this disambiguation.
*/
- if (m_text.isEmpty() && m_windowsVirtualKeyCode && m_qtEvent->key() < Qt::Key_Escape)
+ if (m_text.isEmpty() && m_windowsVirtualKeyCode && isVirtualKeyCodeRepresentingCharacter(m_windowsVirtualKeyCode))
m_text.append(UChar(m_windowsVirtualKeyCode));
m_keyIdentifier = String();
@@ -562,6 +635,18 @@ void PlatformKeyboardEvent::getCurrentModifierState(bool& shiftKey, bool& ctrlKe
metaKey = false;
}
+uint32_t PlatformKeyboardEvent::nativeModifiers() const
+{
+ ASSERT(m_qtEvent);
+ return m_qtEvent->nativeModifiers();
+}
+
+uint32_t PlatformKeyboardEvent::nativeScanCode() const
+{
+ ASSERT(m_qtEvent);
+ return m_qtEvent->nativeScanCode();
+}
+
}
// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/qt/QWebPageClient.h b/WebCore/platform/qt/QWebPageClient.h
index 9301cd5..f5d8c1b 100644
--- a/WebCore/platform/qt/QWebPageClient.h
+++ b/WebCore/platform/qt/QWebPageClient.h
@@ -30,6 +30,7 @@
#include <QCursor>
#endif
+#include <QPalette>
#include <QRect>
QT_BEGIN_NAMESPACE
diff --git a/WebCore/platform/qt/Maemo5Webstyle.cpp b/WebCore/platform/qt/QtMobileWebStyle.cpp
index 42b0b71..240faa5 100644
--- a/WebCore/platform/qt/Maemo5Webstyle.cpp
+++ b/WebCore/platform/qt/QtMobileWebStyle.cpp
@@ -18,7 +18,7 @@
*
*/
#include "config.h"
-#include "Maemo5Webstyle.h"
+#include "QtMobileWebStyle.h"
#include "QtStyleOptionWebComboBox.h"
@@ -26,7 +26,7 @@
#include <QPixmapCache>
#include <QStyleOption>
-Maemo5WebStyle::Maemo5WebStyle()
+QtMobileWebStyle::QtMobileWebStyle()
{
}
@@ -44,10 +44,10 @@ static inline void drawRectangularControlBackground(QPainter* painter, const QPe
painter->setBrush(oldBrush);
}
-void Maemo5WebStyle::drawChecker(QPainter* painter, int size, QColor color) const
+void QtMobileWebStyle::drawChecker(QPainter* painter, int size, QColor color) const
{
int border = qMin(qMax(1, int(0.2 * size)), 6);
- int checkerSize = size - 2 * border;
+ int checkerSize = qMax(size - 2 * border, 3);
int width = checkerSize / 3;
int middle = qMax(3 * checkerSize / 7, 3);
int x = ((size - checkerSize) >> 1);
@@ -67,7 +67,7 @@ void Maemo5WebStyle::drawChecker(QPainter* painter, int size, QColor color) cons
painter->drawLines(lines.constData(), lines.size());
}
-QPixmap Maemo5WebStyle::findChecker(const QRect& rect, bool disabled) const
+QPixmap QtMobileWebStyle::findChecker(const QRect& rect, bool disabled) const
{
int size = qMin(rect.width(), rect.height());
QPixmap result;
@@ -77,24 +77,31 @@ QPixmap Maemo5WebStyle::findChecker(const QRect& rect, bool disabled) const
result = QPixmap(size, size);
result.fill(Qt::transparent);
QPainter painter(&result);
- drawChecker(&painter, size, disabled ? Qt::gray : Qt::black);
+ drawChecker(&painter, size, disabled ? Qt::lightGray : Qt::darkGray);
QPixmapCache::insert(key, result);
}
return result;
}
-void Maemo5WebStyle::drawRadio(QPainter* painter, const QSize& size, bool checked, QColor color) const
+void QtMobileWebStyle::drawRadio(QPainter* painter, const QSize& size, bool checked, QColor color) const
{
painter->setRenderHint(QPainter::Antialiasing, true);
// deflate one pixel
QRect rect = QRect(QPoint(1, 1), QSize(size.width() - 2, size.height() - 2));
+ const QPoint centerGradient(rect.bottomRight() * 0.7);
+
+ QRadialGradient radialGradient(centerGradient, centerGradient.x() - 1);
+ radialGradient.setColorAt(0.0, Qt::white);
+ radialGradient.setColorAt(0.6, Qt::white);
+ radialGradient.setColorAt(1.0, color);
- QPen pen(Qt::black);
- pen.setWidth(1);
painter->setPen(color);
- painter->setBrush(Qt::white);
+ painter->setBrush(color);
+ painter->drawEllipse(rect);
+ painter->setBrush(radialGradient);
painter->drawEllipse(rect);
+
int border = 0.1 * (rect.width() + rect.height());
border = qMin(qMax(2, border), 10);
rect.adjust(border, border, -border, -border);
@@ -105,7 +112,7 @@ void Maemo5WebStyle::drawRadio(QPainter* painter, const QSize& size, bool checke
}
}
-QPixmap Maemo5WebStyle::findRadio(const QSize& size, bool checked, bool disabled) const
+QPixmap QtMobileWebStyle::findRadio(const QSize& size, bool checked, bool disabled) const
{
QPixmap result;
static const QString prefix = "$qt-maemo5-" + QLatin1String(metaObject()->className()) + "-radio-";
@@ -115,19 +122,29 @@ QPixmap Maemo5WebStyle::findRadio(const QSize& size, bool checked, bool disabled
result = QPixmap(size);
result.fill(Qt::transparent);
QPainter painter(&result);
- drawRadio(&painter, size, checked, disabled ? Qt::gray : Qt::black);
+ drawRadio(&painter, size, checked, disabled ? Qt::lightGray : Qt::darkGray);
QPixmapCache::insert(key, result);
}
return result;
}
-void Maemo5WebStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
+void QtMobileWebStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element) {
case CE_CheckBox: {
QRect rect = option->rect;
const bool disabled = !(option->state & State_Enabled);
- drawRectangularControlBackground(painter, QPen(disabled ? Qt::gray : Qt::black), rect, option->palette.base());
+
+ QLinearGradient linearGradient(rect.topLeft(), rect.bottomLeft());
+ if (disabled) {
+ linearGradient.setColorAt(0.0, Qt::lightGray);
+ linearGradient.setColorAt(0.5, Qt::white);
+ } else {
+ linearGradient.setColorAt(0.0, Qt::darkGray);
+ linearGradient.setColorAt(0.5, Qt::white);
+ }
+
+ drawRectangularControlBackground(painter, QPen(disabled ? Qt::lightGray : Qt::darkGray), rect, linearGradient);
rect.adjust(1, 1, -1, -1);
if (option->state & State_Off)
@@ -155,7 +172,7 @@ void Maemo5WebStyle::drawControl(ControlElement element, const QStyleOption* opt
}
}
-void Maemo5WebStyle::drawMultipleComboButton(QPainter* painter, const QSize& size, QColor color) const
+void QtMobileWebStyle::drawMultipleComboButton(QPainter* painter, const QSize& size, QColor color) const
{
int rectWidth = size.width() - 1;
int width = qMax(2, rectWidth >> 3);
@@ -170,17 +187,25 @@ void Maemo5WebStyle::drawMultipleComboButton(QPainter* painter, const QSize& siz
painter->drawRect(2 * (width + distance), top, width, width);
}
-void Maemo5WebStyle::drawSimpleComboButton(QPainter* painter, const QSize& size, QColor color) const
+void QtMobileWebStyle::drawSimpleComboButton(QPainter* painter, const QSize& size, QColor color) const
{
- QPolygon polygon;
int width = size.width();
- polygon.setPoints(3, 0, 0, width - 1, 0, width >> 1, size.height());
+ int midle = width >> 1;
+ QVector<QLine> lines(width + 1);
+
+ for (int x = 0, y = 0; x < midle; x++, y++) {
+ lines[x] = QLine(x, y, x, y + 2);
+ lines[x + midle] = QLine(width - x - 1, y, width - x - 1, y + 2);
+ }
+ // Just to ensure the lines' intersection.
+ lines[width] = QLine(midle, midle, midle, midle + 2);
+
painter->setPen(color);
painter->setBrush(color);
- painter->drawPolygon(polygon);
+ painter->drawLines(lines);
}
-QSize Maemo5WebStyle::getButtonImageSize(const QSize& buttonSize) const
+QSize QtMobileWebStyle::getButtonImageSize(const QSize& buttonSize) const
{
const int border = qMax(3, buttonSize.width() >> 3) << 1;
@@ -195,10 +220,10 @@ QSize Maemo5WebStyle::getButtonImageSize(const QSize& buttonSize) const
else
width = height << 1;
- return QSize(width + 1, width >> 1);
+ return QSize(width + 1, width);
}
-QPixmap Maemo5WebStyle::findComboButton(const QSize& size, bool multiple, bool disabled) const
+QPixmap QtMobileWebStyle::findComboButton(const QSize& size, bool multiple, bool disabled) const
{
QPixmap result;
QSize imageSize = getButtonImageSize(size);
@@ -214,15 +239,15 @@ QPixmap Maemo5WebStyle::findComboButton(const QSize& size, bool multiple, bool d
result.fill(Qt::transparent);
QPainter painter(&result);
if (multiple)
- drawMultipleComboButton(&painter, imageSize, disabled ? Qt::gray : Qt::black);
+ drawMultipleComboButton(&painter, imageSize, disabled ? Qt::lightGray : Qt::darkGray);
else
- drawSimpleComboButton(&painter, imageSize, disabled ? Qt::gray : Qt::black);
+ drawSimpleComboButton(&painter, imageSize, disabled ? Qt::lightGray : Qt::darkGray);
QPixmapCache::insert(key, result);
}
return result;
}
-void Maemo5WebStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
+void QtMobileWebStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
{
switch (control) {
case CC_ComboBox: {
diff --git a/WebCore/platform/qt/Maemo5Webstyle.h b/WebCore/platform/qt/QtMobileWebStyle.h
index ce717b6..779bd26 100644
--- a/WebCore/platform/qt/Maemo5Webstyle.h
+++ b/WebCore/platform/qt/QtMobileWebStyle.h
@@ -18,14 +18,14 @@
*
*/
-#ifndef Maemo5Webstyle_h
-#define Maemo5Webstyle_h
+#ifndef QtMobileWebStyle_h
+#define QtMobileWebStyle_h
#include <QWindowsStyle>
-class Maemo5WebStyle : public QWindowsStyle {
+class QtMobileWebStyle : public QWindowsStyle {
public:
- Maemo5WebStyle();
+ QtMobileWebStyle();
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = 0) const;
void drawComplexControl(ComplexControl cc, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = 0) const;
@@ -44,4 +44,4 @@ private:
};
-#endif // Maemo5WebStyle_h
+#endif // QtMobileWebStyle_h
diff --git a/WebCore/platform/qt/RenderThemeQt.cpp b/WebCore/platform/qt/RenderThemeQt.cpp
index 7388b76..50b5de6 100644
--- a/WebCore/platform/qt/RenderThemeQt.cpp
+++ b/WebCore/platform/qt/RenderThemeQt.cpp
@@ -43,7 +43,7 @@
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
#if USE(QT_MOBILE_THEME)
-#include "Maemo5Webstyle.h"
+#include "QtMobileWebStyle.h"
#endif
#include "NotImplemented.h"
#include "Page.h"
@@ -152,7 +152,7 @@ RenderThemeQt::RenderThemeQt(Page* page)
#endif
#if USE(QT_MOBILE_THEME)
- m_fallbackStyle = new Maemo5WebStyle;
+ m_fallbackStyle = new QtMobileWebStyle;
#else
m_fallbackStyle = QStyleFactory::create(QLatin1String("windows"));
#endif
@@ -779,6 +779,7 @@ bool RenderThemeQt::paintSliderTrack(RenderObject* o, const PaintInfo& pi,
QStyleOptionSlider option;
if (p.widget)
option.initFrom(p.widget);
+ option.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;
ControlPart appearance = initializeCommonQStyleOptions(option, o);
RenderSlider* renderSlider = toRenderSlider(o);
diff --git a/WebCore/platform/sql/SQLiteDatabase.cpp b/WebCore/platform/sql/SQLiteDatabase.cpp
index 80d3946..b9e7639 100644
--- a/WebCore/platform/sql/SQLiteDatabase.cpp
+++ b/WebCore/platform/sql/SQLiteDatabase.cpp
@@ -34,6 +34,7 @@
#include <sqlite3.h>
#include <wtf/Threading.h>
#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
namespace WebCore {
@@ -64,8 +65,7 @@ bool SQLiteDatabase::open(const String& filename, bool forWebSQLDatabase)
{
close();
- m_lastError = SQLiteFileSystem::openDatabase(filename, &m_db, forWebSQLDatabase);
- if (m_lastError != SQLITE_OK) {
+ if (SQLiteFileSystem::openDatabase(filename, &m_db, forWebSQLDatabase) != SQLITE_OK) {
LOG_ERROR("SQLite database failed to load from %s\nCause - %s", filename.ascii().data(),
sqlite3_errmsg(m_db));
sqlite3_close(m_db);
@@ -100,6 +100,7 @@ void SQLiteDatabase::close()
void SQLiteDatabase::interrupt()
{
+#if !ENABLE(SINGLE_THREADED)
m_interrupted = true;
while (!m_lockingMutex.tryLock()) {
MutexLocker locker(m_databaseClosingMutex);
@@ -110,6 +111,7 @@ void SQLiteDatabase::interrupt()
}
m_lockingMutex.unlock();
+#endif
}
bool SQLiteDatabase::isInterrupted()
@@ -217,7 +219,7 @@ int64_t SQLiteDatabase::totalSize()
void SQLiteDatabase::setSynchronous(SynchronousPragma sync)
{
- executeCommand(String::format("PRAGMA synchronous = %i", sync));
+ executeCommand(makeString("PRAGMA synchronous = ", String::number(sync)));
}
void SQLiteDatabase::setBusyTimeout(int ms)
diff --git a/WebCore/platform/sql/SQLiteDatabase.h b/WebCore/platform/sql/SQLiteDatabase.h
index 8151380..c329273 100644
--- a/WebCore/platform/sql/SQLiteDatabase.h
+++ b/WebCore/platform/sql/SQLiteDatabase.h
@@ -139,7 +139,6 @@ private:
int pageSize();
sqlite3* m_db;
- int m_lastError;
int m_pageSize;
bool m_transactionInProgress;
diff --git a/WebCore/platform/text/Base64.cpp b/WebCore/platform/text/Base64.cpp
index cc22cf8..98b537a 100644
--- a/WebCore/platform/text/Base64.cpp
+++ b/WebCore/platform/text/Base64.cpp
@@ -2,6 +2,7 @@
Copyright (C) 2000-2001 Dawit Alemayehu <adawit@kde.org>
Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL)
@@ -25,6 +26,7 @@
#include <limits.h>
#include <wtf/StringExtras.h>
+#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -70,7 +72,7 @@ void base64Encode(const char* data, unsigned len, Vector<char>& out, bool insert
return;
// If the input string is pathologically large, just return nothing.
- // Note: Keep this in sync with the "out_len" computation below.
+ // Note: Keep this in sync with the "outLength" computation below.
// Rather than being perfectly precise, this is a bit conservative.
const unsigned maxInputBufferSize = UINT_MAX / 77 * 76 / 4 * 3 - 2;
if (len > maxInputBufferSize)
@@ -79,21 +81,21 @@ void base64Encode(const char* data, unsigned len, Vector<char>& out, bool insert
unsigned sidx = 0;
unsigned didx = 0;
- unsigned out_len = ((len + 2) / 3) * 4;
+ unsigned outLength = ((len + 2) / 3) * 4;
// Deal with the 76 character per line limit specified in RFC 2045.
- insertLFs = (insertLFs && out_len > 76);
+ insertLFs = (insertLFs && outLength > 76);
if (insertLFs)
- out_len += ((out_len - 1) / 76);
+ outLength += ((outLength - 1) / 76);
int count = 0;
- out.grow(out_len);
+ out.grow(outLength);
// 3-byte to 4-byte conversion + 0-63 to ascii printable conversion
if (len > 1) {
while (sidx < len - 2) {
if (insertLFs) {
- if (count && (count % 76) == 0)
+ if (count && !(count % 76))
out[didx++] = '\n';
count += 4;
}
@@ -106,7 +108,7 @@ void base64Encode(const char* data, unsigned len, Vector<char>& out, bool insert
}
if (sidx < len) {
- if (insertLFs && (count > 0) && (count % 76) == 0)
+ if (insertLFs && (count > 0) && !(count % 76))
out[didx++] = '\n';
out[didx++] = base64EncMap[(data[sidx] >> 2) & 077];
@@ -124,7 +126,7 @@ void base64Encode(const char* data, unsigned len, Vector<char>& out, bool insert
}
}
-bool base64Decode(const Vector<char>& in, Vector<char>& out)
+bool base64Decode(const Vector<char>& in, Vector<char>& out, Base64DecodePolicy policy)
{
out.clear();
@@ -132,36 +134,49 @@ bool base64Decode(const Vector<char>& in, Vector<char>& out)
if (in.size() > UINT_MAX)
return false;
- return base64Decode(in.data(), in.size(), out);
+ return base64Decode(in.data(), in.size(), out, policy);
}
-bool base64Decode(const char* data, unsigned len, Vector<char>& out)
+template<typename T>
+static inline bool base64DecodeInternal(const T* data, unsigned len, Vector<char>& out, Base64DecodePolicy policy)
{
out.clear();
- if (len == 0)
+ if (!len)
return true;
- while (len && data[len-1] == '=')
- --len;
-
out.grow(len);
+
+ bool sawEqualsSign = false;
+ unsigned outLength = 0;
for (unsigned idx = 0; idx < len; idx++) {
- unsigned char ch = data[idx];
- if ((ch > 47 && ch < 58) || (ch > 64 && ch < 91) || (ch > 96 && ch < 123) || ch == '+' || ch == '/' || ch == '=')
- out[idx] = base64DecMap[ch];
- else
+ unsigned ch = data[idx];
+ if (ch == '=')
+ sawEqualsSign = true;
+ else if (('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || ch == '+' || ch == '/') {
+ if (sawEqualsSign)
+ return false;
+ out[outLength] = base64DecMap[ch];
+ outLength++;
+ } else if (policy == FailOnInvalidCharacter || (policy == IgnoreWhitespace && !isSpaceOrNewline(ch)))
return false;
}
+ if (!outLength)
+ return !sawEqualsSign;
+
+ // Valid data is (n * 4 + [0,2,3]) characters long.
+ if ((outLength % 4) == 1)
+ return false;
+
// 4-byte to 3-byte conversion
- unsigned outLen = len - ((len + 3) / 4);
- if (!outLen || ((outLen + 2) / 3) * 4 < len)
+ outLength -= (outLength + 3) / 4;
+ if (!outLength)
return false;
unsigned sidx = 0;
unsigned didx = 0;
- if (outLen > 1) {
- while (didx < outLen - 2) {
+ if (outLength > 1) {
+ while (didx < outLength - 2) {
out[didx] = (((out[sidx] << 2) & 255) | ((out[sidx + 1] >> 4) & 003));
out[didx + 1] = (((out[sidx + 1] << 4) & 255) | ((out[sidx + 2] >> 2) & 017));
out[didx + 2] = (((out[sidx + 2] << 6) & 255) | (out[sidx + 3] & 077));
@@ -170,16 +185,26 @@ bool base64Decode(const char* data, unsigned len, Vector<char>& out)
}
}
- if (didx < outLen)
+ if (didx < outLength)
out[didx] = (((out[sidx] << 2) & 255) | ((out[sidx + 1] >> 4) & 003));
- if (++didx < outLen)
+ if (++didx < outLength)
out[didx] = (((out[sidx + 1] << 4) & 255) | ((out[sidx + 2] >> 2) & 017));
- if (outLen < out.size())
- out.shrink(outLen);
+ if (outLength < out.size())
+ out.shrink(outLength);
return true;
}
+bool base64Decode(const char* data, unsigned len, Vector<char>& out, Base64DecodePolicy policy)
+{
+ return base64DecodeInternal<char>(data, len, out, policy);
}
+
+bool base64Decode(const String& in, Vector<char>& out, Base64DecodePolicy policy)
+{
+ return base64DecodeInternal<UChar>(in.characters(), in.length(), out, policy);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/text/Base64.h b/WebCore/platform/text/Base64.h
index 53b29b0..211bd3c 100644
--- a/WebCore/platform/text/Base64.h
+++ b/WebCore/platform/text/Base64.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
+ * 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
@@ -26,16 +27,19 @@
#ifndef Base64_h
#define Base64_h
+#include <wtf/Forward.h>
#include <wtf/Vector.h>
namespace WebCore {
+enum Base64DecodePolicy { FailOnInvalidCharacter, IgnoreWhitespace, IgnoreInvalidCharacters };
+
void base64Encode(const Vector<char>&, Vector<char>&, bool insertLFs = false);
void base64Encode(const char*, unsigned, Vector<char>&, bool insertLFs = false);
-// this decoder is not general purpose - it returns an error if it encounters a linefeed, as needed for window.atob
-bool base64Decode(const Vector<char>&, Vector<char>&);
-bool base64Decode(const char*, unsigned, Vector<char>&);
+bool base64Decode(const String&, Vector<char>&, Base64DecodePolicy = FailOnInvalidCharacter);
+bool base64Decode(const Vector<char>&, Vector<char>&, Base64DecodePolicy = FailOnInvalidCharacter);
+bool base64Decode(const char*, unsigned, Vector<char>&, Base64DecodePolicy = FailOnInvalidCharacter);
}
diff --git a/WebCore/platform/text/LineEnding.cpp b/WebCore/platform/text/LineEnding.cpp
index 545f22b..00a90eb 100644
--- a/WebCore/platform/text/LineEnding.cpp
+++ b/WebCore/platform/text/LineEnding.cpp
@@ -35,12 +35,69 @@
#include "PlatformString.h"
#include <wtf/text/CString.h>
-namespace WebCore {
+namespace {
-// Normalize all line-endings to CRLF.
-CString normalizeLineEndingsToCRLF(const CString& from)
+class OutputBuffer {
+public:
+ virtual char* allocate(size_t size) = 0;
+ virtual void copy(const CString&) = 0;
+ virtual ~OutputBuffer() { }
+};
+
+class CStringBuffer : public OutputBuffer {
+public:
+ CStringBuffer(CString& buffer)
+ : m_buffer(buffer)
+ {
+ }
+ virtual ~CStringBuffer() { }
+
+ virtual char* allocate(size_t size)
+ {
+ char* ptr;
+ m_buffer = CString::newUninitialized(size, ptr);
+ return ptr;
+ }
+
+ virtual void copy(const CString& source)
+ {
+ m_buffer = source;
+ }
+
+ const CString& buffer() const { return m_buffer; }
+
+private:
+ CString m_buffer;
+};
+
+class VectorCharAppendBuffer : public OutputBuffer {
+public:
+ VectorCharAppendBuffer(Vector<char>& buffer)
+ : m_buffer(buffer)
+ {
+ }
+ virtual ~VectorCharAppendBuffer() { }
+
+ virtual char* allocate(size_t size)
+ {
+ size_t oldSize = m_buffer.size();
+ m_buffer.grow(oldSize + size);
+ return m_buffer.data() + oldSize;
+ }
+
+ virtual void copy(const CString& source)
+ {
+ m_buffer.append(source.data(), source.length());
+ }
+
+private:
+ Vector<char>& m_buffer;
+};
+
+void internalNormalizeLineEndingsToCRLF(const CString& from, OutputBuffer& buffer)
{
- unsigned newLen = 0;
+ // Compute the new length.
+ size_t newLen = 0;
const char* p = from.data();
while (char c = *p++) {
if (c == '\r') {
@@ -57,13 +114,18 @@ CString normalizeLineEndingsToCRLF(const CString& from)
newLen += 1;
}
}
- if (newLen == from.length())
- return from;
+ if (newLen < from.length())
+ return;
+
+ if (newLen == from.length()) {
+ buffer.copy(from);
+ return;
+ }
- // Make a copy of the string.
p = from.data();
- char* q;
- CString result = CString::newUninitialized(newLen, q);
+ char* q = buffer.allocate(newLen);
+
+ // Make a copy of the string.
while (char c = *p++) {
if (c == '\r') {
// Safe to look ahead because of trailing '\0'.
@@ -81,13 +143,19 @@ CString normalizeLineEndingsToCRLF(const CString& from)
*q++ = c;
}
}
- return result;
}
+};
+
+namespace WebCore {
+
+void normalizeToCROrLF(const CString& from, Vector<char>& result, bool toCR);
+
// Normalize all line-endings to CR or LF.
-static CString normalizeToCROrLF(const CString& from, bool toCR)
+void normalizeToCROrLF(const CString& from, Vector<char>& result, bool toCR)
{
- unsigned newLen = 0;
+ // Compute the new length.
+ size_t newLen = 0;
bool needFix = false;
const char* p = from.data();
char fromEndingChar = toCR ? '\n' : '\r';
@@ -103,13 +171,20 @@ static CString normalizeToCROrLF(const CString& from, bool toCR)
}
newLen += 1;
}
- if (!needFix)
- return from;
- // Make a copy of the string.
+ // Grow the result buffer.
p = from.data();
- char* q;
- CString result = CString::newUninitialized(newLen, q);
+ size_t oldResultSize = result.size();
+ result.grow(oldResultSize + newLen);
+ char* q = result.data() + oldResultSize;
+
+ // If no need to fix the string, just copy the string over.
+ if (!needFix) {
+ memcpy(q, p, from.length());
+ return;
+ }
+
+ // Make a copy of the string.
while (char c = *p++) {
if (c == '\r' && *p == '\n') {
// Turn CRLF or CR into CR or LF.
@@ -123,27 +198,33 @@ static CString normalizeToCROrLF(const CString& from, bool toCR)
*q++ = c;
}
}
- return result;
}
-// Normalize all line-endings to CR.
-CString normalizeLineEndingsToCR(const CString& from)
+CString normalizeLineEndingsToCRLF(const CString& from)
+{
+ CString result;
+ CStringBuffer buffer(result);
+ internalNormalizeLineEndingsToCRLF(from, buffer);
+ return buffer.buffer();
+}
+
+void normalizeLineEndingsToCR(const CString& from, Vector<char>& result)
{
- return normalizeToCROrLF(from, true);
+ normalizeToCROrLF(from, result, true);
}
-// Normalize all line-endings to LF.
-CString normalizeLineEndingsToLF(const CString& from)
+void normalizeLineEndingsToLF(const CString& from, Vector<char>& result)
{
- return normalizeToCROrLF(from, false);
+ normalizeToCROrLF(from, result, false);
}
-CString normalizeLineEndingsToNative(const CString& from)
+void normalizeLineEndingsToNative(const CString& from, Vector<char>& result)
{
#if OS(WINDOWS)
- return normalizeLineEndingsToCRLF(from);
+ VectorCharAppendBuffer buffer(result);
+ internalNormalizeLineEndingsToCRLF(from, buffer);
#else
- return normalizeLineEndingsToLF(from);
+ normalizeLineEndingsToLF(from, result);
#endif
}
diff --git a/WebCore/platform/text/LineEnding.h b/WebCore/platform/text/LineEnding.h
index ab8d6ee..4306ce8 100644
--- a/WebCore/platform/text/LineEnding.h
+++ b/WebCore/platform/text/LineEnding.h
@@ -33,25 +33,22 @@
#define LineEnding_h
#include <wtf/Forward.h>
-
-namespace WTF {
-class CString;
-}
+#include <wtf/Vector.h>
namespace WebCore {
// Normalize all line-endings in the given string to CRLF.
-WTF::CString normalizeLineEndingsToCRLF(const WTF::CString&);
+CString normalizeLineEndingsToCRLF(const CString& from);
-// Normalize all line-endings in the given string to CR.
-WTF::CString normalizeLineEndingsToCR(const WTF::CString&);
+// Normalize all line-endings in the given string to CR and append the result to the given buffer.
+void normalizeLineEndingsToCR(const CString& from, Vector<char>& result);
-// Normalize all line-endings in the given string to LF.
-WTF::CString normalizeLineEndingsToLF(const WTF::CString&);
+// Normalize all line-endings in the given string to LF and append the result to the given buffer.
+void normalizeLineEndingsToLF(const CString& from, Vector<char>& result);
-// Normalize all line-endings in the given string to the native line-endings.
+// Normalize all line-endings in the given string to the native line-endings and append the result to the given buffer.
// (Normalize to CRLF on Windows and normalize to LF on all other platforms.)
-WTF::CString normalizeLineEndingsToNative(const WTF::CString&);
+void normalizeLineEndingsToNative(const CString& from, Vector<char>& result);
} // namespace WebCore
diff --git a/WebCore/platform/text/StringBuffer.h b/WebCore/platform/text/StringBuffer.h
deleted file mode 100644
index 3a753b4..0000000
--- a/WebCore/platform/text/StringBuffer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 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 WebCoreStringBuffer_h
-#define WebCoreStringBuffer_h
-
-// FIXME: remove this header, use the forward from wtf directly.
-#include <wtf/text/StringBuffer.h>
-
-#endif // StringBuffer_h
diff --git a/WebCore/platform/text/StringBuilder.cpp b/WebCore/platform/text/StringBuilder.cpp
deleted file mode 100644
index 1c47129..0000000
--- a/WebCore/platform/text/StringBuilder.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
- * 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.
- * 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 "StringBuilder.h"
-
-#include <wtf/text/StringBuffer.h>
-
-namespace WebCore {
-
-void StringBuilder::append(const String& string)
-{
- if (string.isNull())
- return;
-
- if (m_totalLength == UINT_MAX)
- m_totalLength = string.length();
- else
- m_totalLength += string.length();
-
- if (!string.isEmpty())
- m_strings.append(string);
-}
-
-void StringBuilder::append(UChar c)
-{
- if (m_totalLength == UINT_MAX)
- m_totalLength = 1;
- else
- m_totalLength += 1;
-
- m_strings.append(String(&c, 1));
-}
-
-void StringBuilder::append(char c)
-{
- if (m_totalLength == UINT_MAX)
- m_totalLength = 1;
- else
- m_totalLength += 1;
-
- m_strings.append(String(&c, 1));
-}
-
-String StringBuilder::toString(ConcatMode mode) const
-{
- if (isNull())
- return String();
-
- unsigned count = m_strings.size();
-
- if (!count)
- return String(StringImpl::empty());
- if (count == 1)
- return m_strings[0];
-
- UChar* buffer;
- unsigned totalLength = m_totalLength;
- if (mode == ConcatAddingSpacesBetweenIndividualStrings)
- totalLength += count - 1;
- String result = String::createUninitialized(totalLength, buffer);
-
- UChar* p = buffer;
-
- // We could handle both Concat modes in a single for loop, not doing that for performance reasons.
- if (mode == ConcatUnaltered) {
- for (unsigned i = 0; i < count; ++i) {
- StringImpl* string = m_strings[i].impl();
- unsigned length = string->length();
- memcpy(p, string->characters(), length * 2);
- p += length;
- }
- } else {
- ASSERT(mode == ConcatAddingSpacesBetweenIndividualStrings);
- for (unsigned i = 0; i < count; ++i) {
- StringImpl* string = m_strings[i].impl();
- unsigned length = string->length();
- memcpy(p, string->characters(), length * 2);
- p += length;
-
- // Add space after string before the start of the next string, if we're not processing the last string.
- if (i < count - 1) {
- *p = ' ';
- ++p;
- }
- }
- }
- ASSERT(p == totalLength + buffer);
-
- return result;
-}
-
-void StringBuilder::clear()
-{
- m_totalLength = UINT_MAX;
- m_strings.clear();
-}
-
-unsigned StringBuilder::length() const
-{
- if (m_totalLength == UINT_MAX)
- return 0;
- return m_totalLength;
-}
-
-}
diff --git a/WebCore/platform/text/TextEncoding.cpp b/WebCore/platform/text/TextEncoding.cpp
index 29ae170..921ceeb 100644
--- a/WebCore/platform/text/TextEncoding.cpp
+++ b/WebCore/platform/text/TextEncoding.cpp
@@ -133,6 +133,10 @@ CString TextEncoding::encode(const UChar* characters, size_t length, Unencodable
// normalization will be done by Windows CE API
OwnPtr<TextCodec> textCodec = newTextCodec(*this);
return textCodec.get() ? textCodec->encode(characters, length, handling) : CString();
+#elif USE(BREWMP_UNICODE)
+ // FIXME: not sure if Brew MP normalizes the input string automatically
+ OwnPtr<TextCodec> textCodec = newTextCodec(*this);
+ return textCodec.get() ? textCodec->encode(characters, length, handling) : CString();
#endif
}
diff --git a/WebCore/platform/text/TextEncodingRegistry.cpp b/WebCore/platform/text/TextEncodingRegistry.cpp
index 40fcdc5..fbe5826 100644
--- a/WebCore/platform/text/TextEncodingRegistry.cpp
+++ b/WebCore/platform/text/TextEncodingRegistry.cpp
@@ -31,6 +31,7 @@
#include "TextCodecLatin1.h"
#include "TextCodecUserDefined.h"
#include "TextCodecUTF16.h"
+#include "TextEncoding.h"
#include <wtf/ASCIICType.h>
#include <wtf/Assertions.h>
#include <wtf/HashFunctions.h>
@@ -51,6 +52,9 @@
#if USE(GLIB_UNICODE)
#include "gtk/TextCodecGtk.h"
#endif
+#if USE(BREWMP_UNICODE)
+#include "brew/TextCodecBrew.h"
+#endif
#if OS(WINCE) && !PLATFORM(QT)
#include "TextCodecWinCE.h"
#endif
@@ -235,6 +239,11 @@ static void buildBaseTextCodecMaps()
TextCodecGtk::registerBaseCodecs(addToTextCodecMap);
#endif
+#if USE(BREWMP_UNICODE)
+ TextCodecBrew::registerBaseEncodingNames(addToTextEncodingNameMap);
+ TextCodecBrew::registerBaseCodecs(addToTextCodecMap);
+#endif
+
#if OS(WINCE) && !PLATFORM(QT)
TextCodecWinCE::registerBaseEncodingNames(addToTextEncodingNameMap);
TextCodecWinCE::registerBaseCodecs(addToTextCodecMap);
diff --git a/WebCore/platform/text/brew/TextBoundariesBrew.cpp b/WebCore/platform/text/brew/TextBoundariesBrew.cpp
new file mode 100644
index 0000000..506bdcf
--- /dev/null
+++ b/WebCore/platform/text/brew/TextBoundariesBrew.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2007-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.
+ */
+
+#include "config.h"
+#include "TextBoundaries.h"
+
+#include "NotImplemented.h"
+#include "PlatformString.h"
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+int findNextWordFromIndex(const UChar* buffer, int len, int position, bool forward)
+{
+ notImplemented();
+ return 0;
+}
+
+void findWordBoundary(const UChar* buffer, int len, int position, int* start, int* end)
+{
+ if (position > len) {
+ *start = 0;
+ *end = 0;
+ return;
+ }
+
+ String str(buffer, len);
+
+ int currentPosition = position - 1;
+ String foundWord;
+ while (currentPosition >= 0 && isLetter(str[currentPosition])) {
+ UChar c = str[currentPosition];
+ foundWord.insert(&c, 1, 0);
+ --currentPosition;
+ }
+
+ // currentPosition == 0 means the first char is not letter
+ // currentPosition == -1 means we reached the beginning
+ int startPos = (currentPosition < 0) ? 0 : ++currentPosition;
+ currentPosition = position;
+ while (isLetter(str[currentPosition])) {
+ foundWord.append(str[currentPosition]);
+ ++currentPosition;
+ }
+
+ *start = startPos;
+ *end = currentPosition;
+}
+
+}
diff --git a/WebCore/platform/text/brew/TextBreakIteratorBrew.cpp b/WebCore/platform/text/brew/TextBreakIteratorBrew.cpp
new file mode 100644
index 0000000..7f46e4f
--- /dev/null
+++ b/WebCore/platform/text/brew/TextBreakIteratorBrew.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2006 Lars Knoll <lars@trolltech.com>
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "TextBreakIterator.h"
+
+#include "PlatformString.h"
+#include <wtf/StdLibExtras.h>
+#include <wtf/unicode/Unicode.h>
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+// Hack, not entirely correct
+static inline bool isCharStop(UChar c)
+{
+ CharCategory charCategory = category(c);
+ return charCategory != Mark_NonSpacing && (charCategory != Other_Surrogate || (c < 0xd800 || c >= 0xdc00));
+}
+
+static inline bool isLineStop(UChar c)
+{
+ return category(c) != Separator_Line;
+}
+
+static inline bool isSentenceStop(UChar c)
+{
+ return isPunct(c);
+}
+
+class TextBreakIterator {
+public:
+ void reset(const UChar* str, int len)
+ {
+ string = str;
+ length = len;
+ currentPos = 0;
+ }
+ virtual int first() = 0;
+ virtual int next() = 0;
+ virtual int previous() = 0;
+ int following(int position)
+ {
+ currentPos = position;
+ return next();
+ }
+ int preceding(int position)
+ {
+ currentPos = position;
+ return previous();
+ }
+
+ int currentPos;
+ const UChar* string;
+ int length;
+};
+
+struct WordBreakIterator: TextBreakIterator {
+ virtual int first();
+ virtual int next();
+ virtual int previous();
+};
+
+struct CharBreakIterator: TextBreakIterator {
+ virtual int first();
+ virtual int next();
+ virtual int previous();
+};
+
+struct LineBreakIterator: TextBreakIterator {
+ virtual int first();
+ virtual int next();
+ virtual int previous();
+};
+
+struct SentenceBreakIterator : TextBreakIterator {
+ virtual int first();
+ virtual int next();
+ virtual int previous();
+};
+
+int WordBreakIterator::first()
+{
+ currentPos = 0;
+ return currentPos;
+}
+
+int WordBreakIterator::next()
+{
+ if (currentPos == length) {
+ currentPos = -1;
+ return currentPos;
+ }
+ bool haveSpace = false;
+ while (currentPos < length) {
+ if (haveSpace && !isSpace(string[currentPos]))
+ break;
+ if (isSpace(string[currentPos]))
+ haveSpace = true;
+ ++currentPos;
+ }
+ return currentPos;
+}
+
+int WordBreakIterator::previous()
+{
+ if (!currentPos) {
+ currentPos = -1;
+ return currentPos;
+ }
+ bool haveSpace = false;
+ while (currentPos > 0) {
+ if (haveSpace && !isSpace(string[currentPos]))
+ break;
+ if (isSpace(string[currentPos]))
+ haveSpace = true;
+ --currentPos;
+ }
+ return currentPos;
+}
+
+int CharBreakIterator::first()
+{
+ currentPos = 0;
+ return currentPos;
+}
+
+int CharBreakIterator::next()
+{
+ if (currentPos >= length)
+ return -1;
+ ++currentPos;
+ while (currentPos < length && !isCharStop(string[currentPos]))
+ ++currentPos;
+ return currentPos;
+}
+
+int CharBreakIterator::previous()
+{
+ if (currentPos <= 0)
+ return -1;
+ if (currentPos > length)
+ currentPos = length;
+ --currentPos;
+ while (currentPos > 0 && !isCharStop(string[currentPos]))
+ --currentPos;
+ return currentPos;
+}
+
+int LineBreakIterator::first()
+{
+ currentPos = 0;
+ return currentPos;
+}
+
+int LineBreakIterator::next()
+{
+ if (currentPos == length) {
+ currentPos = -1;
+ return currentPos;
+ }
+ bool haveSpace = false;
+ while (currentPos < length) {
+ if (haveSpace && !isLineStop(string[currentPos]))
+ break;
+ if (isLineStop(string[currentPos]))
+ haveSpace = true;
+ ++currentPos;
+ }
+ return currentPos;
+}
+
+int LineBreakIterator::previous()
+{
+ if (!currentPos) {
+ currentPos = -1;
+ return currentPos;
+ }
+ bool haveSpace = false;
+ while (currentPos > 0) {
+ if (haveSpace && !isLineStop(string[currentPos]))
+ break;
+ if (isLineStop(string[currentPos]))
+ haveSpace = true;
+ --currentPos;
+ }
+ return currentPos;
+}
+
+int SentenceBreakIterator::first()
+{
+ currentPos = 0;
+ return currentPos;
+}
+
+int SentenceBreakIterator::next()
+{
+ if (currentPos == length) {
+ currentPos = -1;
+ return currentPos;
+ }
+ bool haveSpace = false;
+ while (currentPos < length) {
+ if (haveSpace && !isSentenceStop(string[currentPos]))
+ break;
+ if (isSentenceStop(string[currentPos]))
+ haveSpace = true;
+ ++currentPos;
+ }
+ return currentPos;
+}
+
+int SentenceBreakIterator::previous()
+{
+ if (!currentPos) {
+ currentPos = -1;
+ return currentPos;
+ }
+ bool haveSpace = false;
+ while (currentPos > 0) {
+ if (haveSpace && !isSentenceStop(string[currentPos]))
+ break;
+ if (isSentenceStop(string[currentPos]))
+ haveSpace = true;
+ --currentPos;
+ }
+ return currentPos;
+}
+
+TextBreakIterator* wordBreakIterator(const UChar* string, int length)
+{
+ DEFINE_STATIC_LOCAL(WordBreakIterator, iterator, ());
+ iterator.reset(string, length);
+ return &iterator;
+}
+
+TextBreakIterator* characterBreakIterator(const UChar* string, int length)
+{
+ DEFINE_STATIC_LOCAL(CharBreakIterator, iterator, ());
+ iterator.reset(string, length);
+ return &iterator;
+}
+
+TextBreakIterator* lineBreakIterator(const UChar* string, int length)
+{
+ DEFINE_STATIC_LOCAL(LineBreakIterator , iterator, ());
+ iterator.reset(string, length);
+ return &iterator;
+}
+
+TextBreakIterator* sentenceBreakIterator(const UChar* string, int length)
+{
+ DEFINE_STATIC_LOCAL(SentenceBreakIterator, iterator, ());
+ iterator.reset(string, length);
+ return &iterator;
+}
+
+int textBreakFirst(TextBreakIterator* breakIterator)
+{
+ return breakIterator->first();
+}
+
+int textBreakNext(TextBreakIterator* breakIterator)
+{
+ return breakIterator->next();
+}
+
+int textBreakPreceding(TextBreakIterator* breakIterator, int position)
+{
+ return breakIterator->preceding(position);
+}
+
+int textBreakFollowing(TextBreakIterator* breakIterator, int position)
+{
+ return breakIterator->following(position);
+}
+
+int textBreakCurrent(TextBreakIterator* breakIterator)
+{
+ return breakIterator->currentPos;
+}
+
+bool isTextBreak(TextBreakIterator*, int)
+{
+ return true;
+}
+
+TextBreakIterator* cursorMovementIterator(const UChar* string, int length)
+{
+ return characterBreakIterator(string, length);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/text/brew/TextCodecBrew.cpp b/WebCore/platform/text/brew/TextCodecBrew.cpp
new file mode 100644
index 0000000..1f32298
--- /dev/null
+++ b/WebCore/platform/text/brew/TextCodecBrew.cpp
@@ -0,0 +1,214 @@
+/*
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this 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 "TextCodecBrew.h"
+
+#include "AEEAppGen.h"
+#include "AEEICharsetConv.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+#include <wtf/Assertions.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+// FIXME: Not sure if there are Brew MP devices which use big endian.
+const char* WebCore::TextCodecBrew::m_internalEncodingName = "UTF-16LE";
+
+static PassOwnPtr<TextCodec> newTextCodecBrew(const TextEncoding& encoding, const void*)
+{
+ return new TextCodecBrew(encoding);
+}
+
+void TextCodecBrew::registerBaseEncodingNames(EncodingNameRegistrar registrar)
+{
+ registrar("UTF-8", "UTF-8");
+}
+
+void TextCodecBrew::registerBaseCodecs(TextCodecRegistrar registrar)
+{
+ registrar("UTF-8", newTextCodecBrew, 0);
+}
+
+void TextCodecBrew::registerExtendedEncodingNames(EncodingNameRegistrar registrar)
+{
+ // FIXME: Not sure how to enumerate all available encodings.
+ notImplemented();
+}
+
+void TextCodecBrew::registerExtendedCodecs(TextCodecRegistrar registrar)
+{
+ notImplemented();
+}
+
+TextCodecBrew::TextCodecBrew(const TextEncoding& encoding)
+ : m_charsetConverter(0)
+ , m_encoding(encoding)
+ , m_numBufferedBytes(0)
+{
+ String format = String::format("%s>%s", encoding.name(), m_internalEncodingName);
+
+ IShell* shell = reinterpret_cast<AEEApplet*>(GETAPPINSTANCE())->m_pIShell;
+ AEECLSID classID = ISHELL_GetHandler(shell, AEEIID_ICharsetConv, format.latin1().data());
+ ISHELL_CreateInstance(shell, classID, reinterpret_cast<void**>(&m_charsetConverter));
+
+ ASSERT(m_charsetConverter);
+}
+
+TextCodecBrew::~TextCodecBrew()
+{
+ if (m_charsetConverter)
+ ICharsetConv_Release(m_charsetConverter);
+}
+
+String TextCodecBrew::decode(const char* bytes, size_t length, bool flush, bool stopOnError, bool& sawError)
+{
+ int code = ICharsetConv_Initialize(m_charsetConverter, m_encoding.name(), m_internalEncodingName, 0);
+ ASSERT(code == AEE_SUCCESS);
+
+ Vector<UChar> result;
+ Vector<unsigned char> prefixedBytes(length);
+
+ int srcSize;
+ unsigned char* srcBegin;
+
+ if (m_numBufferedBytes) {
+ srcSize = length + m_numBufferedBytes;
+ prefixedBytes.grow(srcSize);
+ memcpy(prefixedBytes.data(), m_bufferedBytes, m_numBufferedBytes);
+ memcpy(prefixedBytes.data() + m_numBufferedBytes, bytes, length);
+
+ srcBegin = prefixedBytes.data();
+
+ // all buffered bytes are consumed now
+ m_numBufferedBytes = 0;
+ } else {
+ srcSize = length;
+ srcBegin = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(bytes));
+ }
+
+ unsigned char* src = srcBegin;
+ unsigned char* srcEnd = srcBegin + srcSize;
+
+ Vector<UChar> dstBuffer(srcSize);
+
+ while (src < srcEnd) {
+ int numCharsConverted;
+ unsigned char* dstBegin = reinterpret_cast<unsigned char*>(dstBuffer.data());
+ unsigned char* dst = dstBegin;
+ int dstSize = dstBuffer.size() * sizeof(UChar);
+
+ code = ICharsetConv_CharsetConvert(m_charsetConverter, &src, &srcSize, &dst, &dstSize, &numCharsConverted);
+ ASSERT(code != AEE_ENOSUCH);
+
+ if (code == AEE_EBUFFERTOOSMALL) {
+ // Increase the buffer and try it again.
+ dstBuffer.grow(dstBuffer.size() * 2);
+ continue;
+ }
+
+ if (code == AEE_EBADITEM) {
+ sawError = true;
+ if (stopOnError) {
+ result.append(L'?');
+ break;
+ }
+
+ src++;
+ }
+
+ if (code == AEE_EINCOMPLETEITEM) {
+ if (flush) {
+ LOG_ERROR("Partial bytes at end of input while flush requested.");
+ sawError = true;
+ return String();
+ }
+
+ m_numBufferedBytes = srcEnd - src;
+ memcpy(m_bufferedBytes, src, m_numBufferedBytes);
+ break;
+ }
+
+ int numChars = (dst - dstBegin) / sizeof(UChar);
+ if (numChars > 0)
+ result.append(dstBuffer.data(), numChars);
+ }
+
+ return String::adopt(result);
+}
+
+CString TextCodecBrew::encode(const UChar* characters, size_t length, UnencodableHandling handling)
+{
+ if (!length)
+ return "";
+
+ unsigned int replacementCharacter = '?';
+
+ // FIXME: Impossible to handle EntitiesForUnencodables or URLEncodedEntitiesForUnencodables with ICharsetConv.
+ int code = ICharsetConv_Initialize(m_charsetConverter, m_internalEncodingName, m_encoding.name(), replacementCharacter);
+ ASSERT(code == AEE_SUCCESS);
+
+ Vector<char> result;
+
+ int srcSize = length * sizeof(UChar);
+ unsigned char* srcBegin = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(characters));
+ unsigned char* src = srcBegin;
+ unsigned char* srcEnd = srcBegin + srcSize;
+
+ Vector<unsigned char> dstBuffer(length * sizeof(UChar));
+
+ while (src < srcEnd) {
+ int numCharsConverted;
+ unsigned char* dstBegin = dstBuffer.data();
+ unsigned char* dst = dstBegin;
+ int dstSize = dstBuffer.size();
+
+ code = ICharsetConv_CharsetConvert(m_charsetConverter, &src, &srcSize, &dst, &dstSize, &numCharsConverted);
+ ASSERT(code != AEE_EINCOMPLETEITEM);
+
+ if (code == AEE_ENOSUCH) {
+ LOG_ERROR("Conversion error, Code=%d", code);
+ return CString();
+ }
+
+ if (code == AEE_EBUFFERTOOSMALL) {
+ // Increase the buffer and try it again.
+ dstBuffer.grow(dstBuffer.size() * 2);
+ continue;
+ }
+
+ if (code == AEE_EBADITEM)
+ src += sizeof(UChar); // Skip the invalid character
+
+ int numBytes = dst - dstBegin;
+ if (numBytes > 0)
+ result.append(dstBuffer.data(), numBytes);
+ }
+
+ return CString(result.data(), result.size());
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/text/brew/TextCodecBrew.h b/WebCore/platform/text/brew/TextCodecBrew.h
new file mode 100644
index 0000000..97e2c87
--- /dev/null
+++ b/WebCore/platform/text/brew/TextCodecBrew.h
@@ -0,0 +1,61 @@
+/*
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this 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 TextCodecBrew_h
+#define TextCodecBrew_h
+
+#include "TextCodec.h"
+#include "TextEncoding.h"
+
+typedef struct ICharsetConv ICharsetConv;
+
+namespace WebCore {
+
+class TextCodecBrew : public TextCodec {
+public:
+ static void registerBaseEncodingNames(EncodingNameRegistrar);
+ static void registerBaseCodecs(TextCodecRegistrar);
+
+ static void registerExtendedEncodingNames(EncodingNameRegistrar);
+ static void registerExtendedCodecs(TextCodecRegistrar);
+
+ TextCodecBrew(const TextEncoding&);
+ virtual ~TextCodecBrew();
+
+ virtual String decode(const char*, size_t length, bool flush, bool stopOnError, bool& sawError);
+ virtual CString encode(const UChar*, size_t length, UnencodableHandling);
+
+private:
+ TextEncoding m_encoding;
+ size_t m_numBufferedBytes;
+ unsigned char m_bufferedBytes[16]; // bigger than any single multi-byte character
+ ICharsetConv* m_charsetConverter;
+
+ static const char* m_internalEncodingName;
+};
+
+} // namespace WebCore
+
+#endif // TextCodecBrew_h
diff --git a/WebCore/platform/text/qt/TextBreakIteratorQt.cpp b/WebCore/platform/text/qt/TextBreakIteratorQt.cpp
index dda443f..b9f5a9e 100644
--- a/WebCore/platform/text/qt/TextBreakIteratorQt.cpp
+++ b/WebCore/platform/text/qt/TextBreakIteratorQt.cpp
@@ -33,6 +33,12 @@
namespace WebCore {
+#if USE(QT_ICU_TEXT_BREAKING)
+const char* currentTextBreakLocaleID()
+{
+ return QLocale::system().name().toLatin1();
+}
+#else
static unsigned char buffer[1024];
class TextBreakIterator : public QTextBoundaryFinder {
@@ -135,5 +141,6 @@ namespace WebCore {
{
return true;
}
+#endif
}
diff --git a/WebCore/platform/text/wince/TextCodecWinCE.cpp b/WebCore/platform/text/wince/TextCodecWinCE.cpp
index 499035f..da6d5a5 100644
--- a/WebCore/platform/text/wince/TextCodecWinCE.cpp
+++ b/WebCore/platform/text/wince/TextCodecWinCE.cpp
@@ -33,6 +33,7 @@
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
#include <wtf/text/StringHash.h>
#include <wtf/unicode/UTF8.h>
@@ -110,7 +111,7 @@ LanguageManager::LanguageManager()
info.m_aliases.append(name);
info.m_aliases.append(String(cpInfo.wszHeaderCharset).latin1());
info.m_aliases.append(String(cpInfo.wszBodyCharset).latin1());
- String cpName = String::format("cp%d", cpInfo.uiCodePage);
+ String cpName = makeString("cp", String::number(cpInfo.uiCodePage));
info.m_aliases.append(cpName.latin1());
supportedCharsets().add(i->second.data());
}
diff --git a/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/WebCore/platform/win/ClipboardUtilitiesWin.cpp
index 0130a70..19888bf 100644
--- a/WebCore/platform/win/ClipboardUtilitiesWin.cpp
+++ b/WebCore/platform/win/ClipboardUtilitiesWin.cpp
@@ -33,7 +33,9 @@
#include "markup.h"
#include <shlwapi.h>
#include <wininet.h> // for INTERNET_MAX_URL_LENGTH
+#include <wtf/StringExtras.h>
#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
#if PLATFORM(CF)
#include <CoreFoundation/CoreFoundation.h>
@@ -239,7 +241,11 @@ void markupToCFHTML(const String& markup, const String& srcURL, Vector<char>& re
unsigned endFragmentOffset = startFragmentOffset + markupUTF8.length();
unsigned endHTMLOffset = endFragmentOffset + strlen(endMarkup);
- append(result, String::format(header, startHTMLOffset, endHTMLOffset, startFragmentOffset, endFragmentOffset).utf8());
+ unsigned headerBufferLength = startHTMLOffset + 1; // + 1 for '\0' terminator.
+ char* headerBuffer = (char*)malloc(headerBufferLength);
+ snprintf(headerBuffer, headerBufferLength, header, startHTMLOffset, endHTMLOffset, startFragmentOffset, endFragmentOffset);
+ append(result, CString(headerBuffer));
+ free(headerBuffer);
if (sourceURLUTF8.length()) {
append(result, sourceURLPrefix);
append(result, sourceURLUTF8);
diff --git a/WebCore/platform/win/ClipboardWin.cpp b/WebCore/platform/win/ClipboardWin.cpp
index 529963f..7a54737 100644
--- a/WebCore/platform/win/ClipboardWin.cpp
+++ b/WebCore/platform/win/ClipboardWin.cpp
@@ -38,6 +38,7 @@
#include "FrameLoader.h"
#include "FrameView.h"
#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
#include "Image.h"
#include "MIMETypeRegistry.h"
#include "NotImplemented.h"
@@ -50,7 +51,6 @@
#include "ResourceResponse.h"
#include "SharedBuffer.h"
#include "WCDataObject.h"
-#include "csshelper.h"
#include "markup.h"
#include <shlwapi.h>
#include <wininet.h>
@@ -723,7 +723,7 @@ void ClipboardWin::declareAndWriteDragImage(Element* element, const KURL& url, c
if (imageURL.isEmpty())
return;
- String fullURL = frame->document()->completeURL(deprecatedParseURL(imageURL)).string();
+ String fullURL = frame->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(imageURL)).string();
if (fullURL.isEmpty())
return;
STGMEDIUM medium = {0};
diff --git a/WebCore/platform/win/Language.cpp b/WebCore/platform/win/LanguageWin.cpp
index 676510b..cafda5d 100644
--- a/WebCore/platform/win/Language.cpp
+++ b/WebCore/platform/win/LanguageWin.cpp
@@ -26,8 +26,7 @@
#include "config.h"
#include "Language.h"
-#include "PlatformString.h"
-#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
namespace WebCore {
@@ -45,10 +44,11 @@ static String localeInfo(LCTYPE localeType, const String& fallback)
if (localeName.isEmpty())
return fallback;
+ localeName.truncate(localeName.length() - 1);
return localeName;
}
-String defaultLanguage()
+String platformDefaultLanguage()
{
static String computedDefaultLanguage;
if (!computedDefaultLanguage.isEmpty())
@@ -60,7 +60,7 @@ String defaultLanguage()
if (countryName.isEmpty())
computedDefaultLanguage = languageName;
else
- computedDefaultLanguage = String::format("%s-%s", languageName.latin1().data(), countryName.latin1().data());
+ computedDefaultLanguage = makeString(languageName, '-', countryName);
return computedDefaultLanguage;
}
diff --git a/WebCore/platform/win/PlatformScreenWin.cpp b/WebCore/platform/win/PlatformScreenWin.cpp
index 4af9e17..21fa10d 100644
--- a/WebCore/platform/win/PlatformScreenWin.cpp
+++ b/WebCore/platform/win/PlatformScreenWin.cpp
@@ -68,14 +68,18 @@ static DEVMODE deviceInfoForWidget(Widget* widget)
int screenDepth(Widget* widget)
{
DEVMODE deviceInfo = deviceInfoForWidget(widget);
+ if (deviceInfo.dmBitsPerPel == 32) {
+ // Some video drivers return 32, but this function is supposed to ignore the alpha
+ // component. See <http://webkit.org/b/42972>.
+ return 24;
+ }
return deviceInfo.dmBitsPerPel;
}
int screenDepthPerComponent(Widget* widget)
{
// FIXME: Assumes RGB -- not sure if this is right.
- DEVMODE deviceInfo = deviceInfoForWidget(widget);
- return deviceInfo.dmBitsPerPel / 3;
+ return screenDepth(widget) / 3;
}
bool screenIsMonochrome(Widget* widget)
diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp
index a782b03..e86aef9 100644
--- a/WebCore/platform/win/PopupMenuWin.cpp
+++ b/WebCore/platform/win/PopupMenuWin.cpp
@@ -619,11 +619,11 @@ void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc)
// Draw the background for this menu item
if (itemStyle.isVisible())
- context.fillRect(itemRect, optionBackgroundColor, DeviceColorSpace);
+ context.fillRect(itemRect, optionBackgroundColor, ColorSpaceDeviceRGB);
if (client()->itemIsSeparator(index)) {
IntRect separatorRect(itemRect.x() + separatorPadding, itemRect.y() + (itemRect.height() - separatorHeight) / 2, itemRect.width() - 2 * separatorPadding, separatorHeight);
- context.fillRect(separatorRect, optionTextColor, DeviceColorSpace);
+ context.fillRect(separatorRect, optionTextColor, ColorSpaceDeviceRGB);
continue;
}
@@ -633,7 +633,7 @@ void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc)
const UChar* string = itemText.characters();
TextRun textRun(string, length, false, 0, 0, itemText.defaultWritingDirection() == WTF::Unicode::RightToLeft);
- context.setFillColor(optionTextColor, DeviceColorSpace);
+ context.setFillColor(optionTextColor, ColorSpaceDeviceRGB);
Font itemFont = client()->menuStyle().font();
if (client()->itemIsLabel(index)) {
diff --git a/WebCore/platform/win/WebCoreTextRenderer.cpp b/WebCore/platform/win/WebCoreTextRenderer.cpp
index f771e00..a32fa4f 100644
--- a/WebCore/platform/win/WebCoreTextRenderer.cpp
+++ b/WebCore/platform/win/WebCoreTextRenderer.cpp
@@ -49,7 +49,7 @@ static void doDrawTextAtPoint(GraphicsContext& context, const String& text, cons
{
TextRun run(text.characters(), text.length());
- context.setFillColor(color, DeviceColorSpace);
+ context.setFillColor(color, ColorSpaceDeviceRGB);
if (isOneLeftToRightRun(run))
font.drawText(&context, run, point);
else
@@ -71,7 +71,7 @@ static void doDrawTextAtPoint(GraphicsContext& context, const String& text, cons
IntPoint underlinePoint(point);
underlinePoint.move(beforeWidth, 1);
- context.setStrokeColor(color, DeviceColorSpace);
+ context.setStrokeColor(color, ColorSpaceDeviceRGB);
context.drawLineForText(underlinePoint, underlinedWidth, false);
}
}
diff --git a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp
index 82259f4..56a5d07 100644
--- a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp
+++ b/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp
@@ -48,7 +48,7 @@ void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData*
wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
wxFont* wxfont = font->getWxFont();
- graphicsContext->setFillColor(graphicsContext->fillColor(), DeviceColorSpace);
+ graphicsContext->setFillColor(graphicsContext->fillColor(), ColorSpaceDeviceRGB);
CGContextRef cgContext = static_cast<CGContextRef>(dc->GetGraphicsContext()->GetNativeContext());