summaryrefslogtreecommitdiffstats
path: root/WebCore/platform
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform')
-rw-r--r--WebCore/platform/ContentType.cpp73
-rw-r--r--WebCore/platform/ContentType.h (renamed from WebCore/platform/text/TextDecoder.h)41
-rw-r--r--WebCore/platform/ContextMenu.cpp14
-rw-r--r--WebCore/platform/CrossThreadCopier.cpp62
-rw-r--r--WebCore/platform/CrossThreadCopier.h109
-rw-r--r--WebCore/platform/FileSystem.h6
-rw-r--r--WebCore/platform/GeolocationService.cpp4
-rw-r--r--WebCore/platform/GeolocationService.h12
-rw-r--r--WebCore/platform/KURL.cpp37
-rw-r--r--WebCore/platform/KURL.h24
-rw-r--r--WebCore/platform/KURLGoogle.cpp944
-rw-r--r--WebCore/platform/KURLGooglePrivate.h115
-rw-r--r--WebCore/platform/MIMETypeRegistry.h1
-rw-r--r--WebCore/platform/PlatformWheelEvent.h35
-rw-r--r--WebCore/platform/PopupMenuStyle.h10
-rw-r--r--WebCore/platform/RunLoopTimer.h79
-rw-r--r--WebCore/platform/ScrollView.cpp12
-rw-r--r--WebCore/platform/Scrollbar.h3
-rw-r--r--WebCore/platform/SharedTimer.h43
-rw-r--r--WebCore/platform/ThreadCheck.h14
-rw-r--r--WebCore/platform/ThreadGlobalData.cpp3
-rw-r--r--WebCore/platform/ThreadGlobalData.h3
-rw-r--r--WebCore/platform/ThreadTimers.cpp158
-rw-r--r--WebCore/platform/ThreadTimers.h69
-rw-r--r--WebCore/platform/Timer.cpp165
-rw-r--r--WebCore/platform/Timer.h17
-rw-r--r--WebCore/platform/Widget.h3
-rw-r--r--WebCore/platform/android/FileChooserAndroid.cpp3
-rw-r--r--WebCore/platform/android/FileSystemAndroid.cpp41
-rw-r--r--WebCore/platform/android/KeyEventAndroid.cpp18
-rw-r--r--WebCore/platform/android/LocalizedStringsAndroid.cpp258
-rw-r--r--WebCore/platform/android/PopupMenuAndroid.cpp1
-rw-r--r--WebCore/platform/android/RenderThemeAndroid.cpp168
-rw-r--r--WebCore/platform/android/RenderThemeAndroid.h44
-rw-r--r--WebCore/platform/android/ScrollViewAndroid.cpp14
-rw-r--r--WebCore/platform/android/SystemTimeAndroid.cpp2
-rw-r--r--WebCore/platform/android/TemporaryLinkStubs.cpp344
-rw-r--r--WebCore/platform/android/TextBoundaries.cpp78
-rw-r--r--WebCore/platform/android/WidgetAndroid.cpp10
-rw-r--r--WebCore/platform/animation/Animation.cpp39
-rw-r--r--WebCore/platform/animation/Animation.h25
-rw-r--r--WebCore/platform/cf/RunLoopTimerCF.cpp84
-rw-r--r--WebCore/platform/chromium/ChromiumBridge.h18
-rw-r--r--WebCore/platform/chromium/ChromiumDataObject.cpp2
-rw-r--r--WebCore/platform/chromium/ChromiumDataObject.h1
-rw-r--r--WebCore/platform/chromium/ClipboardChromium.cpp12
-rw-r--r--WebCore/platform/chromium/ClipboardChromium.h6
-rw-r--r--WebCore/platform/chromium/ClipboardChromiumLinux.cpp41
-rw-r--r--WebCore/platform/chromium/ClipboardChromiumMac.cpp41
-rw-r--r--WebCore/platform/chromium/ClipboardChromiumWin.cpp56
-rw-r--r--WebCore/platform/chromium/MimeTypeRegistryChromium.cpp9
-rw-r--r--WebCore/platform/chromium/PasteboardChromium.cpp19
-rw-r--r--WebCore/platform/chromium/PlatformKeyboardEventChromium.cpp4
-rw-r--r--WebCore/platform/chromium/PlatformWidget.h4
-rw-r--r--WebCore/platform/chromium/PopupMenuChromium.cpp156
-rw-r--r--WebCore/platform/chromium/PopupMenuChromium.h50
-rw-r--r--WebCore/platform/chromium/ScrollbarThemeChromium.cpp14
-rw-r--r--WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp154
-rw-r--r--WebCore/platform/chromium/TemporaryLinkStubs.cpp8
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp1
-rw-r--r--WebCore/platform/graphics/BitmapImage.h14
-rw-r--r--WebCore/platform/graphics/Color.cpp39
-rw-r--r--WebCore/platform/graphics/Color.h7
-rw-r--r--WebCore/platform/graphics/FloatPoint.cpp2
-rw-r--r--WebCore/platform/graphics/FloatPoint.h4
-rw-r--r--WebCore/platform/graphics/FloatPoint3D.cpp2
-rw-r--r--WebCore/platform/graphics/FloatPoint3D.h4
-rw-r--r--WebCore/platform/graphics/FloatRect.h4
-rw-r--r--WebCore/platform/graphics/FontCache.cpp26
-rw-r--r--WebCore/platform/graphics/GlyphBuffer.h2
-rw-r--r--WebCore/platform/graphics/GlyphPageTreeNode.cpp1
-rw-r--r--WebCore/platform/graphics/GlyphWidthMap.cpp37
-rw-r--r--WebCore/platform/graphics/GlyphWidthMap.h43
-rw-r--r--WebCore/platform/graphics/Gradient.cpp8
-rw-r--r--WebCore/platform/graphics/Gradient.h10
-rw-r--r--WebCore/platform/graphics/GraphicsContext.cpp40
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h39
-rw-r--r--WebCore/platform/graphics/GraphicsContextPrivate.h13
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.cpp545
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.h407
-rw-r--r--WebCore/platform/graphics/GraphicsLayerClient.h69
-rw-r--r--WebCore/platform/graphics/GraphicsTypes.h8
-rw-r--r--WebCore/platform/graphics/Image.cpp4
-rw-r--r--WebCore/platform/graphics/Image.h10
-rw-r--r--WebCore/platform/graphics/IntPoint.h4
-rw-r--r--WebCore/platform/graphics/IntRect.h4
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp254
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h88
-rw-r--r--WebCore/platform/graphics/MediaPlayerPrivate.h94
-rw-r--r--WebCore/platform/graphics/Pattern.h6
-rw-r--r--WebCore/platform/graphics/SimpleFontData.cpp14
-rw-r--r--WebCore/platform/graphics/SimpleFontData.h17
-rw-r--r--WebCore/platform/graphics/android/FontPlatformData.h3
-rw-r--r--WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp7
-rw-r--r--WebCore/platform/graphics/android/GradientAndroid.cpp48
-rw-r--r--WebCore/platform/graphics/android/GraphicsContextAndroid.cpp131
-rw-r--r--WebCore/platform/graphics/android/ImageAndroid.cpp100
-rw-r--r--WebCore/platform/graphics/android/ImageSourceAndroid.cpp6
-rw-r--r--WebCore/platform/graphics/android/PathAndroid.cpp107
-rw-r--r--WebCore/platform/graphics/android/PatternAndroid.cpp5
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.cpp7
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.h4
-rw-r--r--WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp232
-rw-r--r--WebCore/platform/graphics/android/android_graphics.cpp194
-rw-r--r--WebCore/platform/graphics/android/android_graphics.h41
-rw-r--r--WebCore/platform/graphics/cairo/FontCairo.cpp53
-rw-r--r--WebCore/platform/graphics/cairo/GradientCairo.cpp16
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp24
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h2
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferCairo.cpp32
-rw-r--r--WebCore/platform/graphics/cairo/ImageCairo.cpp27
-rw-r--r--WebCore/platform/graphics/cairo/ImageSourceCairo.cpp2
-rw-r--r--WebCore/platform/graphics/cairo/PatternCairo.cpp13
-rw-r--r--WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp248
-rw-r--r--WebCore/platform/graphics/cg/ColorCG.cpp6
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp8
-rw-r--r--WebCore/platform/graphics/cg/ImageCG.cpp2
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.cpp2
-rw-r--r--WebCore/platform/graphics/cg/PatternCG.cpp7
-rw-r--r--WebCore/platform/graphics/cg/TransformationMatrixCG.cpp184
-rw-r--r--WebCore/platform/graphics/chromium/ColorChromium.cpp30
-rw-r--r--WebCore/platform/graphics/chromium/ColorChromiumMac.mm132
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp47
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheLinux.cpp10
-rw-r--r--WebCore/platform/graphics/chromium/FontChromiumWin.cpp427
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp6
-rw-r--r--WebCore/platform/graphics/chromium/FontLinux.cpp42
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp2
-rw-r--r--WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp15
-rw-r--r--WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h17
-rw-r--r--WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp104
-rw-r--r--WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h98
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.cpp480
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.h252
-rw-r--r--WebCore/platform/graphics/chromium/UniscribeHelper.cpp83
-rw-r--r--WebCore/platform/graphics/chromium/UniscribeHelper.h16
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformData.h2
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp54
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp59
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp113
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h48
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp27
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp25
-rw-r--r--WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp25
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.mm3
-rw-r--r--WebCore/platform/graphics/mac/FontCacheMac.mm13
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.cpp17
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.h1
-rw-r--r--WebCore/platform/graphics/mac/FontMac.mm1
-rw-r--r--WebCore/platform/graphics/mac/FontMacATSUI.mm1
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformData.h18
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformDataMac.mm23
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContextMac.mm5
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.h138
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm1540
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h58
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm253
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerProxy.h118
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm1
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.h57
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.mm219
-rw-r--r--WebCore/platform/graphics/mac/WebTiledLayer.h45
-rw-r--r--WebCore/platform/graphics/mac/WebTiledLayer.mm111
-rw-r--r--WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp (renamed from WebCore/platform/graphics/win/OpenTypeUtilities.cpp)25
-rw-r--r--WebCore/platform/graphics/opentype/OpenTypeUtilities.h (renamed from WebCore/platform/graphics/win/OpenTypeUtilities.h)2
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformDataQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp81
-rw-r--r--WebCore/platform/graphics/qt/GradientQt.cpp17
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp138
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferQt.cpp107
-rw-r--r--WebCore/platform/graphics/qt/ImageQt.cpp58
-rw-r--r--WebCore/platform/graphics/qt/ImageSourceQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp58
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h43
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp80
-rw-r--r--WebCore/platform/graphics/qt/PatternQt.cpp5
-rw-r--r--WebCore/platform/graphics/qt/TransformationMatrixQt.cpp167
-rw-r--r--WebCore/platform/graphics/skia/GradientSkia.cpp20
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContextSkia.cpp53
-rw-r--r--WebCore/platform/graphics/skia/ImageBufferSkia.cpp23
-rw-r--r--WebCore/platform/graphics/skia/ImageSkia.cpp8
-rw-r--r--WebCore/platform/graphics/skia/ImageSourceSkia.cpp14
-rw-r--r--WebCore/platform/graphics/skia/PathSkia.cpp2
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.cpp165
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.h47
-rw-r--r--WebCore/platform/graphics/skia/SkiaFontWin.cpp155
-rw-r--r--WebCore/platform/graphics/skia/SkiaFontWin.h35
-rw-r--r--WebCore/platform/graphics/skia/SkiaUtils.cpp31
-rw-r--r--WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp189
-rw-r--r--WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp56
-rw-r--r--WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h72
-rw-r--r--WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp4
-rw-r--r--WebCore/platform/graphics/transforms/MatrixTransformOperation.h19
-rw-r--r--WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp58
-rw-r--r--WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h71
-rw-r--r--WebCore/platform/graphics/transforms/RotateTransformOperation.cpp61
-rw-r--r--WebCore/platform/graphics/transforms/RotateTransformOperation.h29
-rw-r--r--WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp9
-rw-r--r--WebCore/platform/graphics/transforms/ScaleTransformOperation.h23
-rw-r--r--WebCore/platform/graphics/transforms/TransformOperation.h26
-rw-r--r--WebCore/platform/graphics/transforms/TransformOperations.h10
-rw-r--r--WebCore/platform/graphics/transforms/TransformationMatrix.cpp1065
-rw-r--r--WebCore/platform/graphics/transforms/TransformationMatrix.h285
-rw-r--r--WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp7
-rw-r--r--WebCore/platform/graphics/transforms/TranslateTransformOperation.h25
-rw-r--r--WebCore/platform/graphics/win/FontCGWin.cpp55
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp19
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.cpp14
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp2
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp14
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp2
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp12
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp147
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h27
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.cpp6
-rw-r--r--WebCore/platform/graphics/win/QTMovieWinTimer.cpp26
-rw-r--r--[-rwxr-xr-x]WebCore/platform/graphics/wx/FontCacheWx.cpp0
-rw-r--r--WebCore/platform/graphics/wx/FontPlatformData.h64
-rw-r--r--[-rwxr-xr-x]WebCore/platform/graphics/wx/FontPlatformDataWx.cpp30
-rw-r--r--[-rwxr-xr-x]WebCore/platform/graphics/wx/GlyphMapWx.cpp0
-rw-r--r--WebCore/platform/graphics/wx/ImageSourceWx.cpp2
-rw-r--r--WebCore/platform/graphics/wx/ImageWx.cpp2
-rw-r--r--[-rwxr-xr-x]WebCore/platform/graphics/wx/SimpleFontDataWx.cpp24
-rw-r--r--WebCore/platform/graphics/wx/TransformationMatrixWx.cpp231
-rw-r--r--WebCore/platform/gtk/ContextMenuGtk.cpp5
-rw-r--r--WebCore/platform/gtk/ContextMenuItemGtk.cpp5
-rw-r--r--WebCore/platform/gtk/FileSystemGtk.cpp2
-rw-r--r--WebCore/platform/gtk/GeolocationServiceGtk.cpp162
-rw-r--r--WebCore/platform/gtk/GeolocationServiceGtk.h30
-rw-r--r--WebCore/platform/gtk/LoggingGtk.cpp86
-rw-r--r--WebCore/platform/gtk/PopupMenuGtk.cpp5
-rw-r--r--WebCore/platform/gtk/ScrollViewGtk.cpp4
-rw-r--r--WebCore/platform/gtk/ScrollbarGtk.cpp76
-rw-r--r--WebCore/platform/gtk/ScrollbarGtk.h4
-rw-r--r--WebCore/platform/gtk/WheelEventGtk.cpp17
-rw-r--r--WebCore/platform/gtk/WidgetGtk.cpp61
-rw-r--r--WebCore/platform/image-decoders/ImageDecoder.h9
-rw-r--r--WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp48
-rw-r--r--WebCore/platform/image-decoders/skia/ImageDecoder.h7
-rw-r--r--WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp172
-rw-r--r--WebCore/platform/image-encoders/skia/PNGImageEncoder.h55
-rw-r--r--WebCore/platform/mac/FoundationExtras.h3
-rw-r--r--WebCore/platform/mac/GeolocationServiceMac.h75
-rw-r--r--WebCore/platform/mac/GeolocationServiceMac.mm209
-rw-r--r--WebCore/platform/mac/LocalCurrentGraphicsContext.h4
-rw-r--r--WebCore/platform/mac/PasteboardMac.mm12
-rw-r--r--WebCore/platform/mac/PlatformScreenMac.mm6
-rw-r--r--WebCore/platform/mac/SharedBufferMac.mm10
-rw-r--r--WebCore/platform/mac/ThreadCheck.mm62
-rw-r--r--WebCore/platform/mac/WebCoreSystemInterface.h9
-rw-r--r--WebCore/platform/mac/WebCoreSystemInterface.mm1
-rw-r--r--WebCore/platform/mac/WebCoreTextRenderer.h9
-rw-r--r--WebCore/platform/mac/WebCoreTextRenderer.mm1
-rw-r--r--WebCore/platform/mac/WebFontCache.h3
-rw-r--r--WebCore/platform/mac/WebFontCache.mm2
-rw-r--r--WebCore/platform/mac/WheelEventMac.mm14
-rw-r--r--WebCore/platform/network/FormData.cpp6
-rw-r--r--WebCore/platform/network/FormData.h8
-rw-r--r--WebCore/platform/network/HTTPHeaderMap.cpp2
-rw-r--r--WebCore/platform/network/HTTPParsers.cpp9
-rw-r--r--WebCore/platform/network/ResourceErrorBase.cpp17
-rw-r--r--WebCore/platform/network/ResourceErrorBase.h7
-rw-r--r--WebCore/platform/network/ResourceHandle.h12
-rw-r--r--WebCore/platform/network/ResourceHandleClient.h6
-rw-r--r--WebCore/platform/network/ResourceHandleInternal.h13
-rw-r--r--WebCore/platform/network/ResourceRequestBase.cpp23
-rw-r--r--WebCore/platform/network/ResourceRequestBase.h12
-rw-r--r--WebCore/platform/network/ResourceResponseBase.cpp4
-rw-r--r--WebCore/platform/network/ResourceResponseBase.h9
-rw-r--r--WebCore/platform/network/android/ResourceHandleAndroid.cpp6
-rw-r--r--WebCore/platform/network/cf/FormDataStreamCFNet.cpp88
-rw-r--r--WebCore/platform/network/cf/ResourceHandleCFNet.cpp93
-rw-r--r--WebCore/platform/network/cf/ResourceRequestCFNet.h2
-rw-r--r--WebCore/platform/network/cf/ResourceResponse.h12
-rw-r--r--WebCore/platform/network/chromium/ResourceRequest.h53
-rw-r--r--WebCore/platform/network/curl/ResourceHandleManager.cpp4
-rw-r--r--WebCore/platform/network/mac/FormDataStreamMac.mm2
-rw-r--r--WebCore/platform/network/mac/ResourceErrorMac.mm7
-rw-r--r--WebCore/platform/network/mac/ResourceRequestMac.mm4
-rw-r--r--WebCore/platform/network/mac/ResourceResponse.h12
-rw-r--r--WebCore/platform/network/qt/QNetworkReplyHandler.cpp4
-rw-r--r--WebCore/platform/network/soup/CookieJarSoup.cpp33
-rw-r--r--WebCore/platform/network/soup/CookieJarSoup.h3
-rw-r--r--WebCore/platform/network/soup/ResourceHandleSoup.cpp497
-rw-r--r--WebCore/platform/network/win/CookieJarCFNetWin.cpp24
-rw-r--r--WebCore/platform/qt/CookieJarQt.cpp2
-rw-r--r--WebCore/platform/qt/FileSystemQt.cpp28
-rw-r--r--WebCore/platform/qt/KURLQt.cpp3
-rw-r--r--WebCore/platform/qt/PlatformKeyboardEventQt.cpp49
-rw-r--r--WebCore/platform/qt/QWebPopup.cpp14
-rw-r--r--WebCore/platform/qt/RenderThemeQt.cpp4
-rw-r--r--WebCore/platform/qt/RenderThemeQt.h2
-rw-r--r--WebCore/platform/qt/WheelEventQt.cpp16
-rw-r--r--WebCore/platform/text/AtomicString.cpp2
-rw-r--r--WebCore/platform/text/Base64.cpp6
-rw-r--r--WebCore/platform/text/BidiResolver.h19
-rw-r--r--WebCore/platform/text/CString.cpp25
-rw-r--r--WebCore/platform/text/CString.h17
-rw-r--r--WebCore/platform/text/PlatformString.h12
-rw-r--r--WebCore/platform/text/String.cpp9
-rw-r--r--WebCore/platform/text/StringImpl.cpp87
-rw-r--r--WebCore/platform/text/StringImpl.h40
-rw-r--r--WebCore/platform/text/TextBreakIterator.h12
-rw-r--r--WebCore/platform/text/TextBreakIteratorICU.cpp116
-rw-r--r--WebCore/platform/text/TextCodecICU.cpp2
-rw-r--r--WebCore/platform/text/TextDecoder.cpp129
-rw-r--r--WebCore/platform/text/TextEncoding.cpp26
-rw-r--r--WebCore/platform/text/TextEncoding.h11
-rw-r--r--WebCore/platform/text/TextEncodingDetector.h48
-rw-r--r--WebCore/platform/text/TextEncodingDetectorICU.cpp129
-rw-r--r--WebCore/platform/text/TextEncodingDetectorNone.cpp51
-rw-r--r--WebCore/platform/text/TextEncodingRegistry.h7
-rw-r--r--WebCore/platform/text/android/TextBreakIteratorInternalICU.cpp (renamed from WebCore/platform/android/TextBreakIteratorInternalICU.cpp)0
-rw-r--r--WebCore/platform/text/cf/StringImplCF.cpp131
-rw-r--r--WebCore/platform/text/mac/ShapeArabic.c2
-rw-r--r--WebCore/platform/text/mac/StringImplMac.mm8
-rw-r--r--WebCore/platform/text/mac/StringMac.mm1
-rw-r--r--WebCore/platform/text/qt/TextBreakIteratorQt.cpp10
-rw-r--r--WebCore/platform/win/FileSystemWin.cpp6
-rw-r--r--WebCore/platform/win/PopupMenuWin.cpp5
-rw-r--r--WebCore/platform/win/WheelEventWin.cpp55
-rw-r--r--WebCore/platform/wx/MouseWheelEventWx.cpp7
-rw-r--r--[-rwxr-xr-x]WebCore/platform/wx/TemporaryLinkStubs.cpp0
-rw-r--r--[-rwxr-xr-x]WebCore/platform/wx/WidgetWx.cpp0
-rw-r--r--WebCore/platform/wx/wxcode/fontprops.h3
-rw-r--r--WebCore/platform/wx/wxcode/gtk/fontprops.cpp71
-rw-r--r--WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp185
-rw-r--r--WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp11
-rw-r--r--WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp7
-rw-r--r--WebCore/platform/wx/wxcode/non-kerned-drawing.h21
-rw-r--r--WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp4
331 files changed, 14382 insertions, 5022 deletions
diff --git a/WebCore/platform/ContentType.cpp b/WebCore/platform/ContentType.cpp
new file mode 100644
index 0000000..3dce7b5
--- /dev/null
+++ b/WebCore/platform/ContentType.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this 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 "ContentType.h"
+
+namespace WebCore {
+
+ContentType::ContentType(const String& contentType)
+ : m_type(contentType)
+{
+}
+
+String ContentType::parameter(const String& parameterName) const
+{
+ String parameterValue;
+ String strippedType = m_type.stripWhiteSpace();
+
+ // a MIME type can have one or more "param=value" after a semi-colon, and separated from each other by semi-colons
+ int semi = strippedType.find(';');
+ if (semi != -1) {
+ int start = strippedType.find(parameterName, semi + 1, false);
+ if (start != -1) {
+ start = strippedType.find('=', start + 6);
+ if (start != -1) {
+ int end = strippedType.find(';', start + 6);
+ if (end == -1)
+ end = strippedType.length();
+ parameterValue = strippedType.substring(start + 1, end - (start + 1)).stripWhiteSpace();
+ }
+ }
+ }
+
+ return parameterValue;
+}
+
+String ContentType::type() const
+{
+ String strippedType = m_type.stripWhiteSpace();
+
+ // "type" can have parameters after a semi-colon, strip them
+ int semi = strippedType.find(';');
+ if (semi != -1)
+ strippedType = strippedType.left(semi).stripWhiteSpace();
+
+ return strippedType;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/text/TextDecoder.h b/WebCore/platform/ContentType.h
index 171cb59..bf8fc4c 100644
--- a/WebCore/platform/text/TextDecoder.h
+++ b/WebCore/platform/ContentType.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -20,45 +21,27 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextDecoder_h
-#define TextDecoder_h
+#ifndef ContentType_h
+#define ContentType_h
#include "PlatformString.h"
-#include "TextCodec.h"
-#include "TextEncoding.h"
-#include <wtf/OwnPtr.h>
namespace WebCore {
- class TextCodec;
-
- class TextDecoder {
+ class ContentType {
public:
- TextDecoder(const TextEncoding&);
- void reset(const TextEncoding&);
- const TextEncoding& encoding() const { return m_encoding; };
-
- String decode(const char* data, size_t length, bool flush, bool stopOnError, bool& sawError)
- {
- if (!m_checkedForBOM)
- return checkForBOM(data, length, flush, stopOnError, sawError);
- return m_codec->decode(data, length, flush, stopOnError, sawError);
- }
+ ContentType(const String& type);
+ String parameter (const String& parameterName) const;
+ String type() const;
+ const String& raw() const { return m_type; }
private:
- String checkForBOM(const char*, size_t length, bool flush, bool stopOnError, bool& sawError);
-
- TextEncoding m_encoding;
- OwnPtr<TextCodec> m_codec;
-
- bool m_checkedForBOM;
- unsigned char m_numBufferedBytes;
- unsigned char m_bufferedBytes[3];
+ String m_type;
};
} // namespace WebCore
-#endif // TextDecoder_h
+#endif // ContentType_h
diff --git a/WebCore/platform/ContextMenu.cpp b/WebCore/platform/ContextMenu.cpp
index f086b63..f66a891 100644
--- a/WebCore/platform/ContextMenu.cpp
+++ b/WebCore/platform/ContextMenu.cpp
@@ -192,7 +192,7 @@ static void createAndAppendTextDirectionSubMenu(const HitTestResult& result, Con
static bool selectionContainsPossibleWord(Frame* frame)
{
// Current algorithm: look for a character that's not just a separator.
- for (TextIterator it(frame->selection()->toRange().get()); !it.atEnd(); it.advance()) {
+ for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) {
int length = it.length();
const UChar* characters = it.characters();
for (int i = 0; i < length; ++i)
@@ -252,7 +252,7 @@ void ContextMenu::populate()
if (!node)
return;
#if PLATFORM(GTK)
- if (!result.isContentEditable() && node->isControl())
+ if (!result.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()))
return;
#endif
Frame* frame = node->document()->frame();
@@ -328,12 +328,10 @@ void ContextMenu::populate()
if (!inPasswordField) {
// Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range
// is never considered a misspelling and bad grammar at the same time)
- bool misspelling = frame->editor()->isSelectionMisspelled();
- bool badGrammar = !misspelling && (frame->editor()->isGrammarCheckingEnabled() && frame->editor()->isSelectionUngrammatical());
-
+ bool misspelling;
+ bool badGrammar;
+ Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar);
if (misspelling || badGrammar) {
- Vector<String> guesses = misspelling ? frame->editor()->guessesForMisspelledSelection()
- : frame->editor()->guessesForUngrammaticalSelection();
size_t size = guesses.size();
if (size == 0) {
// If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions
@@ -427,7 +425,7 @@ void ContextMenu::populate()
if (Page* page = frame->page()) {
if (Settings* settings = page->settings()) {
bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded
- || settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection();
+ || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection());
if (includeTextDirectionSubmenu) {
ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu,
contextMenuItemTagTextDirectionMenu());
diff --git a/WebCore/platform/CrossThreadCopier.cpp b/WebCore/platform/CrossThreadCopier.cpp
new file mode 100644
index 0000000..9ca626f
--- /dev/null
+++ b/WebCore/platform/CrossThreadCopier.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "CrossThreadCopier.h"
+
+#include "PlatformString.h"
+#include "ResourceError.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+
+namespace WebCore {
+
+CrossThreadCopierBase<false, String>::Type CrossThreadCopierBase<false, String>::copy(const String& str)
+{
+ return str.copy();
+}
+
+CrossThreadCopierBase<false, ResourceError>::Type CrossThreadCopierBase<false, ResourceError>::copy(const ResourceError& error)
+{
+ return error.copy();
+}
+
+CrossThreadCopierBase<false, ResourceRequest>::Type CrossThreadCopierBase<false, ResourceRequest>::copy(const ResourceRequest& request)
+{
+ return request.copyData();
+}
+
+CrossThreadCopierBase<false, ResourceResponse>::Type CrossThreadCopierBase<false, ResourceResponse>::copy(const ResourceResponse& response)
+{
+ return response.copyData();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/CrossThreadCopier.h b/WebCore/platform/CrossThreadCopier.h
new file mode 100644
index 0000000..e7b4c0e
--- /dev/null
+++ b/WebCore/platform/CrossThreadCopier.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CrossThreadCopier_h
+#define CrossThreadCopier_h
+
+#include <memory>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Threading.h>
+#include <wtf/TypeTraits.h>
+
+namespace WebCore {
+
+ class ResourceError;
+ struct ResourceRequest;
+ class ResourceResponse;
+ class String;
+ struct CrossThreadResourceResponseData;
+ struct CrossThreadResourceRequestData;
+
+ template<typename T> struct CrossThreadCopierPassThrough {
+ typedef T Type;
+ static Type copy(const T& parameter)
+ {
+ return parameter;
+ }
+ };
+
+ template<bool isConvertibleToInteger, typename T> struct CrossThreadCopierBase;
+
+ // Integers get passed through without any changes.
+ template<typename T> struct CrossThreadCopierBase<true, T> : public CrossThreadCopierPassThrough<T> {
+ };
+
+ // Pointers get passed through without any significant changes.
+ template<typename T> struct CrossThreadCopierBase<false, T*> : public CrossThreadCopierPassThrough<T*> {
+ };
+
+ // Custom copy methods.
+ template<typename T> struct CrossThreadCopierBase<false, RefPtr<ThreadSafeShared<T> > > {
+ typedef PassRefPtr<T> Type;
+ static Type copy(const RefPtr<ThreadSafeShared<T> >& refPtr)
+ {
+ return PassRefPtr<T>(static_cast<T*>(refPtr.get()));
+ }
+ };
+
+ template<typename T> struct CrossThreadCopierBase<false, std::auto_ptr<T> > {
+ typedef std::auto_ptr<T> Type;
+ static Type copy(const std::auto_ptr<T>& autoPtr)
+ {
+ return std::auto_ptr<T>(*const_cast<std::auto_ptr<T>*>(&autoPtr));
+ }
+ };
+
+ template<> struct CrossThreadCopierBase<false, String> {
+ typedef String Type;
+ static Type copy(const String&);
+ };
+
+ template<> struct CrossThreadCopierBase<false, ResourceError> {
+ typedef ResourceError Type;
+ static Type copy(const ResourceError&);
+ };
+
+ template<> struct CrossThreadCopierBase<false, ResourceRequest> {
+ typedef std::auto_ptr<CrossThreadResourceRequestData> Type;
+ static Type copy(const ResourceRequest&);
+ };
+
+ template<> struct CrossThreadCopierBase<false, ResourceResponse> {
+ typedef std::auto_ptr<CrossThreadResourceResponseData> Type;
+ static Type copy(const ResourceResponse&);
+ };
+
+ template<typename T> struct CrossThreadCopier : public CrossThreadCopierBase<WTF::IsConvertibleToInteger<T>::value, T> {
+ };
+
+} // namespace WebCore
+
+#endif // CrossThreadCopier_h
diff --git a/WebCore/platform/FileSystem.h b/WebCore/platform/FileSystem.h
index 66dbc20..8ccefab 100644
--- a/WebCore/platform/FileSystem.h
+++ b/WebCore/platform/FileSystem.h
@@ -97,9 +97,6 @@ const PlatformFileHandle invalidPlatformFileHandle = 0;
#if defined(Q_WS_MAC)
typedef CFBundleRef PlatformModule;
typedef unsigned PlatformModuleVersion;
-#elif defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60)
-typedef QLibrary* PlatformModule;
-typedef unsigned PlatformModuleVersion;
#elif defined(Q_OS_WIN)
typedef HMODULE PlatformModule;
struct PlatformModuleVersion {
@@ -119,6 +116,9 @@ struct PlatformModuleVersion {
}
};
+#else
+typedef QLibrary* PlatformModule;
+typedef unsigned PlatformModuleVersion;
#endif
#else
diff --git a/WebCore/platform/GeolocationService.cpp b/WebCore/platform/GeolocationService.cpp
index dfd5a5c..9b362c8 100644
--- a/WebCore/platform/GeolocationService.cpp
+++ b/WebCore/platform/GeolocationService.cpp
@@ -26,9 +26,7 @@
#include "config.h"
#include "GeolocationService.h"
-#include "Geoposition.h"
-#include "PositionError.h"
-#include "PositionOptions.h"
+#include <wtf/Assertions.h>
namespace WebCore {
diff --git a/WebCore/platform/GeolocationService.h b/WebCore/platform/GeolocationService.h
index 90d52eb..74a6ead 100644
--- a/WebCore/platform/GeolocationService.h
+++ b/WebCore/platform/GeolocationService.h
@@ -38,21 +38,21 @@ class PositionOptions;
class GeolocationServiceClient {
public:
virtual ~GeolocationServiceClient() { }
- virtual void geolocationServicePositionChanged(GeolocationService*) { }
- virtual void geolocationServiceErrorOccurred(GeolocationService*) { }
+ virtual void geolocationServicePositionChanged(GeolocationService*) = 0;
+ virtual void geolocationServiceErrorOccurred(GeolocationService*) = 0;
};
class GeolocationService : public Noncopyable {
public:
static GeolocationService* create(GeolocationServiceClient*);
- virtual ~GeolocationService() {}
+ virtual ~GeolocationService() { }
virtual bool startUpdating(PositionOptions*) { return false; }
- virtual void stopUpdating() {}
+ virtual void stopUpdating() { }
virtual void suspend() { }
virtual void resume() { }
-
+
virtual Geoposition* lastPosition() const { return 0; }
virtual PositionError* lastError() const { return 0; }
@@ -65,7 +65,7 @@ protected:
private:
GeolocationServiceClient* m_geolocationServiceClient;
};
-
+
} // namespace WebCore
#endif // GeolocationService_h
diff --git a/WebCore/platform/KURL.cpp b/WebCore/platform/KURL.cpp
index 6fcb9b9..6901782 100644
--- a/WebCore/platform/KURL.cpp
+++ b/WebCore/platform/KURL.cpp
@@ -289,6 +289,7 @@ inline bool KURL::protocolIs(const String& string, const char* protocol)
void KURL::invalidate()
{
m_isValid = false;
+ m_protocolInHTTPFamily = false;
m_schemeEnd = 0;
m_userStart = 0;
m_userEnd = 0;
@@ -604,6 +605,11 @@ bool KURL::hasRef() const
return m_fragmentEnd != m_queryEnd;
}
+String KURL::baseAsString() const
+{
+ return m_string.left(m_pathAfterLastSlash);
+}
+
#ifdef NDEBUG
static inline void assertProtocolIsGood(const char*)
@@ -638,7 +644,10 @@ bool KURL::protocolIs(const char* protocol) const
String KURL::query() const
{
- return m_string.substring(m_pathEnd, m_queryEnd - m_pathEnd);
+ if (m_queryEnd == m_pathEnd)
+ return String();
+
+ return m_string.substring(m_pathEnd + 1, m_queryEnd - (m_pathEnd + 1));
}
String KURL::path() const
@@ -677,13 +686,13 @@ void KURL::setPort(unsigned short i)
if (!m_isValid)
return;
- // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
- // and to avoid changing more than just the port.
-
- bool colonNeeded = m_portEnd == m_hostEnd;
- int portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1);
+ if (i) {
+ bool colonNeeded = m_portEnd == m_hostEnd;
+ int portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1);
- parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(m_portEnd));
+ parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(m_portEnd));
+ } else
+ parse(m_string.left(m_hostEnd) + m_string.substring(m_portEnd));
}
void KURL::setHostAndPort(const String& hostAndPort)
@@ -822,7 +831,11 @@ String KURL::prettyURL() const
}
append(result, path());
- append(result, query());
+
+ if (m_pathEnd != m_queryEnd) {
+ result.append('?');
+ append(result, query());
+ }
if (m_fragmentEnd != m_queryEnd) {
result.append('#');
@@ -1047,7 +1060,7 @@ void KURL::parse(const char* url, const String* originalString)
&& matchLetter(url[2], 'l')
&& matchLetter(url[3], 'e');
- bool isHTTPorHTTPS = matchLetter(url[0], 'h')
+ m_protocolInHTTPFamily = matchLetter(url[0], 'h')
&& matchLetter(url[1], 't')
&& matchLetter(url[2], 't')
&& matchLetter(url[3], 'p')
@@ -1129,7 +1142,7 @@ void KURL::parse(const char* url, const String* originalString)
return;
}
- if (userStart == portEnd && !isHTTPorHTTPS && !isFile) {
+ if (userStart == portEnd && !m_protocolInHTTPFamily && !isFile) {
// No authority found, which means that this is not a net_path, but rather an abs_path whose first two
// path segments are empty. For file, http and https only, an empty authority is allowed.
userStart -= 2;
@@ -1253,7 +1266,7 @@ void KURL::parse(const char* url, const String* originalString)
// For canonicalization, ensure we have a '/' for no path.
// Only do this for http and https.
- if (isHTTPorHTTPS && pathEnd - pathStart == 0)
+ if (m_protocolInHTTPFamily && pathEnd - pathStart == 0)
*p++ = '/';
// add path, escaping bad characters
@@ -1291,7 +1304,7 @@ void KURL::parse(const char* url, const String* originalString)
// If we didn't end up actually changing the original string and
// it was already in a String, reuse it to avoid extra allocation.
- if (originalString && strncmp(buffer.data(), url, m_fragmentEnd) == 0)
+ if (originalString && originalString->length() == static_cast<unsigned>(m_fragmentEnd) && strncmp(buffer.data(), url, m_fragmentEnd) == 0)
m_string = *originalString;
else
m_string = String(buffer.data(), m_fragmentEnd);
diff --git a/WebCore/platform/KURL.h b/WebCore/platform/KURL.h
index 7f6b102..46b72c7 100644
--- a/WebCore/platform/KURL.h
+++ b/WebCore/platform/KURL.h
@@ -47,7 +47,7 @@ QT_END_NAMESPACE
#endif
#if USE(GOOGLEURL)
-#include "GoogleURLPrivate.h"
+#include "KURLGooglePrivate.h"
#endif
namespace WebCore {
@@ -84,7 +84,7 @@ public:
// For conversions for other structures that have already parsed and
// canonicalized the URL. The input must be exactly what KURL would have
// done with the same input.
- KURL(const char* canonicalSpec, int canonicalSpecLen,
+ KURL(const CString& canonicalSpec,
const url_parse::Parsed& parsed, bool isValid);
#endif
@@ -119,16 +119,19 @@ public:
String pass() const;
String path() const;
String lastPathComponent() const;
- String query() const; // Includes the "?".
- String ref() const; // Does *not* include the "#".
+ String query() const;
+ String ref() const;
bool hasRef() const;
+ String baseAsString() const;
+
String prettyURL() const;
String fileSystemPath() const;
// 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 protocolInHTTPFamily() const;
bool isLocalFile() const;
void setProtocol(const String&);
@@ -203,10 +206,10 @@ private:
bool isHierarchical() const;
static bool protocolIs(const String&, const char*);
#if USE(GOOGLEURL)
- friend class GoogleURLPrivate;
+ friend class KURLGooglePrivate;
void parse(const char* url, const String* originalString); // KURLMac calls this.
void copyToBuffer(Vector<char, 512>& buffer) const; // KURLCFNet uses this.
- GoogleURLPrivate m_url;
+ KURLGooglePrivate m_url;
#else // !USE(GOOGLEURL)
void init(const KURL&, const String&, const TextEncoding&);
void copyToBuffer(Vector<char, 512>& buffer) const;
@@ -218,7 +221,9 @@ private:
void parse(const char* url, const String* originalString);
String m_string;
- bool m_isValid;
+ bool m_isValid : 1;
+ bool m_protocolInHTTPFamily : 1;
+
int m_schemeEnd;
int m_userStart;
int m_userEnd;
@@ -311,6 +316,11 @@ inline bool KURL::isValid() const
return m_isValid;
}
+inline bool KURL::protocolInHTTPFamily() const
+{
+ return m_protocolInHTTPFamily;
+}
+
inline unsigned KURL::hostStart() const
{
return (m_passwordEnd == m_userStart) ? m_passwordEnd : m_passwordEnd + 1;
diff --git a/WebCore/platform/KURLGoogle.cpp b/WebCore/platform/KURLGoogle.cpp
new file mode 100644
index 0000000..c2e8272
--- /dev/null
+++ b/WebCore/platform/KURLGoogle.cpp
@@ -0,0 +1,944 @@
+/*
+ * 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"
+
+#if USE(GOOGLEURL)
+#include "KURL.h"
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+#include "CString.h"
+#include "NotImplemented.h"
+#include "TextEncoding.h"
+#include <wtf/Vector.h>
+
+#include <googleurl/src/url_canon_internal.h>
+#include <googleurl/src/url_util.h>
+
+using WTF::isASCIILower;
+using WTF::toASCIILower;
+
+namespace WebCore {
+
+// Wraps WebCore's text encoding in a character set converter for the
+// canonicalizer.
+class KURLCharsetConverter : public url_canon::CharsetConverter {
+public:
+ // The encoding parameter may be NULL, but in this case the object must not
+ // be called.
+ KURLCharsetConverter(const TextEncoding* encoding)
+ : m_encoding(encoding)
+ {
+ }
+
+ virtual void ConvertFromUTF16(const url_parse::UTF16Char* input, int inputLength,
+ url_canon::CanonOutput* output)
+ {
+ CString encoded = m_encoding->encode(input, inputLength, URLEncodedEntitiesForUnencodables);
+ output->Append(encoded.data(), static_cast<int>(encoded.length()));
+ }
+
+private:
+ const TextEncoding* m_encoding;
+};
+
+// Note that this function must be named differently than the one in KURL.cpp
+// since our unit tests evilly include both files, and their local definition
+// will be ambiguous.
+static inline void assertProtocolIsGood(const char* protocol)
+{
+#ifndef NDEBUG
+ const char* p = protocol;
+ while (*p) {
+ ASSERT(*p > ' ' && *p < 0x7F && !(*p >= 'A' && *p <= 'Z'));
+ ++p;
+ }
+#endif
+}
+
+// Returns the characters for the given string, or a pointer to a static empty
+// string if the input string is NULL. This will always ensure we have a non-
+// NULL character pointer since ReplaceComponents has special meaning for NULL.
+static inline const url_parse::UTF16Char* CharactersOrEmpty(const String& str)
+{
+ static const url_parse::UTF16Char zero = 0;
+ return str.characters() ?
+ reinterpret_cast<const url_parse::UTF16Char*>(str.characters()) :
+ &zero;
+}
+
+static inline bool isUnicodeEncoding(const TextEncoding* encoding)
+{
+ return encoding->encodingForFormSubmission() == UTF8Encoding();
+}
+
+static bool lowerCaseEqualsASCII(const char* begin, const char* end, const char* str)
+{
+ while (begin != end && *str) {
+ ASSERT(isASCIILower(*str));
+ if (toASCIILower(*begin++) != *str++)
+ return false;
+ }
+
+ // Both strings are equal (ignoring case) if and only if all of the characters were equal,
+ // and the end of both has been reached.
+ return begin == end && !*str;
+}
+
+
+// KURLGooglePrivate -----------------------------------------------------------
+
+KURLGooglePrivate::KURLGooglePrivate()
+ : m_isValid(false)
+ , m_protocolInHTTPFamily(false)
+ , m_utf8IsASCII(true)
+ , m_stringIsValid(false)
+{
+}
+
+KURLGooglePrivate::KURLGooglePrivate(const url_parse::Parsed& parsed, bool isValid)
+ : m_isValid(isValid)
+ , m_protocolInHTTPFamily(false)
+ , m_parsed(parsed)
+ , m_utf8IsASCII(true)
+ , m_stringIsValid(false)
+{
+}
+
+// Setters for the data. Using the ASCII version when you know the
+// data is ASCII will be slightly more efficient. The UTF-8 version
+// will always be correct if the caller is unsure.
+void KURLGooglePrivate::setUtf8(const CString& str)
+{
+ const char* data = str.data();
+ unsigned dataLength = str.length();
+
+ // The m_utf8IsASCII must always be correct since the DeprecatedString
+ // getter must create it with the proper constructor. This test can be
+ // removed when DeprecatedString is gone, but it still might be a
+ // performance win.
+ m_utf8IsASCII = true;
+ for (unsigned i = 0; i < dataLength; i++) {
+ if (static_cast<unsigned char>(data[i]) >= 0x80) {
+ m_utf8IsASCII = false;
+ break;
+ }
+ }
+
+ m_utf8 = str;
+ m_stringIsValid = false;
+ initProtocolInHTTPFamily();
+}
+
+void KURLGooglePrivate::setAscii(const CString& str)
+{
+ m_utf8 = str;
+ m_utf8IsASCII = true;
+ m_stringIsValid = false;
+ initProtocolInHTTPFamily();
+}
+
+void KURLGooglePrivate::init(const KURL& base,
+ const String& relative,
+ const TextEncoding* queryEncoding)
+{
+ init(base, relative.characters(), relative.length(), queryEncoding);
+}
+
+// Note: code mostly duplicated below.
+void KURLGooglePrivate::init(const KURL& base, const char* rel, int relLength,
+ const TextEncoding* queryEncoding)
+{
+ // As a performance optimization, we do not use the charset converter if
+ // encoding is UTF-8 or other Unicode encodings. Note that this is
+ // per HTML5 2.5.3 (resolving URL). The URL canonicalizer will be
+ // more efficient with no charset converter object because it
+ // can do UTF-8 internally with no extra copies.
+
+ // We feel free to make the charset converter object every time since it's
+ // just a wrapper around a reference.
+ KURLCharsetConverter charsetConverterObject(queryEncoding);
+ KURLCharsetConverter* charsetConverter =
+ (!queryEncoding || isUnicodeEncoding(queryEncoding)) ? 0 :
+ &charsetConverterObject;
+
+ url_canon::RawCanonOutputT<char> output;
+ const CString& baseStr = base.m_url.utf8String();
+ m_isValid = url_util::ResolveRelative(baseStr.data(), baseStr.length(),
+ base.m_url.m_parsed, rel, relLength,
+ charsetConverter,
+ &output, &m_parsed);
+
+ // See FIXME in KURLGooglePrivate in the header. If canonicalization has not
+ // changed the string, we can avoid an extra allocation by using assignment.
+ //
+ // When KURL encounters an error such that the URL is invalid and empty
+ // (for example, resolving a relative URL on a non-hierarchical base), it
+ // will produce an isNull URL, and calling setUtf8 will produce an empty
+ // non-null URL. This is unlikely to affect anything, but we preserve this
+ // just in case.
+ if (m_isValid || output.length()) {
+ // Without ref, the whole url is guaranteed to be ASCII-only.
+ if (m_parsed.ref.is_nonempty())
+ setUtf8(CString(output.data(), output.length()));
+ else
+ setAscii(CString(output.data(), output.length()));
+ } else {
+ // WebCore expects resolved URLs to be empty rather than NULL.
+ setUtf8(CString("", 0));
+ }
+}
+
+// Note: code mostly duplicated above. See FIXMEs and comments there.
+void KURLGooglePrivate::init(const KURL& base, const UChar* rel, int relLength,
+ const TextEncoding* queryEncoding)
+{
+ KURLCharsetConverter charsetConverterObject(queryEncoding);
+ KURLCharsetConverter* charsetConverter =
+ (!queryEncoding || isUnicodeEncoding(queryEncoding)) ? 0 :
+ &charsetConverterObject;
+
+ url_canon::RawCanonOutputT<char> output;
+ const CString& baseStr = base.m_url.utf8String();
+ m_isValid = url_util::ResolveRelative(baseStr.data(), baseStr.length(),
+ base.m_url.m_parsed, rel, relLength,
+ charsetConverter,
+ &output, &m_parsed);
+
+ if (m_isValid || output.length()) {
+ if (m_parsed.ref.is_nonempty())
+ setUtf8(CString(output.data(), output.length()));
+ else
+ setAscii(CString(output.data(), output.length()));
+ } else
+ setUtf8(CString("", 0));
+}
+
+void KURLGooglePrivate::initProtocolInHTTPFamily()
+{
+ if (!m_isValid) {
+ m_protocolInHTTPFamily = false;
+ return;
+ }
+
+ const char* scheme = m_utf8.data() + m_parsed.scheme.begin;
+ if (m_parsed.scheme.len == 4)
+ m_protocolInHTTPFamily = lowerCaseEqualsASCII(scheme, scheme + 4, "http");
+ else if (m_parsed.scheme.len == 5)
+ m_protocolInHTTPFamily = lowerCaseEqualsASCII(scheme, scheme + 5, "https");
+ else
+ m_protocolInHTTPFamily = false;
+}
+
+void KURLGooglePrivate::copyTo(KURLGooglePrivate* dest) const
+{
+ dest->m_isValid = m_isValid;
+ dest->m_protocolInHTTPFamily = m_protocolInHTTPFamily;
+ dest->m_parsed = m_parsed;
+
+ // Don't copy the 16-bit string since that will be regenerated as needed.
+ dest->m_utf8 = CString(m_utf8.data(), m_utf8.length());
+ dest->m_utf8IsASCII = m_utf8IsASCII;
+ dest->m_stringIsValid = false;
+}
+
+String KURLGooglePrivate::componentString(const url_parse::Component& comp) const
+{
+ if (!m_isValid || comp.len <= 0) {
+ // KURL returns a NULL string if the URL is itself a NULL string, and an
+ // empty string for other nonexistant entities.
+ if (utf8String().isNull())
+ return String();
+ return String("", 0);
+ }
+ // begin and len are in terms of bytes which do not match
+ // if string() is UTF-16 and input contains non-ASCII characters.
+ // However, the only part in urlString that can contain non-ASCII
+ // characters is 'ref' at the end of the string. In that case,
+ // begin will always match the actual value and len (in terms of
+ // byte) will be longer than what's needed by 'mid'. However, mid
+ // truncates len to avoid go past the end of a string so that we can
+ // get away withtout doing anything here.
+ return string().substring(comp.begin, comp.len);
+}
+
+void KURLGooglePrivate::replaceComponents(const Replacements& replacements)
+{
+ url_canon::RawCanonOutputT<char> output;
+ url_parse::Parsed newParsed;
+
+ m_isValid = url_util::ReplaceComponents(utf8String().data(),
+ utf8String().length(), m_parsed, replacements, 0, &output, &newParsed);
+
+ m_parsed = newParsed;
+ if (m_parsed.ref.is_nonempty())
+ setUtf8(CString(output.data(), output.length()));
+ else
+ setAscii(CString(output.data(), output.length()));
+}
+
+const String& KURLGooglePrivate::string() const
+{
+ if (!m_stringIsValid) {
+ // Must special case the NULL case, since constructing the
+ // string like we do below will generate an empty rather than
+ // a NULL string.
+ if (m_utf8.isNull())
+ m_string = String();
+ else if (m_utf8IsASCII)
+ m_string = String(m_utf8.data(), m_utf8.length());
+ else
+ m_string = String::fromUTF8(m_utf8.data(), m_utf8.length());
+ m_stringIsValid = true;
+ }
+ return m_string;
+}
+
+// KURL ------------------------------------------------------------------------
+
+// Creates with NULL-terminated string input representing an absolute URL.
+// WebCore generally calls this only with hardcoded strings, so the input is
+// ASCII. We treat is as UTF-8 just in case.
+KURL::KURL(const char *url)
+{
+ // FIXME The Mac code checks for beginning with a slash and converting to a
+ // file: URL. We will want to add this as well once we can compile on a
+ // system like that.
+ m_url.init(KURL(), url, strlen(url), 0);
+
+ // The one-argument constructors should never generate a NULL string.
+ // This is a funny quirk of KURL.cpp (probably a bug) which we preserve.
+ if (m_url.utf8String().isNull())
+ m_url.setAscii(CString("", 0));
+}
+
+// Initializes with a string representing an absolute URL. No encoding
+// information is specified. This generally happens when a KURL is converted
+// to a string and then converted back. In this case, the URL is already
+// canonical and in proper escaped form so needs no encoding. We treat it was
+// UTF-8 just in case.
+KURL::KURL(const String& url)
+{
+ if (!url.isNull())
+ m_url.init(KURL(), url, 0);
+ else {
+ // WebCore expects us to preserve the nullness of strings when this
+ // constructor is used. In all other cases, it expects a non-null
+ // empty string, which is what init() will create.
+ m_url.m_isValid = false;
+ m_url.m_protocolInHTTPFamily = false;
+ }
+}
+
+// Constructs a new URL given a base URL and a possibly relative input URL.
+// This assumes UTF-8 encoding.
+KURL::KURL(const KURL& base, const String& relative)
+{
+ m_url.init(base, relative, 0);
+}
+
+// Constructs a new URL given a base URL and a possibly relative input URL.
+// Any query portion of the relative URL will be encoded in the given encoding.
+KURL::KURL(const KURL& base,
+ const String& relative,
+ const TextEncoding& encoding)
+{
+ m_url.init(base, relative, &encoding.encodingForFormSubmission());
+}
+
+KURL::KURL(const CString& canonicalSpec,
+ const url_parse::Parsed& parsed, bool isValid)
+ : m_url(parsed, isValid)
+{
+ // We know the reference fragment is the only part that can be UTF-8, so
+ // we know it's ASCII when there is no ref.
+ if (parsed.ref.is_nonempty())
+ m_url.setUtf8(canonicalSpec);
+ else
+ m_url.setAscii(canonicalSpec);
+}
+
+#if PLATFORM(CF)
+KURL::KURL(CFURLRef)
+{
+ notImplemented();
+ invalidate();
+}
+
+CFURLRef KURL::createCFURL() const
+{
+ notImplemented();
+ return 0;
+}
+#endif
+
+KURL KURL::copy() const
+{
+ KURL result = *this;
+ m_url.copyTo(&result.m_url);
+ return result;
+}
+
+bool KURL::isNull() const
+{
+ return m_url.utf8String().isNull();
+}
+
+bool KURL::isEmpty() const
+{
+ return !m_url.utf8String().length();
+}
+
+bool KURL::isValid() const
+{
+ return m_url.m_isValid;
+}
+
+bool KURL::protocolInHTTPFamily() const
+{
+ return m_url.m_protocolInHTTPFamily;
+}
+
+bool KURL::hasPath() const
+{
+ // Note that http://www.google.com/" has a path, the path is "/". This can
+ // return false only for invalid or nonstandard URLs.
+ return m_url.m_parsed.path.len >= 0;
+}
+
+// We handle "parameters" separated by a semicolon, while KURL.cpp does not,
+// which can lead to different results in some cases.
+String KURL::lastPathComponent() const
+{
+ // When the output ends in a slash, WebCore has different expectations than
+ // the GoogleURL library. For "/foo/bar/" the library will return the empty
+ // string, but WebCore wants "bar".
+ url_parse::Component path = m_url.m_parsed.path;
+ if (path.len > 0 && m_url.utf8String().data()[path.end() - 1] == '/')
+ path.len--;
+
+ url_parse::Component file;
+ url_parse::ExtractFileName(m_url.utf8String().data(), path, &file);
+
+ // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns
+ // a null string when the path is empty, which we duplicate here.
+ if (!file.is_nonempty())
+ return String();
+ return m_url.componentString(file);
+}
+
+String KURL::protocol() const
+{
+ return m_url.componentString(m_url.m_parsed.scheme);
+}
+
+String KURL::host() const
+{
+ // Note: KURL.cpp unescapes here.
+ return m_url.componentString(m_url.m_parsed.host);
+}
+
+// Returns 0 when there is no port or it is invalid.
+//
+// We treat URL's with out-of-range port numbers as invalid URLs, and they will
+// be rejected by the canonicalizer. KURL.cpp will allow them in parsing, but
+// return 0 from this port() function, so we mirror that behavior here.
+unsigned short KURL::port() const
+{
+ if (!m_url.m_isValid || m_url.m_parsed.port.len <= 0)
+ return 0;
+ int port = url_parse::ParsePort(m_url.utf8String().data(), m_url.m_parsed.port);
+ if (port == url_parse::PORT_UNSPECIFIED)
+ return 0;
+ return static_cast<unsigned short>(port);
+}
+
+// Returns the empty string if there is no password.
+String KURL::pass() const
+{
+ // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns
+ // a null string when the password is empty, which we duplicate here.
+ if (!m_url.m_parsed.password.is_nonempty())
+ return String();
+
+ // Note: KURL.cpp unescapes here.
+ return m_url.componentString(m_url.m_parsed.password);
+}
+
+// Returns the empty string if there is no username.
+String KURL::user() const
+{
+ // Note: KURL.cpp unescapes here.
+ return m_url.componentString(m_url.m_parsed.username);
+}
+
+String KURL::ref() const
+{
+ // Empty but present refs ("foo.com/bar#") should result in the empty
+ // string, which m_url.componentString will produce. Nonexistant refs should be
+ // the NULL string.
+ if (!m_url.m_parsed.ref.is_valid())
+ return String();
+
+ // Note: KURL.cpp unescapes here.
+ return m_url.componentString(m_url.m_parsed.ref);
+}
+
+bool KURL::hasRef() const
+{
+ // Note: KURL.cpp unescapes here.
+ // FIXME determine if KURL.cpp agrees about an empty ref
+ return m_url.m_parsed.ref.len >= 0;
+}
+
+String KURL::query() const
+{
+ if (m_url.m_parsed.query.len >= 0)
+ return m_url.componentString(m_url.m_parsed.query);
+
+ // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns
+ // an empty string when the query is empty rather than a null (not sure
+ // which is right).
+ return String("", 0);
+}
+
+String KURL::path() const
+{
+ // Note: KURL.cpp unescapes here.
+ return m_url.componentString(m_url.m_parsed.path);
+}
+
+void KURL::setProtocol(const String& protocol)
+{
+ KURLGooglePrivate::Replacements replacements;
+ replacements.SetScheme(CharactersOrEmpty(protocol),
+ url_parse::Component(0, protocol.length()));
+ m_url.replaceComponents(replacements);
+}
+
+void KURL::setHost(const String& host)
+{
+ KURLGooglePrivate::Replacements replacements;
+ replacements.SetHost(CharactersOrEmpty(host),
+ url_parse::Component(0, host.length()));
+ m_url.replaceComponents(replacements);
+}
+
+// This function is used only in the JSC build.
+void KURL::setHostAndPort(const String& s)
+{
+ String newhost = s.left(s.find(":"));
+ String newport = s.substring(s.find(":") + 1);
+
+ KURLGooglePrivate::Replacements replacements;
+ // Host can't be removed, so we always set.
+ replacements.SetHost(CharactersOrEmpty(newhost),
+ url_parse::Component(0, newhost.length()));
+
+ if (newport.isEmpty()) // Port may be removed, so we support clearing.
+ replacements.ClearPort();
+ else
+ replacements.SetPort(CharactersOrEmpty(newport), url_parse::Component(0, newport.length()));
+ m_url.replaceComponents(replacements);
+}
+
+void KURL::setPort(unsigned short i)
+{
+ KURLGooglePrivate::Replacements replacements;
+ String portStr;
+ if (i) {
+ portStr = String::number(static_cast<int>(i));
+ replacements.SetPort(
+ reinterpret_cast<const url_parse::UTF16Char*>(portStr.characters()),
+ url_parse::Component(0, portStr.length()));
+
+ } else {
+ // Clear any existing port when it is set to 0.
+ replacements.ClearPort();
+ }
+ m_url.replaceComponents(replacements);
+}
+
+void KURL::setUser(const String& user)
+{
+ // This function is commonly called to clear the username, which we
+ // normally don't have, so we optimize this case.
+ if (user.isEmpty() && !m_url.m_parsed.username.is_valid())
+ return;
+
+ // The canonicalizer will clear any usernames that are empty, so we
+ // don't have to explicitly call ClearUsername() here.
+ KURLGooglePrivate::Replacements replacements;
+ replacements.SetUsername(CharactersOrEmpty(user),
+ url_parse::Component(0, user.length()));
+ m_url.replaceComponents(replacements);
+}
+
+void KURL::setPass(const String& pass)
+{
+ // This function is commonly called to clear the password, which we
+ // normally don't have, so we optimize this case.
+ if (pass.isEmpty() && !m_url.m_parsed.password.is_valid())
+ return;
+
+ // The canonicalizer will clear any passwords that are empty, so we
+ // don't have to explicitly call ClearUsername() here.
+ KURLGooglePrivate::Replacements replacements;
+ replacements.SetPassword(CharactersOrEmpty(pass),
+ url_parse::Component(0, pass.length()));
+ m_url.replaceComponents(replacements);
+}
+
+void KURL::setRef(const String& ref)
+{
+ // This function is commonly called to clear the ref, which we
+ // normally don't have, so we optimize this case.
+ if (ref.isNull() && !m_url.m_parsed.ref.is_valid())
+ return;
+
+ KURLGooglePrivate::Replacements replacements;
+ if (ref.isNull())
+ replacements.ClearRef();
+ else
+ replacements.SetRef(CharactersOrEmpty(ref), url_parse::Component(0, ref.length()));
+ m_url.replaceComponents(replacements);
+}
+
+void KURL::removeRef()
+{
+ KURLGooglePrivate::Replacements replacements;
+ replacements.ClearRef();
+ m_url.replaceComponents(replacements);
+}
+
+void KURL::setQuery(const String& query)
+{
+ KURLGooglePrivate::Replacements replacements;
+ if (query.isNull()) {
+ // KURL.cpp sets to NULL to clear any query.
+ replacements.ClearQuery();
+ } else if (query.length() > 0 && query[0] == '?') {
+ // WebCore expects the query string to begin with a question mark, but
+ // GoogleURL doesn't. So we trim off the question mark when setting.
+ replacements.SetQuery(CharactersOrEmpty(query),
+ url_parse::Component(1, query.length() - 1));
+ } else {
+ // When set with the empty string or something that doesn't begin with
+ // a question mark, KURL.cpp will add a question mark for you. The only
+ // way this isn't compatible is if you call this function with an empty
+ // string. KURL.cpp will leave a '?' with nothing following it in the
+ // URL, whereas we'll clear it.
+ // FIXME We should eliminate this difference.
+ replacements.SetQuery(CharactersOrEmpty(query),
+ url_parse::Component(0, query.length()));
+ }
+ m_url.replaceComponents(replacements);
+}
+
+void KURL::setPath(const String& path)
+{
+ // Empty paths will be canonicalized to "/", so we don't have to worry
+ // about calling ClearPath().
+ KURLGooglePrivate::Replacements replacements;
+ replacements.SetPath(CharactersOrEmpty(path),
+ url_parse::Component(0, path.length()));
+ m_url.replaceComponents(replacements);
+}
+
+// On Mac, this just seems to return the same URL, but with "/foo/bar" for
+// file: URLs instead of file:///foo/bar. We don't bother with any of this,
+// at least for now.
+String KURL::prettyURL() const
+{
+ if (!m_url.m_isValid)
+ return String();
+ return m_url.string();
+}
+
+// We copied the KURL version here on Sept 12, 2008 while doing a WebKit
+// merge.
+//
+// FIXME Somehow share this with KURL? Like we'd theoretically merge with
+// decodeURLEscapeSequences below?
+String mimeTypeFromDataURL(const String& url)
+{
+ ASSERT(protocolIs(url, "data"));
+ int index = url.find(';');
+ if (index == -1)
+ index = url.find(',');
+ if (index != -1) {
+ int len = index - 5;
+ if (len > 0)
+ return url.substring(5, len);
+ return "text/plain"; // Data URLs with no MIME type are considered text/plain.
+ }
+ return "";
+}
+
+String decodeURLEscapeSequences(const String& str)
+{
+ return decodeURLEscapeSequences(str, UTF8Encoding());
+}
+
+// In KURL.cpp's implementation, this is called by every component getter.
+// It will unescape every character, including NULL. This is scary, and may
+// cause security holes. We never call this function for components, and
+// just return the ASCII versions instead.
+//
+// However, this static function is called directly in some cases. It appears
+// that this only happens for javascript: URLs, so this is essentially the
+// JavaScript URL decoder. It assumes UTF-8 encoding.
+//
+// IE doesn't unescape %00, forcing you to use \x00 in JS strings, so we do
+// the same. This also eliminates NULL-related problems should a consumer
+// incorrectly call this function for non-JavaScript.
+//
+// FIXME These should be merged to the KURL.cpp implementation.
+String decodeURLEscapeSequences(const String& str, const TextEncoding& encoding)
+{
+ // FIXME We can probably use KURL.cpp's version of this function
+ // without modification. However, I'm concerned about
+ // https://bugs.webkit.org/show_bug.cgi?id=20559 so am keeping this old
+ // custom code for now. Using their version will also fix the bug that
+ // we ignore the encoding.
+ //
+ // FIXME b/1350291: This does not get called very often. We just convert
+ // first to 8-bit UTF-8, then unescape, then back to 16-bit. This kind of
+ // sucks, and we don't use the encoding properly, which will make some
+ // obscure anchor navigations fail.
+ CString cstr = str.utf8();
+
+ const char* input = cstr.data();
+ int inputLength = cstr.length();
+ url_canon::RawCanonOutputT<char> unescaped;
+ for (int i = 0; i < inputLength; i++) {
+ if (input[i] == '%') {
+ unsigned char ch;
+ if (url_canon::DecodeEscaped(input, &i, inputLength, &ch)) {
+ if (!ch) {
+ // Never unescape NULLs.
+ unescaped.push_back('%');
+ unescaped.push_back('0');
+ unescaped.push_back('0');
+ } else
+ unescaped.push_back(ch);
+ } else {
+ // Invalid escape sequence, copy the percent literal.
+ unescaped.push_back('%');
+ }
+ } else {
+ // Regular non-escaped 8-bit character.
+ unescaped.push_back(input[i]);
+ }
+ }
+
+ // Convert that 8-bit to UTF-16. It's not clear IE does this at all to
+ // JavaScript URLs, but Firefox and Safari do.
+ url_canon::RawCanonOutputT<url_parse::UTF16Char> utf16;
+ for (int i = 0; i < unescaped.length(); i++) {
+ unsigned char uch = static_cast<unsigned char>(unescaped.at(i));
+ if (uch < 0x80) {
+ // Non-UTF-8, just append directly
+ utf16.push_back(uch);
+ } else {
+ // next_ch will point to the last character of the decoded
+ // character.
+ int nextCharacter = i;
+ unsigned codePoint;
+ if (url_canon::ReadUTFChar(unescaped.data(), &nextCharacter,
+ unescaped.length(), &codePoint)) {
+ // Valid UTF-8 character, convert to UTF-16.
+ url_canon::AppendUTF16Value(codePoint, &utf16);
+ i = nextCharacter;
+ } else {
+ // KURL.cpp strips any sequences that are not valid UTF-8. This
+ // sounds scary. Instead, we just keep those invalid code
+ // points and promote to UTF-16. We copy all characters from
+ // the current position to the end of the identified sqeuqnce.
+ while (i < nextCharacter) {
+ utf16.push_back(static_cast<unsigned char>(unescaped.at(i)));
+ i++;
+ }
+ utf16.push_back(static_cast<unsigned char>(unescaped.at(i)));
+ }
+ }
+ }
+
+ return String(reinterpret_cast<UChar*>(utf16.data()), utf16.length());
+}
+
+bool KURL::protocolIs(const char* protocol) const
+{
+ assertProtocolIsGood(protocol);
+ if (m_url.m_parsed.scheme.len <= 0)
+ return !protocol;
+ return lowerCaseEqualsASCII(
+ m_url.utf8String().data() + m_url.m_parsed.scheme.begin,
+ m_url.utf8String().data() + m_url.m_parsed.scheme.end(),
+ protocol);
+}
+
+bool KURL::isLocalFile() const
+{
+ return protocolIs("file");
+}
+
+// This is called to escape a URL string. It is only used externally when
+// constructing mailto: links to set the query section. Since our query setter
+// will automatically do the correct escaping, this function does not have to
+// do any work.
+//
+// There is a possibility that a future called may use this function in other
+// ways, and may expect to get a valid URL string. The dangerous thing we want
+// to protect against here is accidentally getting NULLs in a string that is
+// not supposed to have NULLs. Therefore, we escape NULLs here to prevent this.
+String encodeWithURLEscapeSequences(const String& notEncodedString)
+{
+ CString utf8 = UTF8Encoding().encode(
+ reinterpret_cast<const UChar*>(notEncodedString.characters()),
+ notEncodedString.length(),
+ URLEncodedEntitiesForUnencodables);
+ const char* input = utf8.data();
+ int inputLength = utf8.length();
+
+ Vector<char, 2048> buffer;
+ for (int i = 0; i < inputLength; i++) {
+ if (!input[i])
+ buffer.append("%00", 3);
+ else
+ buffer.append(input[i]);
+ }
+ return String(buffer.data(), buffer.size());
+}
+
+bool KURL::isHierarchical() const
+{
+ if (!m_url.m_parsed.scheme.is_nonempty())
+ return false;
+ return url_util::IsStandard(
+ &m_url.utf8String().data()[m_url.m_parsed.scheme.begin],
+ m_url.utf8String().length(),
+ m_url.m_parsed.scheme);
+}
+
+#ifndef NDEBUG
+void KURL::print() const
+{
+ printf("%s\n", m_url.utf8String().data());
+}
+#endif
+
+void KURL::invalidate()
+{
+ // This is only called from the constructor so resetting the (automatically
+ // initialized) string and parsed structure would be a waste of time.
+ m_url.m_isValid = false;
+ m_url.m_protocolInHTTPFamily = false;
+}
+
+// Equal up to reference fragments, if any.
+bool equalIgnoringRef(const KURL& a, const KURL& b)
+{
+ // Compute the length of each URL without its ref. Note that the reference
+ // begin (if it exists) points to the character *after* the '#', so we need
+ // to subtract one.
+ int aLength = a.m_url.utf8String().length();
+ if (a.m_url.m_parsed.ref.len >= 0)
+ aLength = a.m_url.m_parsed.ref.begin - 1;
+
+ int bLength = b.m_url.utf8String().length();
+ if (b.m_url.m_parsed.ref.len >= 0)
+ bLength = b.m_url.m_parsed.ref.begin - 1;
+
+ return aLength == bLength
+ && !strncmp(a.m_url.utf8String().data(), b.m_url.utf8String().data(), aLength);
+}
+
+unsigned KURL::hostStart() const
+{
+ return m_url.m_parsed.CountCharactersBefore(url_parse::Parsed::HOST, false);
+}
+
+unsigned KURL::hostEnd() const
+{
+ return m_url.m_parsed.CountCharactersBefore(url_parse::Parsed::PORT, true);
+}
+
+unsigned KURL::pathStart() const
+{
+ return m_url.m_parsed.CountCharactersBefore(url_parse::Parsed::PATH, false);
+}
+
+unsigned KURL::pathEnd() const
+{
+ return m_url.m_parsed.CountCharactersBefore(url_parse::Parsed::QUERY, true);
+}
+
+unsigned KURL::pathAfterLastSlash() const
+{
+ // When there's no path, ask for what would be the beginning of it.
+ if (!m_url.m_parsed.path.is_valid())
+ return m_url.m_parsed.CountCharactersBefore(url_parse::Parsed::PATH, false);
+
+ url_parse::Component filename;
+ url_parse::ExtractFileName(m_url.utf8String().data(), m_url.m_parsed.path,
+ &filename);
+ return filename.begin;
+}
+
+const KURL& blankURL()
+{
+ static KURL staticBlankURL("about:blank");
+ return staticBlankURL;
+}
+
+bool protocolIs(const String& url, const char* protocol)
+{
+ // Do the comparison without making a new string object.
+ assertProtocolIsGood(protocol);
+ for (int i = 0; ; ++i) {
+ if (!protocol[i])
+ return url[i] == ':';
+ if (toASCIILower(url[i]) != protocol[i])
+ return false;
+ }
+}
+
+inline bool KURL::protocolIs(const String& string, const char* protocol)
+{
+ return WebCore::protocolIs(string, protocol);
+}
+
+} // namespace WebCore
+
+#endif // USE(GOOGLEURL)
diff --git a/WebCore/platform/KURLGooglePrivate.h b/WebCore/platform/KURLGooglePrivate.h
new file mode 100644
index 0000000..a70cce5
--- /dev/null
+++ b/WebCore/platform/KURLGooglePrivate.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef KURLGooglePrivate_h
+#define KURLGooglePrivate_h
+
+#include "CString.h"
+
+#include <googleurl/src/url_parse.h>
+#include <googleurl/src/url_canon.h>
+
+namespace WebCore {
+
+ class KURL;
+ class TextEncoding;
+
+ // Wraps the internals related to using Google-URL as the bnackend for KURL.
+ // This maintains the state and has auxiliary functions so that we don't need
+ // to uglify KURL.h while allowing Google-URL to be evaluated.
+ class KURLGooglePrivate {
+ public:
+ KURLGooglePrivate();
+ KURLGooglePrivate(const url_parse::Parsed&, bool isValid);
+
+ // Initializes the object. This will call through to one of the backend
+ // initializers below depending on whether the string's internal
+ // representation is 8 or 16 bit.
+ void init(const KURL& base, const String& relative,
+ const TextEncoding* queryEncoding);
+
+ // Backend initializers. The query encoding parameters are optional and can
+ // be NULL (this implies UTF-8). These initializers require that the object
+ // has just been created and the strings are NULL. Do not call on an
+ // already-constructed object.
+ void init(const KURL& base, const char* rel, int relLength,
+ const TextEncoding* queryEncoding);
+ void init(const KURL& base, const UChar* rel, int relLength,
+ const TextEncoding* queryEncoding);
+
+ // Does a deep copy to the given output object.
+ void copyTo(KURLGooglePrivate* dest) const;
+
+ // Returns the substring of the input identified by the given component.
+ String componentString(const url_parse::Component&) const;
+
+ // Replaces the given components, modifying the current URL. The current
+ // URL must be valid.
+ typedef url_canon::Replacements<url_parse::UTF16Char> Replacements;
+ void replaceComponents(const Replacements&);
+
+ // Setters for the data. Using the ASCII version when you know the
+ // data is ASCII will be slightly more efficient. The UTF-8 version
+ // will always be correct if the caller is unsure.
+ void setUtf8(const CString&);
+ void setAscii(const CString&);
+
+ // TODO(brettw) we can support an additional optimization. Make this
+ // buffer support both optinal Strings and UTF-8 data. This way, we can use
+ // the optimization from the original KURL which uses = with the original
+ // string when canonicalization did not change it. This allows the strings
+ // to share a buffer internally, and saves a malloc.
+
+ // Getters for the data.
+ const CString& utf8String() const { return m_utf8; }
+ const String& string() const;
+
+ bool m_isValid;
+ bool m_protocolInHTTPFamily;
+ url_parse::Parsed m_parsed; // Indexes into the UTF-8 version of the string.
+
+ private:
+ void initProtocolInHTTPFamily();
+
+ CString m_utf8;
+
+ // Set to true when the caller set us using the ASCII setter. We can
+ // be more efficient when we know there is no UTF-8 to worry about.
+ // This flag is currently always correct, but should be changed to be a
+ // hint (see setUtf8).
+ bool m_utf8IsASCII;
+
+ mutable bool m_stringIsValid;
+ mutable String m_string;
+ };
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/MIMETypeRegistry.h b/WebCore/platform/MIMETypeRegistry.h
index be741a4..fca467f 100644
--- a/WebCore/platform/MIMETypeRegistry.h
+++ b/WebCore/platform/MIMETypeRegistry.h
@@ -38,6 +38,7 @@ public:
static String getMIMETypeForExtension(const String& ext);
static Vector<String> getExtensionsForMIMEType(const String& type);
static String getPreferredExtensionForMIMEType(const String& type);
+
static String getMIMETypeForPath(const String& path);
// Check to see if a mime type is suitable for being loaded inline as an
diff --git a/WebCore/platform/PlatformWheelEvent.h b/WebCore/platform/PlatformWheelEvent.h
index fc954ed..9395e93 100644
--- a/WebCore/platform/PlatformWheelEvent.h
+++ b/WebCore/platform/PlatformWheelEvent.h
@@ -59,23 +59,13 @@ class wxPoint;
namespace WebCore {
- // Wheel events come in three flavors:
- // The ScrollByPixelWheelEvent is a fine-grained event that specifies the precise number of pixels to scroll. It is sent by MacBook touchpads on OS X.
- // For ScrollByPixelWheelEvents, the delta values contain the precise number of pixels to scroll.
- // The ScrollByLineWheelEvent (the normal wheel event) sends a delta that can be corrected by a line multiplier to determine how many lines to scroll.
- // If the platform has configurable line sensitivity (Windows), then the number of lines to scroll is used in order to behave like the platform.
- // If the platform does not have configurable line sensitivity, then WebCore's default behavior is used (which scrolls 3 * the wheel line delta).
- // For ScrollByLineWheelEvents, the delta values represent the number of lines to scroll.
- // The ScrollByPageWheelEvent indicates that the wheel event should scroll an entire page instead. In this case WebCore's built in paging behavior is used to page
+ // Wheel events come in two flavors:
+ // The ScrollByPixelWheelEvent is a fine-grained event that specifies the precise number of pixels to scroll. It is sent directly by MacBook touchpads on OS X,
+ // and synthesized in other cases where platforms generate line-by-line scrolling events.
+ // The ScrollByPageWheelEvent indicates that the wheel event should scroll an entire page. In this case WebCore's built in paging behavior is used to page
// up and down (you get the same behavior as if the user was clicking in a scrollbar track to page up or page down). Page scrolling only works in the vertical direction.
- enum PlatformWheelEventGranularity { ScrollByLineWheelEvent, ScrollByPageWheelEvent, ScrollByPixelWheelEvent };
+ enum PlatformWheelEventGranularity { ScrollByPageWheelEvent, ScrollByPixelWheelEvent };
- // WebCore uses a line multiple of ~3 (40px per line step) when doing arrowing with a scrollbar or line stepping via the arrow keys. The delta for wheeling is expressed
- // as a # of actual lines (40 / 3 = 1 wheel line). We use the horizontalLineMultiplier and verticalLineMultiplier methods to incorporate the line multiplier into the deltas. On
- // platforms that do not support wheel sensitivity, we use this hardcoded constant value of 3 to ensure that wheeling by default matches the WebCore multiplier you
- // get when doing other kinds of line stepping.
- const int cLineMultiplier = 3;
-
class PlatformWheelEvent {
public:
const IntPoint& pos() const { return m_position; } // PlatformWindow coordinates.
@@ -84,6 +74,9 @@ namespace WebCore {
float deltaX() const { return m_deltaX; }
float deltaY() const { return m_deltaY; }
+ float wheelTicksX() const { return m_wheelTicksX; }
+ float wheelTicksY() const { return m_wheelTicksY; }
+
PlatformWheelEventGranularity granularity() const { return m_granularity; }
bool isAccepted() const { return m_isAccepted; }
@@ -104,7 +97,7 @@ namespace WebCore {
PlatformWheelEvent(NSEvent*);
#endif
#if PLATFORM(WIN)
- PlatformWheelEvent(HWND, WPARAM, LPARAM, bool isHorizontal);
+ PlatformWheelEvent(HWND, WPARAM, LPARAM, bool isMouseHWheel);
#endif
#if PLATFORM(GTK)
PlatformWheelEvent(GdkEventScroll*);
@@ -117,18 +110,12 @@ namespace WebCore {
#endif
protected:
-#if !PLATFORM(WIN)
- int horizontalLineMultiplier() const { return cLineMultiplier; }
- int verticalLineMultiplier() const { return cLineMultiplier; }
-#else
- int horizontalLineMultiplier() const;
- int verticalLineMultiplier() const;
-#endif
-
IntPoint m_position;
IntPoint m_globalPosition;
float m_deltaX;
float m_deltaY;
+ float m_wheelTicksX;
+ float m_wheelTicksY;
PlatformWheelEventGranularity m_granularity;
bool m_isAccepted;
bool m_shiftKey;
diff --git a/WebCore/platform/PopupMenuStyle.h b/WebCore/platform/PopupMenuStyle.h
index 89a7a74..5325ff3 100644
--- a/WebCore/platform/PopupMenuStyle.h
+++ b/WebCore/platform/PopupMenuStyle.h
@@ -28,16 +28,20 @@
#include "Color.h"
#include "Font.h"
+#include "Length.h"
+#include "TextDirection.h"
namespace WebCore {
class PopupMenuStyle {
public:
- PopupMenuStyle(const Color& foreground, const Color& background, const Font& font, bool visible)
+ PopupMenuStyle(const Color& foreground, const Color& background, const Font& font, bool visible, Length textIndent, TextDirection textDirection)
: m_foregroundColor(foreground)
, m_backgroundColor(background)
, m_font(font)
, m_visible(visible)
+ , m_textIndent(textIndent)
+ , m_textDirection(textDirection)
{
}
@@ -45,12 +49,16 @@ public:
const Color& backgroundColor() const { return m_backgroundColor; }
const Font& font() const { return m_font; }
bool isVisible() const { return m_visible; }
+ Length textIndent() const { return m_textIndent; }
+ TextDirection textDirection() const { return m_textDirection; }
private:
Color m_foregroundColor;
Color m_backgroundColor;
Font m_font;
bool m_visible;
+ Length m_textIndent;
+ TextDirection m_textDirection;
};
} // namespace WebCore
diff --git a/WebCore/platform/RunLoopTimer.h b/WebCore/platform/RunLoopTimer.h
new file mode 100644
index 0000000..96eb8d8
--- /dev/null
+++ b/WebCore/platform/RunLoopTimer.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RunLoopTimer_h
+#define RunLoopTimer_h
+
+#include "SchedulePair.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+// Time intervals are all in seconds.
+
+class RunLoopTimerBase : Noncopyable {
+public:
+ virtual ~RunLoopTimerBase();
+
+ void schedule(const SchedulePair*);
+ void schedule(const SchedulePairHashSet&);
+
+ void start(double nextFireInterval, double repeatInterval);
+
+ void startRepeating(double repeatInterval) { start(repeatInterval, repeatInterval); }
+ void startOneShot(double interval) { start(interval, 0); }
+
+ void stop();
+ bool isActive() const;
+
+ virtual void fired() = 0;
+
+private:
+#if PLATFORM(CF)
+ RetainPtr<CFRunLoopTimerRef> m_timer;
+#endif
+};
+
+template <typename TimerFiredClass> class RunLoopTimer : public RunLoopTimerBase {
+public:
+ typedef void (TimerFiredClass::*TimerFiredFunction)(RunLoopTimer*);
+
+ RunLoopTimer(TimerFiredClass* o, TimerFiredFunction f)
+ : m_object(o), m_function(f) { }
+
+ virtual void fired() { (m_object->*m_function)(this); }
+
+private:
+ TimerFiredClass* m_object;
+ TimerFiredFunction m_function;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp
index 573dabe..5a12304 100644
--- a/WebCore/platform/ScrollView.cpp
+++ b/WebCore/platform/ScrollView.cpp
@@ -441,6 +441,9 @@ const int panIconSizeLength = 20;
void ScrollView::scrollContents(const IntSize& scrollDelta)
{
+ if (!hostWindow())
+ return;
+
// Since scrolling is double buffered, we will be blitting the scroll view's intersection
// with the clip rect every time to keep it smooth.
IntRect clipRect = windowClipRect();
@@ -531,8 +534,8 @@ void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
// If we went from n to 0 or from 0 to n and we're the outermost view,
// we need to invalidate the windowResizerRect(), since it will now need to paint
// differently.
- if (oldCount > 0 && m_scrollbarsAvoidingResizer == 0 ||
- oldCount == 0 && m_scrollbarsAvoidingResizer > 0)
+ if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0) ||
+ (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
invalidateRect(windowResizerRect());
}
}
@@ -615,10 +618,7 @@ void ScrollView::wheelEvent(PlatformWheelEvent& e)
e.accept();
float deltaX = e.deltaX();
float deltaY = e.deltaY();
- if (e.granularity() == ScrollByLineWheelEvent) {
- deltaX *= cMouseWheelPixelsPerLineStep;
- deltaY *= cMouseWheelPixelsPerLineStep;
- } else if (e.granularity() == ScrollByPageWheelEvent) {
+ if (e.granularity() == ScrollByPageWheelEvent) {
ASSERT(deltaX == 0);
bool negative = deltaY < 0;
deltaY = max(0, visibleHeight() - cAmountToKeepWhenPaging);
diff --git a/WebCore/platform/Scrollbar.h b/WebCore/platform/Scrollbar.h
index 9238a77..2c5b274 100644
--- a/WebCore/platform/Scrollbar.h
+++ b/WebCore/platform/Scrollbar.h
@@ -42,8 +42,7 @@ class ScrollbarTheme;
class PlatformMouseEvent;
// These match the numbers we use over in WebKit (WebFrameView.m).
-const int cScrollbarPixelsPerLineStep = 40;
-const float cMouseWheelPixelsPerLineStep = 40.0f / 3.0f;
+const int cScrollbarPixelsPerLineStep = 40;
const int cAmountToKeepWhenPaging = 40;
class Scrollbar : public Widget, public RefCounted<Scrollbar> {
diff --git a/WebCore/platform/SharedTimer.h b/WebCore/platform/SharedTimer.h
index 4cc90a2..a005add 100644
--- a/WebCore/platform/SharedTimer.h
+++ b/WebCore/platform/SharedTimer.h
@@ -28,17 +28,46 @@
namespace WebCore {
- // Single timer, shared to implement all the timers managed by the Timer class.
+ // Each thread has its own single instance of shared timer, which implements this interface.
+ // This instance is shared by all timers in the thread.
// Not intended to be used directly; use the Timer class instead.
+ class SharedTimer {
+ public:
+ virtual ~SharedTimer() {}
+ virtual void setFiredFunction(void (*)()) = 0;
- void setSharedTimerFiredFunction(void (*)());
+ // The fire time is relative to the classic POSIX epoch of January 1, 1970,
+ // as the result of currentTime() is.
+ virtual void setFireTime(double) = 0;
+ virtual void stop() = 0;
+ };
- // The fire time is relative to the classic POSIX epoch of January 1, 1970,
- // as the result of currentTime() is.
- void setSharedTimerFireTime(double fireTime);
+ // Implemented by port (since it provides the run loop for the main thread).
+ // FIXME: make ports implement MainThreadSharedTimer directly instead.
+ void setSharedTimerFiredFunction(void (*)());
+ void setSharedTimerFireTime(double);
void stopSharedTimer();
-}
+ // Implementation of SharedTimer for the main thread.
+ class MainThreadSharedTimer : public SharedTimer {
+ public:
+ virtual void setFiredFunction(void (*function)())
+ {
+ setSharedTimerFiredFunction(function);
+ }
+
+ virtual void setFireTime(double fireTime)
+ {
+ setSharedTimerFireTime(fireTime);
+ }
+
+ virtual void stop()
+ {
+ stopSharedTimer();
+ }
+ };
+
+} // namespace WebCore
-#endif
+#endif // SharedTimer_h
diff --git a/WebCore/platform/ThreadCheck.h b/WebCore/platform/ThreadCheck.h
index d1ff4a4..07eb463 100644
--- a/WebCore/platform/ThreadCheck.h
+++ b/WebCore/platform/ThreadCheck.h
@@ -33,12 +33,18 @@ namespace WebCore {
LogOnThreadViolation,
RaiseExceptionOnThreadViolation
};
- void setDefaultThreadViolationBehavior(ThreadViolationBehavior);
- void reportThreadViolation(const char* function);
+ enum ThreadViolationRound {
+ ThreadViolationRoundOne = 0,
+ ThreadViolationRoundTwo,
+ MaximumThreadViolationRound
+ };
+ void setDefaultThreadViolationBehavior(ThreadViolationBehavior, ThreadViolationRound);
+ void reportThreadViolation(const char* function, ThreadViolationRound);
}
-extern "C" void WebCoreReportThreadViolation(const char* function);
+extern "C" void WebCoreReportThreadViolation(const char* function, WebCore::ThreadViolationRound);
-#define WebCoreThreadViolationCheck() ::WebCore::reportThreadViolation(WTF_PRETTY_FUNCTION)
+#define WebCoreThreadViolationCheckRoundOne() ::WebCore::reportThreadViolation(WTF_PRETTY_FUNCTION, WebCore::ThreadViolationRoundOne)
+#define WebCoreThreadViolationCheckRoundTwo() ::WebCore::reportThreadViolation(WTF_PRETTY_FUNCTION, WebCore::ThreadViolationRoundTwo)
#endif
diff --git a/WebCore/platform/ThreadGlobalData.cpp b/WebCore/platform/ThreadGlobalData.cpp
index 9bf0bf2..903af66 100644
--- a/WebCore/platform/ThreadGlobalData.cpp
+++ b/WebCore/platform/ThreadGlobalData.cpp
@@ -29,6 +29,7 @@
#include "EventNames.h"
#include "StringImpl.h"
+#include "ThreadTimers.h"
#include <wtf/UnusedParam.h>
#if USE(ICU_UNICODE)
@@ -70,6 +71,7 @@ ThreadGlobalData::ThreadGlobalData()
: m_emptyString(new StringImpl)
, m_atomicStringTable(new HashSet<StringImpl*>)
, m_eventNames(new EventNames)
+ , m_threadTimers(new ThreadTimers)
#if USE(ICU_UNICODE)
, m_cachedConverterICU(new ICUConverterWrapper)
#endif
@@ -90,6 +92,7 @@ ThreadGlobalData::~ThreadGlobalData()
delete m_eventNames;
delete m_atomicStringTable;
+ delete m_threadTimers;
ASSERT(isMainThread() || m_emptyString->hasOneRef()); // We intentionally don't clean up static data on application quit, so there will be many strings remaining on the main thread.
delete m_emptyString;
diff --git a/WebCore/platform/ThreadGlobalData.h b/WebCore/platform/ThreadGlobalData.h
index 17637aa..7faca36 100644
--- a/WebCore/platform/ThreadGlobalData.h
+++ b/WebCore/platform/ThreadGlobalData.h
@@ -36,6 +36,7 @@ namespace WebCore {
class EventNames;
struct ICUConverterWrapper;
struct TECConverterWrapper;
+ class ThreadTimers;
class ThreadGlobalData : Noncopyable {
public:
@@ -45,6 +46,7 @@ namespace WebCore {
EventNames& eventNames() { return *m_eventNames; }
StringImpl* emptyString() { return m_emptyString; }
HashSet<StringImpl*>& atomicStringTable() { return *m_atomicStringTable; }
+ ThreadTimers& threadTimers() { return *m_threadTimers; }
#if USE(ICU_UNICODE)
ICUConverterWrapper& cachedConverterICU() { return *m_cachedConverterICU; }
@@ -58,6 +60,7 @@ namespace WebCore {
StringImpl* m_emptyString;
HashSet<StringImpl*>* m_atomicStringTable;
EventNames* m_eventNames;
+ ThreadTimers* m_threadTimers;
#if USE(ICU_UNICODE)
ICUConverterWrapper* m_cachedConverterICU;
diff --git a/WebCore/platform/ThreadTimers.cpp b/WebCore/platform/ThreadTimers.cpp
new file mode 100644
index 0000000..71a06b0
--- /dev/null
+++ b/WebCore/platform/ThreadTimers.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this 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 "ThreadTimers.h"
+
+#include "SharedTimer.h"
+#include "ThreadGlobalData.h"
+#include "Timer.h"
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+// Timers are created, started and fired on the same thread, and each thread has its own ThreadTimers
+// copy to keep the heap and a set of currently firing timers.
+
+static MainThreadSharedTimer* mainThreadSharedTimer()
+{
+ static MainThreadSharedTimer* timer = new MainThreadSharedTimer;
+ return timer;
+}
+
+ThreadTimers::ThreadTimers()
+ : m_sharedTimer(0)
+ , m_firingTimers(false)
+{
+ if (isMainThread())
+ setSharedTimer(mainThreadSharedTimer());
+}
+
+// A worker thread may initialize SharedTimer after some timers are created.
+// Also, SharedTimer can be replaced with 0 before all timers are destroyed.
+void ThreadTimers::setSharedTimer(SharedTimer* sharedTimer)
+{
+ if (m_sharedTimer) {
+ m_sharedTimer->setFiredFunction(0);
+ m_sharedTimer->stop();
+ }
+
+ m_sharedTimer = sharedTimer;
+
+ if (sharedTimer) {
+ m_sharedTimer->setFiredFunction(ThreadTimers::sharedTimerFired);
+ updateSharedTimer();
+ }
+}
+
+void ThreadTimers::updateSharedTimer()
+{
+ if (!m_sharedTimer)
+ return;
+
+ if (m_firingTimers || m_timerHeap.isEmpty())
+ m_sharedTimer->stop();
+ else
+ m_sharedTimer->setFireTime(m_timerHeap.first()->m_nextFireTime);
+}
+
+
+void ThreadTimers::collectFiringTimers(double fireTime, Vector<TimerBase*>& firingTimers)
+{
+ while (!m_timerHeap.isEmpty() && m_timerHeap.first()->m_nextFireTime <= fireTime) {
+ TimerBase* timer = m_timerHeap.first();
+ firingTimers.append(timer);
+ m_timersReadyToFire.add(timer);
+ timer->m_nextFireTime = 0;
+ timer->heapDeleteMin();
+ }
+}
+
+void ThreadTimers::fireTimers(double fireTime, const Vector<TimerBase*>& firingTimers)
+{
+ size_t size = firingTimers.size();
+ for (size_t i = 0; i != size; ++i) {
+ TimerBase* timer = firingTimers[i];
+
+ // If not in the set, this timer has been deleted or re-scheduled in another timer's fired function.
+ // So either we don't want to fire it at all or we will fire it next time the shared timer goes off.
+ // It might even have been deleted; that's OK because we won't do anything else with the pointer.
+ if (!m_timersReadyToFire.contains(timer))
+ continue;
+
+ // Setting the next fire time has a side effect of removing the timer from the firing timers set.
+ double interval = timer->repeatInterval();
+ timer->setNextFireTime(interval ? fireTime + interval : 0);
+
+ // Once the timer has been fired, it may be deleted, so do nothing else with it after this point.
+ timer->fired();
+
+ // Catch the case where the timer asked timers to fire in a nested event loop.
+ if (!m_firingTimers)
+ break;
+ }
+}
+
+void ThreadTimers::sharedTimerFired()
+{
+ // Redirect to non-static method.
+ threadGlobalData().threadTimers().sharedTimerFiredInternal();
+}
+
+void ThreadTimers::sharedTimerFiredInternal()
+{
+ // Do a re-entrancy check.
+ if (m_firingTimers)
+ return;
+ m_firingTimers = true;
+
+ double fireTime = currentTime();
+ Vector<TimerBase*> firingTimers;
+
+ // m_timersReadyToFire will initially contain the same set as firingTimers, but
+ // as timers fire some mat become re-scheduled or deleted. They get removed from
+ // m_timersReadyToFire so we can avoid firing them.
+ ASSERT(m_timersReadyToFire.isEmpty());
+
+ collectFiringTimers(fireTime, firingTimers);
+ fireTimers(fireTime, firingTimers);
+
+ m_timersReadyToFire.clear();
+ m_firingTimers = false;
+
+ updateSharedTimer();
+}
+
+void ThreadTimers::fireTimersInNestedEventLoop()
+{
+ // Reset the reentrancy guard so the timers can fire again.
+ m_firingTimers = false;
+ m_timersReadyToFire.clear();
+ updateSharedTimer();
+}
+
+} // namespace WebCore
+
diff --git a/WebCore/platform/ThreadTimers.h b/WebCore/platform/ThreadTimers.h
new file mode 100644
index 0000000..366c320
--- /dev/null
+++ b/WebCore/platform/ThreadTimers.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this 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 ThreadTimer_h
+#define ThreadTimer_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class SharedTimer;
+ class TimerBase;
+
+ // A collection of timers per thread. Kept in ThreadGlobalData.
+ class ThreadTimers : Noncopyable {
+ public:
+ ThreadTimers();
+
+ // On a thread different then main, we should set the thread's instance of the SharedTimer.
+ void setSharedTimer(SharedTimer*);
+
+ Vector<TimerBase*>& timerHeap() { return m_timerHeap; }
+ HashSet<const TimerBase*>& timersReadyToFire() { return m_timersReadyToFire; }
+
+ void updateSharedTimer();
+ void fireTimersInNestedEventLoop();
+
+ private:
+ static void sharedTimerFired();
+
+ void fireTimers(double fireTime, const Vector<TimerBase*>&);
+ void collectFiringTimers(double fireTime, Vector<TimerBase*>&);
+ void sharedTimerFiredInternal();
+ void fireTimersInNestedEventLoopInternal();
+
+ Vector<TimerBase*> m_timerHeap;
+ HashSet<const TimerBase*> m_timersReadyToFire; // Temporarily holds a pointer to a stack object. No ownership.
+ SharedTimer* m_sharedTimer; // External object, can be a run loop on a worker thread. Normally set/reset by worker thread.
+ bool m_firingTimers; // Reentrancy guard.
+ };
+
+}
+
+#endif
diff --git a/WebCore/platform/Timer.cpp b/WebCore/platform/Timer.cpp
index a8fcbb8..353a2a7 100644
--- a/WebCore/platform/Timer.cpp
+++ b/WebCore/platform/Timer.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,6 +28,8 @@
#include "Timer.h"
#include "SharedTimer.h"
+#include "ThreadGlobalData.h"
+#include "ThreadTimers.h"
#include <limits.h>
#include <limits>
#include <math.h>
@@ -44,22 +47,28 @@ namespace WebCore {
//
// When a timer's "next fire time" changes, we need to move it around in the priority queue.
-// ----------------
-
-#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it
-static bool deferringTimers;
-#endif
-static Vector<TimerBase*>* timerHeap;
-static HashSet<const TimerBase*>* timersReadyToFire;
+// Simple accessors to thread-specific data.
+static Vector<TimerBase*>& timerHeap()
+{
+ return threadGlobalData().threadTimers().timerHeap();
+}
-// ----------------
+static HashSet<const TimerBase*>& timersReadyToFire()
+{
+ return threadGlobalData().threadTimers().timersReadyToFire();
+}
// Class to represent elements in the heap when calling the standard library heap algorithms.
// Maintains the m_heapIndex value in the timers themselves, which allows us to do efficient
// modification of the heap.
class TimerHeapElement {
public:
- explicit TimerHeapElement(int i) : m_index(i), m_timer((*timerHeap)[m_index]) { checkConsistency(); }
+ explicit TimerHeapElement(int i)
+ : m_index(i)
+ , m_timer(timerHeap()[m_index])
+ {
+ checkConsistency();
+ }
TimerHeapElement(const TimerHeapElement&);
TimerHeapElement& operator=(const TimerHeapElement&);
@@ -69,7 +78,7 @@ public:
void checkConsistency() const
{
ASSERT(m_index >= 0);
- ASSERT(m_index < (timerHeap ? static_cast<int>(timerHeap->size()) : 0));
+ ASSERT(m_index < static_cast<int>(timerHeap().size()));
}
private:
@@ -90,7 +99,7 @@ inline TimerHeapElement& TimerHeapElement::operator=(const TimerHeapElement& o)
m_timer = t;
if (m_index != -1) {
checkConsistency();
- (*timerHeap)[m_index] = t;
+ timerHeap()[m_index] = t;
t->m_heapIndex = m_index;
}
return *this;
@@ -137,7 +146,7 @@ public:
void checkConsistency(int offset = 0) const
{
ASSERT_UNUSED(offset, m_index + offset >= 0);
- ASSERT_UNUSED(offset, m_index + offset <= (timerHeap ? static_cast<int>(timerHeap->size()) : 0));
+ ASSERT_UNUSED(offset, m_index + offset <= static_cast<int>(timerHeap().size()));
}
private:
@@ -156,31 +165,16 @@ inline int operator-(TimerHeapIterator a, TimerHeapIterator b) { return a.index(
// ----------------
-void updateSharedTimer()
-{
-#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it
- if (timersReadyToFire || deferringTimers || !timerHeap || timerHeap->isEmpty())
-#else
- if (timersReadyToFire || !timerHeap || timerHeap->isEmpty())
-#endif
- stopSharedTimer();
- else
- setSharedTimerFireTime(timerHeap->first()->m_nextFireTime);
-}
-
-// ----------------
-
TimerBase::TimerBase()
- : m_nextFireTime(0), m_repeatInterval(0), m_heapIndex(-1)
+ : m_nextFireTime(0)
+ , m_repeatInterval(0)
+ , m_heapIndex(-1)
{
- // We only need to do this once, but probably not worth trying to optimize it.
- setSharedTimerFiredFunction(sharedTimerFired);
}
TimerBase::~TimerBase()
{
stop();
-
ASSERT(!inHeap());
}
@@ -202,7 +196,7 @@ void TimerBase::stop()
bool TimerBase::isActive() const
{
- return m_nextFireTime || (timersReadyToFire && timersReadyToFire->contains(this));
+ return m_nextFireTime || timersReadyToFire().contains(this);
}
double TimerBase::nextFireInterval() const
@@ -216,11 +210,10 @@ double TimerBase::nextFireInterval() const
inline void TimerBase::checkHeapIndex() const
{
- ASSERT(timerHeap);
- ASSERT(!timerHeap->isEmpty());
+ ASSERT(!timerHeap().isEmpty());
ASSERT(m_heapIndex >= 0);
- ASSERT(m_heapIndex < static_cast<int>(timerHeap->size()));
- ASSERT((*timerHeap)[m_heapIndex] == this);
+ ASSERT(m_heapIndex < static_cast<int>(timerHeap().size()));
+ ASSERT(timerHeap()[m_heapIndex] == this);
}
inline void TimerBase::checkConsistency() const
@@ -243,15 +236,15 @@ inline void TimerBase::heapDelete()
{
ASSERT(m_nextFireTime == 0);
heapPop();
- timerHeap->removeLast();
+ timerHeap().removeLast();
m_heapIndex = -1;
}
-inline void TimerBase::heapDeleteMin()
+void TimerBase::heapDeleteMin()
{
ASSERT(m_nextFireTime == 0);
heapPopMin();
- timerHeap->removeLast();
+ timerHeap().removeLast();
m_heapIndex = -1;
}
@@ -265,10 +258,8 @@ inline void TimerBase::heapIncreaseKey()
inline void TimerBase::heapInsert()
{
ASSERT(!inHeap());
- if (!timerHeap)
- timerHeap = new Vector<TimerBase*>;
- timerHeap->append(this);
- m_heapIndex = timerHeap->size() - 1;
+ timerHeap().append(this);
+ m_heapIndex = timerHeap().size() - 1;
heapDecreaseKey();
}
@@ -284,19 +275,18 @@ inline void TimerBase::heapPop()
void TimerBase::heapPopMin()
{
- ASSERT(this == timerHeap->first());
+ ASSERT(this == timerHeap().first());
checkHeapIndex();
- pop_heap(TimerHeapIterator(0), TimerHeapIterator(timerHeap->size()));
+ pop_heap(TimerHeapIterator(0), TimerHeapIterator(timerHeap().size()));
checkHeapIndex();
- ASSERT(this == timerHeap->last());
+ ASSERT(this == timerHeap().last());
}
void TimerBase::setNextFireTime(double newTime)
{
// Keep heap valid while changing the next-fire time.
- if (timersReadyToFire)
- timersReadyToFire->remove(this);
+ timersReadyToFire().remove(this);
double oldTime = m_nextFireTime;
if (oldTime != newTime) {
@@ -318,89 +308,16 @@ void TimerBase::setNextFireTime(double newTime)
bool isFirstTimerInHeap = m_heapIndex == 0;
if (wasFirstTimerInHeap || isFirstTimerInHeap)
- updateSharedTimer();
+ threadGlobalData().threadTimers().updateSharedTimer();
}
checkConsistency();
}
-void TimerBase::collectFiringTimers(double fireTime, Vector<TimerBase*>& firingTimers)
-{
- while (!timerHeap->isEmpty() && timerHeap->first()->m_nextFireTime <= fireTime) {
- TimerBase* timer = timerHeap->first();
- firingTimers.append(timer);
- timersReadyToFire->add(timer);
- timer->m_nextFireTime = 0;
- timer->heapDeleteMin();
- }
-}
-
-void TimerBase::fireTimers(double fireTime, const Vector<TimerBase*>& firingTimers)
-{
- int size = firingTimers.size();
- for (int i = 0; i != size; ++i) {
- TimerBase* timer = firingTimers[i];
-
- // If not in the set, this timer has been deleted or re-scheduled in another timer's fired function.
- // So either we don't want to fire it at all or we will fire it next time the shared timer goes off.
- // It might even have been deleted; that's OK because we won't do anything else with the pointer.
- if (!timersReadyToFire->contains(timer))
- continue;
-
- // Setting the next fire time has a side effect of removing the timer from the firing timers set.
- double interval = timer->repeatInterval();
- timer->setNextFireTime(interval ? fireTime + interval : 0);
-
- // Once the timer has been fired, it may be deleted, so do nothing else with it after this point.
- timer->fired();
-
- // Catch the case where the timer asked timers to fire in a nested event loop.
- if (!timersReadyToFire)
- break;
- }
-}
-
-void TimerBase::sharedTimerFired()
-{
- // Do a re-entrancy check.
- if (timersReadyToFire)
- return;
-
- double fireTime = currentTime();
- Vector<TimerBase*> firingTimers;
- HashSet<const TimerBase*> firingTimersSet;
-
- timersReadyToFire = &firingTimersSet;
-
- collectFiringTimers(fireTime, firingTimers);
- fireTimers(fireTime, firingTimers);
-
- timersReadyToFire = 0;
-
- updateSharedTimer();
-}
-
void TimerBase::fireTimersInNestedEventLoop()
{
- timersReadyToFire = 0;
- updateSharedTimer();
-}
-
-#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it
-// ----------------
-
-bool isDeferringTimers()
-{
- return deferringTimers;
-}
-
-void setDeferringTimers(bool shouldDefer)
-{
- if (shouldDefer == deferringTimers)
- return;
- deferringTimers = shouldDefer;
- updateSharedTimer();
+ // Redirect to ThreadTimers.
+ threadGlobalData().threadTimers().fireTimersInNestedEventLoop();
}
-#endif
-}
+} // namespace WebCore
diff --git a/WebCore/platform/Timer.h b/WebCore/platform/Timer.h
index a2589f7..aab52c2 100644
--- a/WebCore/platform/Timer.h
+++ b/WebCore/platform/Timer.h
@@ -27,7 +27,6 @@
#define Timer_h
#include <wtf/Noncopyable.h>
-#include <wtf/Vector.h>
namespace WebCore {
@@ -73,20 +72,13 @@ private:
void heapPop();
void heapPopMin();
- static void collectFiringTimers(double fireTime, Vector<TimerBase*>&);
- static void fireTimers(double fireTime, const Vector<TimerBase*>&);
- static void sharedTimerFired();
-
double m_nextFireTime; // 0 if inactive
double m_repeatInterval; // 0 if not repeating
int m_heapIndex; // -1 if not in heap
unsigned m_heapInsertionOrder; // Used to keep order among equal-fire-time timers
- friend void updateSharedTimer();
-#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it
- friend void setDeferringTimers(bool);
-#endif
friend class TimerHeapElement;
+ friend class ThreadTimers;
friend bool operator<(const TimerHeapElement&, const TimerHeapElement&);
};
@@ -104,13 +96,6 @@ private:
TimerFiredFunction m_function;
};
-#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it
-// Set to true to prevent any timers from firing.
-// When set back to false, timers that were deferred will fire.
-bool isDeferringTimers();
-void setDeferringTimers(bool);
-#endif
-
}
#endif
diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h
index 6684eb2..459d615 100644
--- a/WebCore/platform/Widget.h
+++ b/WebCore/platform/Widget.h
@@ -142,7 +142,6 @@ public:
virtual void setFocus();
void setCursor(const Cursor&);
- Cursor cursor();
virtual void show();
virtual void hide();
@@ -198,7 +197,7 @@ private:
IntRect m_frame; // Not used when a native widget exists.
-#if PLATFORM(MAC) || PLATFORM(GTK)
+#if PLATFORM(MAC)
WidgetPrivate* m_data;
#endif
#if PLATFORM(ANDROID)
diff --git a/WebCore/platform/android/FileChooserAndroid.cpp b/WebCore/platform/android/FileChooserAndroid.cpp
index a8c4150..ec1b758 100644
--- a/WebCore/platform/android/FileChooserAndroid.cpp
+++ b/WebCore/platform/android/FileChooserAndroid.cpp
@@ -32,9 +32,8 @@ namespace WebCore {
String FileChooser::basenameForWidth(const Font& font, int width) const
{
- if (m_filenames.size() == 0) {
+ if (!m_filenames.size())
return String();
- }
// FIXME: This could be a lot faster, but assuming the data will not
// often be much longer than the provided width, this may be fast enough.
String output = m_filenames[0].copy();
diff --git a/WebCore/platform/android/FileSystemAndroid.cpp b/WebCore/platform/android/FileSystemAndroid.cpp
index fcb0413..f2665a2 100644
--- a/WebCore/platform/android/FileSystemAndroid.cpp
+++ b/WebCore/platform/android/FileSystemAndroid.cpp
@@ -29,6 +29,7 @@
#include "FileSystem.h"
#include "CString.h"
+#include "StringBuilder.h"
#include <fnmatch.h>
#include <dlfcn.h>
#include <dirent.h>
@@ -42,7 +43,8 @@ namespace WebCore {
// This is set in WebSettings.cpp
String sPluginPath;
-CString fileSystemRepresentation(const String& path) {
+CString fileSystemRepresentation(const String& path)
+{
return path.utf8();
}
@@ -51,19 +53,20 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
int number = rand() % 10000 + 1;
CString filename;
do {
- String path = sPluginPath;
- path.append("/");
- path.append(prefix);
- path.append(String::number(number));
- filename = path.utf8();
- const char *fstr = filename.data();
+ StringBuilder builder;
+ builder.append(sPluginPath);
+ builder.append('/');
+ builder.append(prefix);
+ builder.append(String::number(number));
+ filename = builder.toString().utf8();
+ const char* fstr = filename.data();
handle = open(filename.data(), O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
number++;
- } while (handle == -1 && errno == EEXIST);
+
+ if (handle != -1)
+ return filename;
+ } while (errno == EEXIST);
- if (handle != -1) {
- return filename;
- }
return CString();
}
@@ -84,7 +87,7 @@ int writeToFile(PlatformFileHandle handle, const char* data, int length)
{
int totalBytesWritten = 0;
while (totalBytesWritten < length) {
- int bytesWritten = write(handle, data, length - totalBytesWritten);
+ int bytesWritten = write(handle, data, (size_t)(length - totalBytesWritten));
if (bytesWritten < 0 && errno != EINTR)
return -1;
else if (bytesWritten > 0)
@@ -94,13 +97,11 @@ int writeToFile(PlatformFileHandle handle, const char* data, int length)
return totalBytesWritten;
}
-// new as of SVN change 36269, Sept 8, 2008
String homeDirectoryPath()
{
return sPluginPath;
}
-// new as of webkit4, Feb 28, 2009
Vector<String> listDirectory(const String& path, const String& filter)
{
Vector<String> entries;
@@ -108,15 +109,13 @@ Vector<String> listDirectory(const String& path, const String& filter)
CString cfilter = filter.utf8();
DIR* dir = opendir(cpath.data());
if (dir) {
- struct dirent * dp;
- while ((dp = readdir(dir)) != NULL) {
+ struct dirent* dp;
+ while (dp = readdir(dir)) {
const char* name = dp->d_name;
- if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+ if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
- }
- if (fnmatch(cfilter.data(), name, 0) != 0) {
+ if (fnmatch(cfilter.data(), name, 0))
continue;
- }
char filePath[1024];
if ((int) (sizeof(filePath) - 1) < snprintf(filePath,
sizeof(filePath), "%s/%s", cpath.data(), name)) {
@@ -129,4 +128,4 @@ Vector<String> listDirectory(const String& path, const String& filter)
return entries;
}
-}
+} // namespace WebCore
diff --git a/WebCore/platform/android/KeyEventAndroid.cpp b/WebCore/platform/android/KeyEventAndroid.cpp
index 5496bbc..ab848bd 100644
--- a/WebCore/platform/android/KeyEventAndroid.cpp
+++ b/WebCore/platform/android/KeyEventAndroid.cpp
@@ -1,5 +1,10 @@
/*
* Copyright 2007, The Android Open Source Project
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,7 +38,8 @@
namespace WebCore {
// compare to same function in gdk/KeyEventGdk.cpp
-static int windowsKeyCodeForKeyEvent(unsigned int keyCode) {
+static int windowsKeyCodeForKeyEvent(unsigned int keyCode)
+{
// Does not provide all key codes, and does not handle all keys.
switch(keyCode) {
case kKeyCodeDel:
@@ -190,7 +196,7 @@ static String keyIdentifierForAndroidKeyCode(int keyCode)
}
}
-static inline String singleCharacterString(int c)
+static inline String singleCharacterString(UChar32 c)
{
if (!c)
return String();
@@ -215,10 +221,10 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(int keyCode, UChar32 unichar,
, m_windowsVirtualKeyCode(windowsKeyCodeForKeyEvent(keyCode))
, m_nativeVirtualKeyCode(keyCode)
, m_isKeypad(false)
- , m_shiftKey((mods & ShiftKey) != 0)
- , m_ctrlKey((mods & CtrlKey) != 0)
- , m_altKey((mods & AltKey) != 0)
- , m_metaKey((mods & MetaKey) != 0)
+ , m_shiftKey((mods & ShiftKey))
+ , m_ctrlKey((mods & CtrlKey))
+ , m_altKey((mods & AltKey))
+ , m_metaKey((mods & MetaKey))
// added for android
, m_repeatCount(repeatCount)
, m_unichar(unichar)
diff --git a/WebCore/platform/android/LocalizedStringsAndroid.cpp b/WebCore/platform/android/LocalizedStringsAndroid.cpp
index 02f135f..07cf229 100644
--- a/WebCore/platform/android/LocalizedStringsAndroid.cpp
+++ b/WebCore/platform/android/LocalizedStringsAndroid.cpp
@@ -27,6 +27,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define LOG_TAG "WebCore"
+
#include "config.h"
#include "LocalizedStrings.h"
@@ -35,14 +37,16 @@
namespace WebCore {
+// *** The following strings should be localized *** //
+
String contextMenuItemTagInspectElement()
{
- return String::fromUTF8("Inspect Element");
+ return String("Inspect Element");
}
String unknownFileSizeText()
{
- return String::fromUTF8("Unknown");
+ return String("Unknown");
}
String imageTitle(const String& filename, const IntSize& size)
@@ -51,4 +55,254 @@ String imageTitle(const String& filename, const IntSize& size)
return String();
}
+// The following functions are used to fetch localized text for HTML form
+// elements submit and reset. These strings are used when the page author
+// has not specified any text for these buttons.
+String submitButtonDefaultLabel()
+{
+ verifiedOk();
+ return String("Submit");
+}
+
+String resetButtonDefaultLabel()
+{
+ verifiedOk();
+ return String("Reset");
+}
+
+// The alt text for an input element is not used visually, but rather is
+// used for accessability - eg reading the web page. See
+// HTMLInputElement::altText() for more information.
+String inputElementAltText()
+{
+ notImplemented();
+ return String();
+}
+
+// This is the string that appears before an input box when the HTML element
+// <ISINDEX> is used. The returned string is used if no PROMPT attribute is
+// provided.
+// note: Safari and FireFox use (too long for us imho) "This is a searchable index. Enter search keywords:"
+String searchableIndexIntroduction()
+{
+ verifiedOk();
+ return String("Enter search:");
+}
+
+String contextMenuItemTagOpenLinkInNewWindow()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagDownloadLinkToDisk()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagCopyLinkToClipboard()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagOpenImageInNewWindow()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagDownloadImageToDisk()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagCopyImageToClipboard()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagOpenFrameInNewWindow()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagCopy()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagGoBack()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagGoForward()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagStop()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagReload()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagCut()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagPaste()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagNoGuessesFound()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagIgnoreSpelling()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagLearnSpelling()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagSearchWeb()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagLookUpInDictionary()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagOpenLink()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagIgnoreGrammar()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagSpellingMenu()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagShowSpellingPanel(bool)
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagCheckSpelling()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagCheckSpellingWhileTyping()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagCheckGrammarWithSpelling()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagFontMenu()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagBold()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagItalic()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagUnderline()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagOutline()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagWritingDirectionMenu()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagDefaultDirection()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagLeftToRight()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagRightToLeft()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String contextMenuItemTagTextDirectionMenu()
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/android/PopupMenuAndroid.cpp b/WebCore/platform/android/PopupMenuAndroid.cpp
index 4d1fe04..8a1ed07 100644
--- a/WebCore/platform/android/PopupMenuAndroid.cpp
+++ b/WebCore/platform/android/PopupMenuAndroid.cpp
@@ -39,7 +39,6 @@ PopupMenu::~PopupMenu()
void PopupMenu::show(const IntRect&, FrameView*, int)
{
-
}
void PopupMenu::hide()
diff --git a/WebCore/platform/android/RenderThemeAndroid.cpp b/WebCore/platform/android/RenderThemeAndroid.cpp
index e104c8e..a1e8bf6 100644
--- a/WebCore/platform/android/RenderThemeAndroid.cpp
+++ b/WebCore/platform/android/RenderThemeAndroid.cpp
@@ -26,28 +26,33 @@
#include "config.h"
#include "RenderThemeAndroid.h"
+#include "Color.h"
+#include "FormControlElement.h"
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContext.h"
#include "RenderSkinAndroid.h"
#include "RenderSkinButton.h"
#include "RenderSkinCombo.h"
#include "RenderSkinRadio.h"
-
-#include "GraphicsContext.h"
-#include "PlatformGraphicsContext.h"
-
#include "SkCanvas.h"
-#define MAX_COMBO_HEIGHT 20
+namespace WebCore {
+
+const int MAX_COMBO_HEIGHT = 20;
-// Add a constant amount of padding to the textsize to get the final height of buttons,
-// so that our button images are large enough to properly fit the text.
-#define BUTTON_PADDING 18
+// Add a constant amount of padding to the textsize to get the final height
+// of buttons, so that our button images are large enough to properly fit
+// the text.
+const int BUTTON_PADDING = 18;
// Add padding to the fontSize of ListBoxes to get their maximum sizes.
-// Listboxes often have a specified size. Since we change them into dropdowns,
-// we want a much smaller height, which encompasses the text.
-#define LISTBOX_PADDING 5
+// Listboxes often have a specified size. Since we change them into
+// dropdowns, we want a much smaller height, which encompasses the text.
+const int LISTBOX_PADDING = 5;
-namespace WebCore {
+// This is the color of selection in a textfield. It was obtained by checking
+// the color of selection in TextViews in the system.
+const RGBA32 SELECTION_COLOR = makeRGB(255, 146, 0);
static SkCanvas* getCanvasFromInfo(const RenderObject::PaintInfo& info)
{
@@ -72,10 +77,10 @@ void RenderThemeAndroid::close()
{
}
-bool RenderThemeAndroid::stateChanged(RenderObject* o, ControlState state) const
+bool RenderThemeAndroid::stateChanged(RenderObject* obj, ControlState state) const
{
if (CheckedState == state) {
- o->repaint();
+ obj->repaint();
return true;
}
return false;
@@ -83,12 +88,12 @@ bool RenderThemeAndroid::stateChanged(RenderObject* o, ControlState state) const
Color RenderThemeAndroid::platformActiveSelectionBackgroundColor() const
{
- return Color(46, 251, 0);
+ return Color(SELECTION_COLOR);
}
Color RenderThemeAndroid::platformInactiveSelectionBackgroundColor() const
{
- return Color(255, 255, 0, 255);
+ return Color(Color::transparent);
}
Color RenderThemeAndroid::platformActiveSelectionForegroundColor() const
@@ -103,7 +108,7 @@ Color RenderThemeAndroid::platformInactiveSelectionForegroundColor() const
Color RenderThemeAndroid::platformTextSearchHighlightColor() const
{
- return Color(192, 192, 192);
+ return Color(Color::transparent);
}
int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const
@@ -145,18 +150,18 @@ void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const
bool RenderThemeAndroid::supportsFocus(ControlPart appearance)
{
switch (appearance) {
- case PushButtonPart:
- case ButtonPart:
- case TextFieldPart:
- return true;
- default:
- return false;
+ case PushButtonPart:
+ case ButtonPart:
+ case TextFieldPart:
+ return true;
+ default:
+ return false;
}
return false;
}
-void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
+void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
{
// Padding code is taken from RenderThemeSafari.cpp
// It makes sure we have enough space for the button text.
@@ -166,29 +171,30 @@ void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector* selector, RenderSty
style->setMinHeight(Length(style->fontSize() + BUTTON_PADDING, Fixed));
}
-bool RenderThemeAndroid::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+bool RenderThemeAndroid::paintCheckbox(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
{
- RenderSkinRadio::Draw(getCanvasFromInfo(i), o->element(), ir, true);
+ RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, true);
return false;
}
-bool RenderThemeAndroid::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+bool RenderThemeAndroid::paintButton(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
{
// If it is a disabled button, simply paint it to the master picture.
- Node* element = o->element();
- if (!element->isEnabled()) {
- RenderSkinButton::Draw(getCanvasFromInfo(i), ir, RenderSkinAndroid::kDisabled);
- } else {
+ Node* node = obj->node();
+ FormControlElement* formControlElement = toFormControlElement(static_cast<Element*>(node));
+ if (formControlElement && !formControlElement->isEnabled())
+ RenderSkinButton::Draw(getCanvasFromInfo(info), rect, RenderSkinAndroid::kDisabled);
+ else
// Store all the important information in the platform context.
- i.context->platformContext()->storeButtonInfo(element, ir);
- }
+ info.context->platformContext()->storeButtonInfo(node, rect);
+
// We always return false so we do not request to be redrawn.
return false;
}
-bool RenderThemeAndroid::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+bool RenderThemeAndroid::paintRadio(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
{
- RenderSkinRadio::Draw(getCanvasFromInfo(i), o->element(), ir, false);
+ RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, false);
return false;
}
@@ -204,74 +210,85 @@ void RenderThemeAndroid::setRadioSize(RenderStyle* style) const
setCheckboxSize(style);
}
-void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
+void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
{
addIntrinsicMargins(style);
}
-bool RenderThemeAndroid::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+bool RenderThemeAndroid::paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&)
{
return true;
}
-void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
+void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
{
addIntrinsicMargins(style);
}
-bool RenderThemeAndroid::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
{
- if (o->isMenuList()) {
- return paintCombo(o, i, ir);
- }
+ if (obj->isMenuList())
+ return paintCombo(obj, info, rect);
return true;
}
-void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
addIntrinsicMargins(style);
}
-bool RenderThemeAndroid::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+bool RenderThemeAndroid::paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&)
{
return true;
}
-void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
style->setMaxHeight(Length(style->fontSize() + LISTBOX_PADDING, Fixed));
addIntrinsicMargins(style);
}
-void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+static void adjustMenuListStyleCommon(RenderStyle* style, Element* e)
{
+ // Added to make room for our arrow.
style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
+ // Code copied from RenderThemeMac.mm
+ // Makes sure that the text shows up on our treatment
+ bool isEnabled = true;
+ if (FormControlElement* formControlElement = toFormControlElement(e))
+ isEnabled = formControlElement->isEnabled();
+ style->setColor(isEnabled ? Color::black : Color::darkGray);
+}
+
+void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
+{
+ adjustMenuListStyleCommon(style, e);
addIntrinsicMargins(style);
}
-bool RenderThemeAndroid::paintCombo(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+bool RenderThemeAndroid::paintCombo(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
{
- if (o->style() && o->style()->backgroundColor().alpha() == 0)
+ if (obj->style() && !obj->style()->backgroundColor().alpha())
return true;
- Node* element = o->element();
- int height = ir.height();
- int y = ir.y();
+ Node* node = obj->node();
+ int height = rect.height();
+ int y = rect.y();
// If the combo box is too large, leave it at its max height, and center it.
if (height > MAX_COMBO_HEIGHT) {
y += (height - MAX_COMBO_HEIGHT) >> 1;
height = MAX_COMBO_HEIGHT;
}
- return RenderSkinCombo::Draw(getCanvasFromInfo(i), element, ir.x(), y,
- ir.width(), height);
+ return RenderSkinCombo::Draw(getCanvasFromInfo(info), node, rect.x(), y,
+ rect.width(), height);
}
-bool RenderThemeAndroid::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
{
- return paintCombo(o, i, ir);
+ return paintCombo(obj, info, rect);
}
-void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
{
// Copied from RenderThemeSafari.
const float baseFontSize = 11.0f;
@@ -289,30 +306,29 @@ void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector* selector, R
const int padding = 4;
style->setPaddingTop(Length(padding, Fixed));
style->setPaddingLeft(Length(padding, Fixed));
- // Added to make room for our arrow.
- style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
+ adjustMenuListStyleCommon(style, e);
}
-bool RenderThemeAndroid::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
{
- return paintCombo(o, i, ir);
+ return paintCombo(obj, info, rect);
}
bool RenderThemeAndroid::supportsFocusRing(const RenderStyle* style) const
{
- return (style->opacity() > 0 && style->hasAppearance()
- && style->appearance() != TextFieldPart
- && style->appearance() != SearchFieldPart
- && style->appearance() != TextAreaPart
- && style->appearance() != CheckboxPart
- && style->appearance() != RadioPart
- && style->appearance() != PushButtonPart
- && style->appearance() != SquareButtonPart
- && style->appearance() != ButtonPart
- && style->appearance() != ButtonBevelPart
- && style->appearance() != MenulistPart
- && style->appearance() != MenulistButtonPart
- );
-}
-
-}
+ return style->opacity() > 0
+ && style->hasAppearance()
+ && style->appearance() != TextFieldPart
+ && style->appearance() != SearchFieldPart
+ && style->appearance() != TextAreaPart
+ && style->appearance() != CheckboxPart
+ && style->appearance() != RadioPart
+ && style->appearance() != PushButtonPart
+ && style->appearance() != SquareButtonPart
+ && style->appearance() != ButtonPart
+ && style->appearance() != ButtonBevelPart
+ && style->appearance() != MenulistPart
+ && style->appearance() != MenulistButtonPart;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/android/RenderThemeAndroid.h b/WebCore/platform/android/RenderThemeAndroid.h
index 3b6e9cb..056b2d6 100644
--- a/WebCore/platform/android/RenderThemeAndroid.h
+++ b/WebCore/platform/android/RenderThemeAndroid.h
@@ -35,7 +35,11 @@ class RenderSkinRadio;
class RenderSkinCombo;
struct ThemeData {
- ThemeData() :m_part(0), m_state(0) {}
+ ThemeData()
+ : m_part(0)
+ , m_state(0)
+ {
+ }
unsigned m_part;
unsigned m_state;
@@ -48,7 +52,7 @@ public:
virtual bool stateChanged(RenderObject*, ControlState) const;
- virtual bool supportsFocusRing(const RenderStyle* style) const;
+ virtual bool supportsFocusRing(const RenderStyle*) const;
// A method asking if the theme's controls actually care about redrawing when hovered.
virtual bool supportsHover(const RenderStyle* style) const { return style->affectedByHoverRules(); }
@@ -65,38 +69,38 @@ public:
virtual int minimumMenuListSize(RenderStyle*) const { return 0; }
protected:
- virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
- virtual void setCheckboxSize(RenderStyle* style) const;
+ virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void setCheckboxSize(RenderStyle*) const;
- virtual bool paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
- virtual void setRadioSize(RenderStyle* style) const;
+ virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void setRadioSize(RenderStyle*) const;
- virtual void adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const;
- virtual bool paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+ virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, WebCore::Element*) const;
+ virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const;
- virtual bool paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+ virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, WebCore::Element*) const;
+ virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const;
- virtual bool paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+ virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, WebCore::Element*) const;
+ virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- bool paintCombo(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir);
+ bool paintCombo(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustListboxStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const;
- virtual void adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const;
- virtual bool paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+ virtual void adjustListboxStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const;
- virtual bool paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+ virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
private:
- void addIntrinsicMargins(RenderStyle* style) const;
+ void addIntrinsicMargins(RenderStyle*) const;
void close();
- bool supportsFocus(ControlPart appearance);
+ bool supportsFocus(ControlPart);
};
} // namespace WebCore
diff --git a/WebCore/platform/android/ScrollViewAndroid.cpp b/WebCore/platform/android/ScrollViewAndroid.cpp
index 5622d8b..a59faf3 100644
--- a/WebCore/platform/android/ScrollViewAndroid.cpp
+++ b/WebCore/platform/android/ScrollViewAndroid.cpp
@@ -28,6 +28,7 @@
#include "ScrollView.h"
#include "FloatRect.h"
+#include "Frame.h"
#include "FrameView.h"
#include "IntRect.h"
#include "WebCoreFrameBridge.h"
@@ -67,9 +68,13 @@ IntSize ScrollView::platformContentsSize() const
void ScrollView::platformSetScrollPosition(const WebCore::IntPoint& pt)
{
- if (parent()) // don't attempt to scroll subframes; they're fully visible
+ android::WebViewCore* webviewCore = android::WebViewCore::getWebViewCore(this);
+ // don't attempt to scroll subframes; they're fully visible.
+ // as this can be called before the view is added to the parent in iframe
+ // creation, we can't depend on parent() checking.
+ if (webviewCore->mainFrame()->view() != this)
return;
- android::WebViewCore::getWebViewCore(this)->scrollTo(pt.x(), pt.y());
+ webviewCore->scrollTo(pt.x(), pt.y());
}
void ScrollView::platformScrollbarModes(ScrollbarMode& h, ScrollbarMode& v) const
@@ -98,7 +103,10 @@ void ScrollView::platformRepaintContentRectangle(const IntRect &rect, bool now)
#ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
void ScrollView::platformOffscreenContentRectangle(const IntRect& rect)
{
- android::WebViewCore::getWebViewCore(this)->offInvalidate(rect);
+ android::WebViewCore* core = android::WebViewCore::getWebViewCore(this);
+ if (!core)
+ return;
+ core->offInvalidate(rect);
}
#endif
diff --git a/WebCore/platform/android/SystemTimeAndroid.cpp b/WebCore/platform/android/SystemTimeAndroid.cpp
index a9c862a..1ecbfc7 100644
--- a/WebCore/platform/android/SystemTimeAndroid.cpp
+++ b/WebCore/platform/android/SystemTimeAndroid.cpp
@@ -31,7 +31,7 @@ namespace WebCore {
float userIdleTime()
{
// Needed for PageCache, which we currently have disabled.
- return 0.0F;
+ return 0.0f;
}
} // namespace WebCore
diff --git a/WebCore/platform/android/TemporaryLinkStubs.cpp b/WebCore/platform/android/TemporaryLinkStubs.cpp
index 5d71dd0..446b078 100644
--- a/WebCore/platform/android/TemporaryLinkStubs.cpp
+++ b/WebCore/platform/android/TemporaryLinkStubs.cpp
@@ -41,7 +41,6 @@
#include "CString.h"
#include "Cursor.h"
#include "Database.h"
-//#include "DebuggerCallFrame.h"
#include "DocumentFragment.h"
#include "DocumentLoader.h"
#include "EditCommand.h"
@@ -61,12 +60,15 @@
#include "IconDatabase.h"
#include "IconLoader.h"
#include "IntPoint.h"
+
+#if USE(JSC)
#include "JavaScriptCallFrame.h"
#include "JavaScriptDebugServer.h"
#include "API/JSClassRef.h"
-#include "JavaScriptCallFrame.h"
#include "JavaScriptProfile.h"
#include "jni_utility.h"
+#endif
+
#include "KURL.h"
#include "Language.h"
#include "loader.h"
@@ -90,14 +92,6 @@
using namespace WebCore;
-// This function is called when the frame view has changed the state of it's border.
-// iFrames, which are have a FrameView, are drawn with a 1px left/right border and 2px top/bottom border
-// Check function _shouldDrawBorder in WebFrameView.mm
-// We don't draw borders unless css draws them.
-//void FrameView::updateBorder() { verifiedOk(); }
-//int WebCore::screenDepthPerComponent(Widget*) { ASSERT(0); notImplemented(); return 0; }
-//bool WebCore::screenIsMonochrome(Widget*) { ASSERT(0); notImplemented(); return false; }
-
/********************************************************/
/* Completely empty stubs (mostly to allow DRT to run): */
/********************************************************/
@@ -124,7 +118,7 @@ namespace WebCore {
// of a plugin can be used to render a mimetype that is not native to the browser.
PluginInfo* PluginInfoStore::createPluginInfoForPluginAtIndex(unsigned)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
return 0;
}
@@ -157,7 +151,7 @@ void refreshPlugins(bool)
// the app may update progress with the amount of data loaded.
void CheckCacheObjectStatus(DocLoader*, CachedResource*)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
@@ -168,42 +162,6 @@ void CheckCacheObjectStatus(DocLoader*, CachedResource*)
Icon::~Icon() { }
void Icon::paint(GraphicsContext*, const IntRect&) { }
-// *** The following strings should be localized *** //
-
-// The following functions are used to fetch localized text for HTML form
-// elements submit and reset. These strings are used when the page author
-// has not specified any text for these buttons.
-String submitButtonDefaultLabel()
-{
- verifiedOk();
- return "Submit";
-}
-
-String resetButtonDefaultLabel()
-{
- verifiedOk();
- return "Reset";
-}
-
-// The alt text for an input element is not used visually, but rather is
-// used for accessability - eg reading the web page. See
-// HTMLInputElement::altText() for more information.
-String inputElementAltText()
-{
- notImplemented();
- return String();
-}
-
-// This is the string that appears before an input box when the HTML element
-// <ISINDEX> is used. The returned string is used if no PROMPT attribute is
-// provided.
-// note: Safari and FireFox use (too long for us imho) "This is a searchable index. Enter search keywords:"
-String searchableIndexIntroduction()
-{
- verifiedOk();
- return String("Enter search:");
-}
-
// This function provides the default value for the CSS property:
// -webkit-focus-ring-color
// It is also related to the CSS property outline-color:
@@ -213,223 +171,6 @@ Color focusRingColor()
return 0xFF0000FF;
}
-// LocalizedStrings
-String contextMenuItemTagOpenLinkInNewWindow()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagDownloadLinkToDisk()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagCopyLinkToClipboard()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagOpenImageInNewWindow()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagDownloadImageToDisk()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagCopyImageToClipboard()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagOpenFrameInNewWindow()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagCopy()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagGoBack()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagGoForward()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagStop()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagReload()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagCut()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagPaste()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagNoGuessesFound()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagIgnoreSpelling()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagLearnSpelling()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagSearchWeb()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagLookUpInDictionary()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagOpenLink()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagIgnoreGrammar()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagSpellingMenu()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagShowSpellingPanel(bool)
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagCheckSpelling()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagCheckSpellingWhileTyping()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagCheckGrammarWithSpelling()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagFontMenu()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagBold()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagItalic()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagUnderline()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagOutline()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagWritingDirectionMenu()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagDefaultDirection()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagLeftToRight()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagRightToLeft()
-{
- ASSERT(0);
- return String();
-}
-
-String contextMenuItemTagTextDirectionMenu()
-{
- ASSERT(0);
- return String();
-}
-
} // namespace WebCore
// FIXME, no support for spelling yet.
@@ -484,126 +225,126 @@ Pasteboard::~Pasteboard()
ContextMenu::ContextMenu(const HitTestResult& result) : m_hitTestResult(result)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
ContextMenu::~ContextMenu()
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
void ContextMenu::appendItem(ContextMenuItem&)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
void ContextMenu::setPlatformDescription(PlatformMenuDescription menu)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
m_platformDescription = menu;
}
PlatformMenuDescription ContextMenu::platformDescription() const
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
return m_platformDescription;
}
ContextMenuItem::ContextMenuItem(PlatformMenuItemDescription)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
ContextMenuItem::ContextMenuItem(ContextMenu*)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
ContextMenuItem::ContextMenuItem(ContextMenuItemType, ContextMenuAction, const String&, ContextMenu*)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
ContextMenuItem::~ContextMenuItem()
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription()
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
return m_platformDescription;
}
ContextMenuItemType ContextMenuItem::type() const
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
return ActionType;
}
void ContextMenuItem::setType(ContextMenuItemType)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
ContextMenuAction ContextMenuItem::action() const
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
return ContextMenuItemTagNoAction;
}
void ContextMenuItem::setAction(ContextMenuAction)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
String ContextMenuItem::title() const
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
return String();
}
void ContextMenuItem::setTitle(const String&)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
PlatformMenuDescription ContextMenuItem::platformSubMenu() const
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
return 0;
}
void ContextMenuItem::setSubMenu(ContextMenu*)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
void ContextMenuItem::setChecked(bool)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
void ContextMenuItem::setEnabled(bool)
{
- ASSERT(0);
+ ASSERT_NOT_REACHED();
notImplemented();
}
@@ -614,16 +355,6 @@ void systemBeep()
notImplemented();
}
-// functions new to Jun-07 tip of tree merge:
-
-// void WebCore::CachedPage::close() {}
-
-//void WebCore::Frame::print() {}
-// void WebCore::Frame::issueTransposeCommand() {}
-//void WebCore::Frame::cleanupPlatformScriptObjects() {}
-// void WebCore::Frame::dashboardRegionsChanged() {}
-//bool WebCore::Frame::isCharacterSmartReplaceExempt(unsigned short, bool) { return false; }
-
void* WebCore::Frame::dragImageForSelection()
{
return 0;
@@ -641,7 +372,7 @@ namespace WebCore {
IntSize dragImageSize(void*)
{
- return IntSize(0, 0);
+ return IntSize();
}
void deleteDragImage(void*) {}
@@ -709,13 +440,6 @@ String signedPublicKeyAndChallengeString(unsigned int, String const&, WebCore::K
} // namespace WebCore
-// added for Nov-16-07 ToT integration
-//namespace WebCore {
-//void Frame::clearPlatformScriptObjects() { notImplemented(); }
-
-//}
-
-// functions new to Feb-19 tip of tree merge:
namespace WebCore {
// isCharacterSmartReplaceExempt is defined in SmartReplaceICU.cpp; in theory, we could use that one
// but we don't support all of the required icu functions
@@ -729,7 +453,6 @@ bool isCharacterSmartReplaceExempt(UChar32, bool)
int MakeDataExecutable;
-// functions new to Mar-2 tip of tree merge:
String KURL::fileSystemPath() const
{
notImplemented();
@@ -737,7 +460,6 @@ String KURL::fileSystemPath() const
}
-// functions new to Jun-1 tip of tree merge:
PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&)
{
notImplemented();
@@ -745,6 +467,7 @@ PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&)
}
+#if USE(JSC)
namespace JSC { namespace Bindings {
bool dispatchJNICall(ExecState*, const void* targetAppletView, jobject obj, bool isStatic, JNIType returnType,
jmethodID methodID, jvalue* args, jvalue& result, const char* callingURL, JSValuePtr& exceptionDescription)
@@ -754,6 +477,7 @@ bool dispatchJNICall(ExecState*, const void* targetAppletView, jobject obj, bool
}
} } // namespace Bindings
+#endif
char* dirname(const char*)
{
@@ -761,14 +485,6 @@ char* dirname(const char*)
return 0;
}
- // new as of SVN change 36269, Sept 8, 2008
-const String& Database::databaseInfoTableName()
-{
- notImplemented();
- static const String dummy;
- return dummy;
-}
-
// new as of SVN change 38068, Nov 5, 2008
namespace WebCore {
void prefetchDNS(const String&)
@@ -839,6 +555,7 @@ void AXObjectCache::remove(RenderObject*)
notImplemented();
}
+#if USE(JSC)
using namespace JSC;
@@ -962,3 +679,4 @@ void JavaScriptDebugServer::willExecuteProgram(const DebuggerCallFrame&, int, in
{
notImplemented();
}
+#endif
diff --git a/WebCore/platform/android/TextBoundaries.cpp b/WebCore/platform/android/TextBoundaries.cpp
deleted file mode 100644
index 457a36e..0000000
--- a/WebCore/platform/android/TextBoundaries.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2009, The Android Open Source Project
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "TextBoundaries.h"
-
-#include <unicode/ubrk.h>
-
-#include "TextBreakIterator.h"
-
-namespace WebCore {
-
-int findNextWordFromIndex(const UChar* chars, int len, int position, bool forward)
-{
- UBreakIterator* it = wordBreakIterator(chars, len);
-
- int newPosition = position;
-
- if (forward) {
- position = ubrk_following(it, position);
- while (position != UBRK_DONE) {
- // We stop searching when the character preceeding the break
- // is alphanumeric.
- if (position < len && u_isalnum(chars[position - 1]))
- return position;
-
- position = ubrk_following(it, position);
- }
-
- return len;
- } else {
- position = ubrk_preceding(it, position);
- while (position != UBRK_DONE) {
- // We stop searching when the character following the break
- // is alphanumeric.
- if (position > 0 && u_isalnum(chars[position]))
- return position;
-
- position = ubrk_preceding(it, position);
- }
-
- return 0;
- }
-}
-
-void findWordBoundary(const UChar* chars, int len, int position, int* start, int* end)
-{
- UBreakIterator* it = wordBreakIterator(chars, len);
- *end = ubrk_following(it, position);
- if (*end < 0)
- *end = ubrk_last(it);
- *start = ubrk_previous(it);
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/android/WidgetAndroid.cpp b/WebCore/platform/android/WidgetAndroid.cpp
index 84ab26c..fcfea2e 100644
--- a/WebCore/platform/android/WidgetAndroid.cpp
+++ b/WebCore/platform/android/WidgetAndroid.cpp
@@ -51,7 +51,7 @@ IntRect Widget::frameRect() const
{
// FIXME: use m_frame instead?
if (!platformWidget())
- return IntRect(0, 0, 0, 0);
+ return IntRect();
return platformWidget()->getBounds();
}
@@ -118,9 +118,11 @@ int Widget::screenWidth() const
}
if (!widget)
return 0;
-
- return android::WebViewCore::getWebViewCore(
- static_cast<const ScrollView*>(widget))->screenWidth();
+ android::WebViewCore* core = android::WebViewCore::getWebViewCore(
+ static_cast<const ScrollView*>(widget));
+ if (!core)
+ return 0;
+ return core->screenWidth();
}
} // WebCore namepsace
diff --git a/WebCore/platform/animation/Animation.cpp b/WebCore/platform/animation/Animation.cpp
index 5df4480..05761f8 100644
--- a/WebCore/platform/animation/Animation.cpp
+++ b/WebCore/platform/animation/Animation.cpp
@@ -25,13 +25,13 @@
namespace WebCore {
Animation::Animation()
- : m_delay(initialAnimationDelay())
- , m_direction(initialAnimationDirection())
- , m_duration(initialAnimationDuration())
- , m_iterationCount(initialAnimationIterationCount())
- , m_name(initialAnimationName())
+ : m_name(initialAnimationName())
, m_property(initialAnimationProperty())
+ , m_iterationCount(initialAnimationIterationCount())
+ , m_delay(initialAnimationDelay())
+ , m_duration(initialAnimationDuration())
, m_timingFunction(initialAnimationTimingFunction())
+ , m_direction(initialAnimationDirection())
, m_playState(initialAnimationPlayState())
, m_delaySet(false)
, m_directionSet(false)
@@ -47,13 +47,13 @@ Animation::Animation()
Animation::Animation(const Animation& o)
: RefCounted<Animation>()
- , m_delay(o.m_delay)
- , m_direction(o.m_direction)
- , m_duration(o.m_duration)
- , m_iterationCount(o.m_iterationCount)
, m_name(o.m_name)
, m_property(o.m_property)
+ , m_iterationCount(o.m_iterationCount)
+ , m_delay(o.m_delay)
+ , m_duration(o.m_duration)
, m_timingFunction(o.m_timingFunction)
+ , m_direction(o.m_direction)
, m_playState(o.m_playState)
, m_delaySet(o.m_delaySet)
, m_directionSet(o.m_directionSet)
@@ -69,14 +69,14 @@ Animation::Animation(const Animation& o)
Animation& Animation::operator=(const Animation& o)
{
- m_delay = o.m_delay;
- m_direction = o.m_direction;
- m_duration = o.m_duration;
- m_iterationCount = o.m_iterationCount;
m_name = o.m_name;
- m_playState = o.m_playState;
m_property = o.m_property;
+ m_iterationCount = o.m_iterationCount;
+ m_delay = o.m_delay;
+ m_duration = o.m_duration;
m_timingFunction = o.m_timingFunction;
+ m_direction = o.m_direction;
+ m_playState = o.m_playState;
m_delaySet = o.m_delaySet;
m_directionSet = o.m_directionSet;
@@ -86,7 +86,6 @@ Animation& Animation::operator=(const Animation& o)
m_playStateSet = o.m_playStateSet;
m_propertySet = o.m_propertySet;
m_timingFunctionSet = o.m_timingFunctionSet;
-
m_isNone = o.m_isNone;
return *this;
@@ -101,13 +100,13 @@ bool Animation::animationsMatch(const Animation* o, bool matchPlayStates) const
if (!o)
return false;
- bool result = m_delay == o->m_delay &&
- m_direction == o->m_direction &&
- m_duration == o->m_duration &&
- m_iterationCount == o->m_iterationCount &&
- m_name == o->m_name &&
+ bool result = m_name == o->m_name &&
m_property == o->m_property &&
+ m_iterationCount == o->m_iterationCount &&
+ m_delay == o->m_delay &&
+ m_duration == o->m_duration &&
m_timingFunction == o->m_timingFunction &&
+ m_direction == o->m_direction &&
m_delaySet == o->m_delaySet &&
m_directionSet == o->m_directionSet &&
m_durationSet == o->m_durationSet &&
diff --git a/WebCore/platform/animation/Animation.h b/WebCore/platform/animation/Animation.h
index 294acdf..9e1e8e1 100644
--- a/WebCore/platform/animation/Animation.h
+++ b/WebCore/platform/animation/Animation.h
@@ -35,6 +35,12 @@ namespace WebCore {
const int cAnimateNone = 0;
const int cAnimateAll = -2;
+// These were in RenderStyle, but have been moved here as
+// animation-play-state is in the process of being removed.
+
+const unsigned AnimPlayStatePlaying = 0;
+const unsigned AnimPlayStatePaused = 1;
+
class Animation : public RefCounted<Animation> {
public:
~Animation();
@@ -77,8 +83,13 @@ public:
void clearTimingFunction() { m_timingFunctionSet = false; }
double delay() const { return m_delay; }
- bool direction() const { return m_direction; }
+
+ enum AnimationDirection { AnimationDirectionNormal, AnimationDirectionAlternate };
+ AnimationDirection direction() const { return m_direction; }
+
double duration() const { return m_duration; }
+
+ enum { IterationCountInfinite = -1 };
int iterationCount() const { return m_iterationCount; }
const String& name() const { return m_name; }
unsigned playState() const { return m_playState; }
@@ -86,7 +97,7 @@ public:
const TimingFunction& timingFunction() const { return m_timingFunction; }
void setDelay(double c) { m_delay = c; m_delaySet = true; }
- void setDirection(bool d) { m_direction = d; m_directionSet = true; }
+ void setDirection(AnimationDirection d) { m_direction = d; m_directionSet = true; }
void setDuration(double d) { ASSERT(d >= 0); m_duration = d; m_durationSet = true; }
void setIterationCount(int c) { m_iterationCount = c; m_iterationCountSet = true; }
void setName(const String& n) { m_name = n; m_nameSet = true; }
@@ -109,13 +120,13 @@ private:
Animation();
Animation(const Animation& o);
- double m_delay;
- bool m_direction;
- double m_duration;
- int m_iterationCount;
String m_name;
int m_property;
+ int m_iterationCount;
+ double m_delay;
+ double m_duration;
TimingFunction m_timingFunction;
+ AnimationDirection m_direction : 1;
unsigned m_playState : 2;
@@ -132,7 +143,7 @@ private:
public:
static float initialAnimationDelay() { return 0; }
- static bool initialAnimationDirection() { return false; }
+ static AnimationDirection initialAnimationDirection() { return AnimationDirectionNormal; }
static double initialAnimationDuration() { return 0; }
static int initialAnimationIterationCount() { return 1; }
static String initialAnimationName() { return String("none"); }
diff --git a/WebCore/platform/cf/RunLoopTimerCF.cpp b/WebCore/platform/cf/RunLoopTimerCF.cpp
new file mode 100644
index 0000000..c97dd21
--- /dev/null
+++ b/WebCore/platform/cf/RunLoopTimerCF.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 "RunLoopTimer.h"
+
+#if PLATFORM(MAC)
+
+namespace WebCore {
+
+RunLoopTimerBase::~RunLoopTimerBase()
+{
+ stop();
+}
+
+static void timerFired(CFRunLoopTimerRef, void* context)
+{
+ RunLoopTimerBase* timer = static_cast<RunLoopTimerBase*>(context);
+ timer->fired();
+}
+
+void RunLoopTimerBase::start(double nextFireInterval, double repeatInterval)
+{
+ if (m_timer)
+ CFRunLoopTimerInvalidate(m_timer.get());
+ CFRunLoopTimerContext context = { 0, this, 0, 0, 0 };
+ m_timer.adoptCF(CFRunLoopTimerCreate(0, CFAbsoluteTimeGetCurrent() + nextFireInterval, repeatInterval, 0, 0, timerFired, &context));
+}
+
+void RunLoopTimerBase::schedule(const SchedulePair* schedulePair)
+{
+ ASSERT_ARG(schedulePair, schedulePair);
+ ASSERT_WITH_MESSAGE(m_timer, "Timer must have one of the start functions called before calling schedule().");
+ CFRunLoopAddTimer(schedulePair->runLoop(), m_timer.get(), schedulePair->mode());
+}
+
+void RunLoopTimerBase::schedule(const SchedulePairHashSet& schedulePairs)
+{
+ SchedulePairHashSet::const_iterator end = schedulePairs.end();
+ for (SchedulePairHashSet::const_iterator it = schedulePairs.begin(); it != end; ++it)
+ schedule((*it).get());
+}
+
+void RunLoopTimerBase::stop()
+{
+ if (!m_timer)
+ return;
+ CFRunLoopTimerInvalidate(m_timer.get());
+ m_timer = 0;
+}
+
+bool RunLoopTimerBase::isActive() const
+{
+ return m_timer && CFRunLoopTimerIsValid(m_timer.get());
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h
index dd36c1a..3e5c404 100644
--- a/WebCore/platform/chromium/ChromiumBridge.h
+++ b/WebCore/platform/chromium/ChromiumBridge.h
@@ -92,6 +92,7 @@ namespace WebCore {
// JavaScript ---------------------------------------------------------
static void notifyJSOutOfMemory(Frame*);
+ static bool allowScriptDespiteSettings(const KURL& documentURL);
// Language -----------------------------------------------------------
static String computedDefaultLanguage();
@@ -100,11 +101,10 @@ namespace WebCore {
static bool layoutTestMode();
// MimeType -----------------------------------------------------------
- static bool isSupportedImageMIMEType(const char* mimeType);
- static bool isSupportedJavascriptMIMEType(const char* mimeType);
- static bool isSupportedNonImageMIMEType(const char* mimeType);
- static bool matchesMIMEType(const String& pattern, const String& type);
- static String mimeTypeForExtension(const String& ext);
+ static bool isSupportedImageMIMEType(const String& mimeType);
+ static bool isSupportedJavaScriptMIMEType(const String& mimeType);
+ static bool isSupportedNonImageMIMEType(const String& mimeType);
+ static String mimeTypeForExtension(const String& fileExtension);
static String mimeTypeFromFile(const String& filePath);
static String preferredExtensionForMIMEType(const String& mimeType);
@@ -114,7 +114,7 @@ namespace WebCore {
static bool popupsAllowed(NPP);
// Protocol -----------------------------------------------------------
- static String uiResourceProtocol();
+ static String uiResourceProtocol(); // deprecated
// Resources ----------------------------------------------------------
static PassRefPtr<Image> loadPlatformImageResource(const char* name);
@@ -134,7 +134,6 @@ namespace WebCore {
// StatsCounters ------------------------------------------------------
static void decrementStatsCounter(const char* name);
static void incrementStatsCounter(const char* name);
- static void initV8CounterFunction();
// SystemTime ---------------------------------------------------------
static double currentTime();
@@ -153,15 +152,14 @@ namespace WebCore {
GraphicsContext*, int part, int state, int classicState, const IntRect&, const IntRect& alignRect);
static void paintTextField(
GraphicsContext*, int part, int state, int classicState, const IntRect&, const Color&, bool fillContentArea, bool drawEdges);
+ static void paintTrackbar(
+ GraphicsContext*, int part, int state, int classicState, const IntRect&);
#endif
// Trace Event --------------------------------------------------------
static void traceEventBegin(const char* name, void* id, const char* extra);
static void traceEventEnd(const char* name, void* id, const char* extra);
- // URL ----------------------------------------------------------------
- static KURL inspectorURL();
-
// Visited links ------------------------------------------------------
static LinkHash visitedLinkHash(const UChar* url, unsigned length);
static LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL);
diff --git a/WebCore/platform/chromium/ChromiumDataObject.cpp b/WebCore/platform/chromium/ChromiumDataObject.cpp
index 67e9d00..dee4568 100644
--- a/WebCore/platform/chromium/ChromiumDataObject.cpp
+++ b/WebCore/platform/chromium/ChromiumDataObject.cpp
@@ -37,6 +37,7 @@ void ChromiumDataObject::clear()
{
url = KURL();
urlTitle = "";
+ fileExtension = "";
filenames.clear();
plainText = "";
textHtml = "";
@@ -49,6 +50,7 @@ void ChromiumDataObject::clear()
bool ChromiumDataObject::hasData()
{
return !url.isEmpty()
+ || !fileExtension.isEmpty()
|| !filenames.isEmpty()
|| !plainText.isEmpty()
|| !textHtml.isEmpty()
diff --git a/WebCore/platform/chromium/ChromiumDataObject.h b/WebCore/platform/chromium/ChromiumDataObject.h
index 448e763..19b91c4 100644
--- a/WebCore/platform/chromium/ChromiumDataObject.h
+++ b/WebCore/platform/chromium/ChromiumDataObject.h
@@ -54,6 +54,7 @@ namespace WebCore {
KURL url;
String urlTitle;
+ String fileExtension;
Vector<String> filenames;
String plainText;
diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp
index 7fc156e..b28503d 100644
--- a/WebCore/platform/chromium/ClipboardChromium.cpp
+++ b/WebCore/platform/chromium/ClipboardChromium.cpp
@@ -268,15 +268,15 @@ static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* elem
// use the alt tag if one exists, otherwise we fall back on the suggested
// filename in the http header, and finally we resort to using the filename
// in the URL.
- String extension(".");
- extension += MIMETypeRegistry::getPreferredExtensionForMIMEType(
+ String extension = MIMETypeRegistry::getPreferredExtensionForMIMEType(
cachedImage->response().mimeType());
+ dataObject->fileExtension = extension.isEmpty() ? "" : "." + extension;
String title = element->getAttribute(altAttr);
- if (title.isEmpty()) {
+ if (title.isEmpty())
title = cachedImage->response().suggestedFilename();
- // FIXME: If title is empty, get the filename from the URL.
- }
- dataObject->fileContentFilename = title + extension;
+
+ title = ClipboardChromium::validateFileName(title, dataObject);
+ dataObject->fileContentFilename = title + dataObject->fileExtension;
}
void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
diff --git a/WebCore/platform/chromium/ClipboardChromium.h b/WebCore/platform/chromium/ClipboardChromium.h
index 1864c1a..53699da 100644
--- a/WebCore/platform/chromium/ClipboardChromium.h
+++ b/WebCore/platform/chromium/ClipboardChromium.h
@@ -47,6 +47,12 @@ namespace WebCore {
static PassRefPtr<ClipboardChromium> create(
bool isForDragging, PassRefPtr<ChromiumDataObject>, ClipboardAccessPolicy);
+ // 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.
+ // This may change the file extension in dataObject.
+ static String validateFileName(const String& title, ChromiumDataObject* dataObject);
+
virtual void clearData(const String& type);
void clearAllData();
String getData(const String& type, bool& success) const;
diff --git a/WebCore/platform/chromium/ClipboardChromiumLinux.cpp b/WebCore/platform/chromium/ClipboardChromiumLinux.cpp
new file mode 100644
index 0000000..2c89f6e
--- /dev/null
+++ b/WebCore/platform/chromium/ClipboardChromiumLinux.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 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 "ClipboardChromium.h"
+
+#include "ChromiumDataObject.h"
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+String ClipboardChromium::validateFileName(const String& title, ChromiumDataObject* dataObject)
+{
+ notImplemented();
+ return title;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/chromium/ClipboardChromiumMac.cpp b/WebCore/platform/chromium/ClipboardChromiumMac.cpp
new file mode 100644
index 0000000..2c89f6e
--- /dev/null
+++ b/WebCore/platform/chromium/ClipboardChromiumMac.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 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 "ClipboardChromium.h"
+
+#include "ChromiumDataObject.h"
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+String ClipboardChromium::validateFileName(const String& title, ChromiumDataObject* dataObject)
+{
+ notImplemented();
+ return title;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/chromium/ClipboardChromiumWin.cpp b/WebCore/platform/chromium/ClipboardChromiumWin.cpp
new file mode 100644
index 0000000..b4a2c21
--- /dev/null
+++ b/WebCore/platform/chromium/ClipboardChromiumWin.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 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 "ClipboardChromium.h"
+
+#include "ChromiumDataObject.h"
+
+#include <shlwapi.h>
+
+namespace WebCore {
+
+// Returns true if the specified character is not valid in a file name. This
+// is intended for use with removeCharacters.
+static bool isInvalidFileCharacter(UChar c)
+{
+ return (PathGetCharType(c) & (GCT_LFNCHAR | GCT_SHORTCHAR)) == 0;
+}
+
+String ClipboardChromium::validateFileName(const String& title, ChromiumDataObject* dataObject)
+{
+ // 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);
+ }
+ return result;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp b/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp
index 5d6f426..1aac5ec 100644
--- a/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp
+++ b/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp
@@ -83,8 +83,7 @@ String MIMETypeRegistry::getMIMETypeForPath(const String& path)
bool MIMETypeRegistry::isSupportedImageMIMEType(const String& mimeType)
{
- return !mimeType.isEmpty()
- && ChromiumBridge::isSupportedImageMIMEType(mimeType.latin1().data());
+ return ChromiumBridge::isSupportedImageMIMEType(mimeType);
}
bool MIMETypeRegistry::isSupportedImageResourceMIMEType(const String& mimeType)
@@ -100,14 +99,12 @@ bool MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(const String& mimeTyp
bool MIMETypeRegistry::isSupportedJavaScriptMIMEType(const String& mimeType)
{
- return !mimeType.isEmpty()
- && ChromiumBridge::isSupportedJavascriptMIMEType(mimeType.latin1().data());
+ return ChromiumBridge::isSupportedJavaScriptMIMEType(mimeType);
}
bool MIMETypeRegistry::isSupportedNonImageMIMEType(const String& mimeType)
{
- return !mimeType.isEmpty()
- && ChromiumBridge::isSupportedNonImageMIMEType(mimeType.latin1().data());
+ return ChromiumBridge::isSupportedNonImageMIMEType(mimeType);
}
bool MIMETypeRegistry::isSupportedMediaMIMEType(const String& mimeType)
diff --git a/WebCore/platform/chromium/PasteboardChromium.cpp b/WebCore/platform/chromium/PasteboardChromium.cpp
index e7b2203..9b32bae 100644
--- a/WebCore/platform/chromium/PasteboardChromium.cpp
+++ b/WebCore/platform/chromium/PasteboardChromium.cpp
@@ -98,6 +98,15 @@ void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame)
void Pasteboard::writeImage(Node* node, const KURL&, const String& title)
{
+ ASSERT(node);
+ ASSERT(node->renderer());
+ ASSERT(node->renderer()->isImage());
+ RenderImage* renderer = static_cast<RenderImage*>(node->renderer());
+ CachedImage* cachedImage = static_cast<CachedImage*>(renderer->cachedImage());
+ ASSERT(cachedImage);
+ Image* image = cachedImage->image();
+ ASSERT(image);
+
// If the image is wrapped in a link, |url| points to the target of the
// link. This isn't useful to us, so get the actual image URL.
AtomicString urlString;
@@ -113,16 +122,6 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String& title)
}
KURL url = urlString.isEmpty() ? KURL() : node->document()->completeURL(parseURL(urlString));
- ASSERT(node);
- ASSERT(node->renderer());
- ASSERT(node->renderer()->isImage());
-
- RenderImage* renderer = static_cast<RenderImage*>(node->renderer());
- CachedImage* cachedImage = static_cast<CachedImage*>(renderer->cachedImage());
- ASSERT(cachedImage);
- Image* image = cachedImage->image();
- ASSERT(image);
-
NativeImageSkia* bitmap = 0;
#if !PLATFORM(CG)
bitmap = image->nativeImageForCurrentFrame();
diff --git a/WebCore/platform/chromium/PlatformKeyboardEventChromium.cpp b/WebCore/platform/chromium/PlatformKeyboardEventChromium.cpp
index 6840bdf..ae55afe 100644
--- a/WebCore/platform/chromium/PlatformKeyboardEventChromium.cpp
+++ b/WebCore/platform/chromium/PlatformKeyboardEventChromium.cpp
@@ -42,7 +42,7 @@ void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCom
#if PLATFORM(WIN_OS)
// No KeyDown events on Windows to disambiguate.
ASSERT_NOT_REACHED();
-#elif PLATFORM(DARWIN)
+#else
// Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions.
ASSERT(m_type == KeyDown);
ASSERT(type == RawKeyDown || type == Char);
@@ -56,6 +56,7 @@ void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCom
} else {
m_keyIdentifier = String();
m_windowsVirtualKeyCode = 0;
+#if PLATFORM(DARWIN)
if (m_text.length() == 1 && (m_text[0U] >= 0xF700 && m_text[0U] <= 0xF7FF)) {
// According to NSEvents.h, OpenStep reserves the range 0xF700-0xF8FF for function keys. However, some actual private use characters
// happen to be in this range, e.g. the Apple logo (Option+Shift+K).
@@ -63,6 +64,7 @@ void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCom
m_text = String();
m_unmodifiedText = String();
}
+#endif
}
#endif
}
diff --git a/WebCore/platform/chromium/PlatformWidget.h b/WebCore/platform/chromium/PlatformWidget.h
index e4e6a18..b9dddf3 100644
--- a/WebCore/platform/chromium/PlatformWidget.h
+++ b/WebCore/platform/chromium/PlatformWidget.h
@@ -31,10 +31,12 @@
#ifndef PlatformWidget_h
#define PlatformWidget_h
+#include <wtf/StdLibExtras.h> // for intptr_t
+
// PlatformWidget is an opaque identifier corresponding to whatever native
// view type the embedder may use. PlatformWidget CANNOT be assumed to be
// a valid pointer. Some embedders may not use this identifier at all.
-typedef void* PlatformWidget;
+typedef intptr_t PlatformWidget;
#endif
diff --git a/WebCore/platform/chromium/PopupMenuChromium.cpp b/WebCore/platform/chromium/PopupMenuChromium.cpp
index fad0a6b..53f565a 100644
--- a/WebCore/platform/chromium/PopupMenuChromium.cpp
+++ b/WebCore/platform/chromium/PopupMenuChromium.cpp
@@ -69,10 +69,24 @@ static const int kMaxHeight = 500;
static const int kBorderSize = 1;
static const TimeStamp kTypeAheadTimeoutMs = 1000;
+// The settings used for the drop down menu.
+// This is the delegate used if none is provided.
+static const PopupContainerSettings dropDownSettings = {
+ true, // focusOnShow
+ true, // setTextOnIndexChange
+ true, // acceptOnAbandon
+ false // loopSelectionNavigation
+};
+
// This class uses WebCore code to paint and handle events for a drop-down list
// box ("combobox" on Windows).
class PopupListBox : public FramelessScrollView, public RefCounted<PopupListBox> {
public:
+ static PassRefPtr<PopupListBox> create(PopupMenuClient* client, const PopupContainerSettings& settings)
+ {
+ return adoptRef(new PopupListBox(client, settings));
+ }
+
// FramelessScrollView
virtual void paint(GraphicsContext*, const IntRect&);
virtual bool handleMouseDownEvent(const PlatformMouseEvent&);
@@ -84,9 +98,6 @@ public:
// ScrollView
virtual HostWindow* hostWindow() const;
- // Widget
- virtual void invalidateRect(const IntRect&);
-
// PopupListBox methods
// Shows the popup
@@ -125,20 +136,6 @@ public:
// Returns whether the popup wants to process events for the passed key.
bool isInterestedInEventForKey(int keyCode);
- // Sets whether the PopupMenuClient should be told to change its text when a
- // new item is selected (by using the arrow keys). Default is true.
- void setTextOnIndexChange(bool value) { m_setTextOnIndexChange = value; }
-
- // Sets whether we should accept the selected index when the popup is
- // abandonned.
- void setAcceptOnAbandon(bool value) { m_shouldAcceptOnAbandon = value; }
-
- // Sets whether pressing the down/up arrow when the last/first row is
- // selected clears the selection on the first key press and then selects the
- // first/last row on the next key press. If false, the selected row stays
- // the last/first row.
- void setLoopSelectionNavigation(bool value) { m_loopSelectionNavigation = value; }
-
private:
friend class PopupContainer;
friend class RefCounted<PopupListBox>;
@@ -159,17 +156,15 @@ private:
int y; // y offset of this item, relative to the top of the popup.
};
- PopupListBox(PopupMenuClient* client)
- : m_originalIndex(0)
+ PopupListBox(PopupMenuClient* client, const PopupContainerSettings& settings)
+ : m_settings(settings)
+ , m_originalIndex(0)
, m_selectedIndex(0)
- , m_shouldAcceptOnAbandon(true)
, m_willAcceptOnAbandon(false)
, m_visibleRows(0)
, m_popupClient(client)
, m_repeatingChar(0)
, m_lastCharTime(0)
- , m_setTextOnIndexChange(true)
- , m_loopSelectionNavigation(false)
{
setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
}
@@ -228,6 +223,9 @@ private:
void selectPreviousRow();
void selectNextRow();
+ // The settings that specify the behavior for this Popup window.
+ PopupContainerSettings m_settings;
+
// This is the index of the item marked as "selected" - i.e. displayed in the widget on the
// page.
int m_originalIndex;
@@ -237,15 +235,10 @@ private:
// enter yet however.
int m_selectedIndex;
- // Whether we should accept the selectedIndex as chosen when the popup is
- // "abandoned". This value is set through its setter and is useful as
- // select popup menu and form autofill popup menu have different behaviors.
- bool m_shouldAcceptOnAbandon;
-
// True if we should accept the selectedIndex as chosen, even if the popup
// is "abandoned". This is used for keyboard navigation, where we want the
- // selection to change immediately, and is only used if
- // m_shouldAcceptOnAbandon is true.
+ // selection to change immediately, and is only used if the settings
+ // acceptOnAbandon field is true.
bool m_willAcceptOnAbandon;
// This is the number of rows visible in the popup. The maximum number visible at a time is
@@ -277,10 +270,6 @@ private:
// The last time the user hit a key. Used for typeAheadFind.
TimeStamp m_lastCharTime;
-
- bool m_setTextOnIndexChange;
-
- bool m_loopSelectionNavigation;
};
static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e,
@@ -316,19 +305,15 @@ static PlatformWheelEvent constructRelativeWheelEvent(const PlatformWheelEvent&
// static
PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client,
- bool focusOnShow)
+ const PopupContainerSettings& settings)
{
- return adoptRef(new PopupContainer(client, focusOnShow));
+ return adoptRef(new PopupContainer(client, settings));
}
-PopupContainer::PopupContainer(PopupMenuClient* client, bool focusOnShow)
- : m_listBox(new PopupListBox(client)),
- m_focusOnShow(focusOnShow)
+PopupContainer::PopupContainer(PopupMenuClient* client, const PopupContainerSettings& settings)
+ : m_listBox(PopupListBox::create(client, settings))
+ , m_settings(settings)
{
- // FrameViews are created with a refcount of 1 so it needs releasing after we
- // assign it to a RefPtr.
- m_listBox->deref();
-
setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
}
@@ -352,19 +337,19 @@ void PopupContainer::showPopup(FrameView* view)
if (chromeClient) {
// If the popup would extend past the bottom of the screen, open upwards
// instead.
- FloatRect screen = screenRect(view);
+ FloatRect screen = screenAvailableRect(view);
IntRect widgetRect = chromeClient->windowToScreen(frameRect());
if (widgetRect.bottom() > static_cast<int>(screen.bottom()))
widgetRect.move(0, -(widgetRect.height() + selectHeight));
- chromeClient->popupOpened(this, widgetRect, m_focusOnShow);
+ chromeClient->popupOpened(this, widgetRect, m_settings.focusOnShow);
}
- // Must get called after we have a client and containingWindow.
- addChild(m_listBox.get());
+ if (!m_listBox->parent())
+ addChild(m_listBox.get());
- // Enable scrollbars after the listbox is inserted into the hierarchy, so
- // it has a proper WidgetClient.
+ // Enable scrollbars after the listbox is inserted into the hierarchy,
+ // so it has a proper WidgetClient.
m_listBox->setVerticalScrollbarMode(ScrollbarAuto);
m_listBox->scrollToRevealSelection();
@@ -374,12 +359,6 @@ void PopupContainer::showPopup(FrameView* view)
void PopupContainer::hidePopup()
{
- invalidate();
-
- m_listBox->disconnectClient();
- removeChild(m_listBox.get());
- m_listBox = 0;
-
if (client())
client()->popupClosed(this);
}
@@ -495,27 +474,17 @@ void PopupContainer::show(const IntRect& r, FrameView* v, int index)
showPopup(v);
}
-void PopupContainer::setTextOnIndexChange(bool value)
-{
- listBox()->setTextOnIndexChange(value);
-}
-
-void PopupContainer::setAcceptOnAbandon(bool value)
-{
- listBox()->setAcceptOnAbandon(value);
-}
-
-void PopupContainer::setLoopSelectionNavigation(bool value)
-{
- listBox()->setLoopSelectionNavigation(value);
-}
-
void PopupContainer::refresh()
{
listBox()->updateFromElement();
layout();
}
+int PopupContainer::selectedIndex() const
+{
+ return m_listBox->selectedIndex();
+}
+
///////////////////////////////////////////////////////////////////////////////
// PopupListBox implementation
@@ -658,13 +627,14 @@ bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event)
// want to fire the onchange event until the popup is closed, to match
// IE). We change the original index so we revert to that when the
// popup is closed.
- if (m_shouldAcceptOnAbandon)
+ if (m_settings.acceptOnAbandon)
m_willAcceptOnAbandon = true;
setOriginalIndex(m_selectedIndex);
- if (m_setTextOnIndexChange)
+ if (m_settings.setTextOnIndexChange)
m_popupClient->setTextFromItem(m_selectedIndex);
- } else if (!m_setTextOnIndexChange && event.windowsVirtualKeyCode() == VKEY_TAB) {
+ } else if (!m_settings.setTextOnIndexChange &&
+ event.windowsVirtualKeyCode() == VKEY_TAB) {
// TAB is a special case as it should select the current item if any and
// advance focus.
if (m_selectedIndex >= 0)
@@ -683,15 +653,6 @@ HostWindow* PopupListBox::hostWindow() const
return parent() ? parent()->hostWindow() : 0;
}
-void PopupListBox::invalidateRect(const IntRect& rect)
-{
- // Since we are returning the HostWindow of our parent as our own in
- // hostWindow(), we need to invalidate in our parent's coordinates.
- IntRect newRect(rect);
- newRect.move(kBorderSize, kBorderSize);
- FramelessScrollView::invalidateRect(newRect);
-}
-
// From HTMLSelectElement.cpp
static String stripLeadingWhiteSpace(const String& string)
{
@@ -855,12 +816,10 @@ void PopupListBox::abandon()
m_selectedIndex = m_originalIndex;
+ m_popupClient->hidePopup();
+
if (m_willAcceptOnAbandon)
m_popupClient->valueChanged(m_selectedIndex);
-
- // valueChanged may have torn down the popup!
- if (m_popupClient)
- m_popupClient->hidePopup();
}
int PopupListBox::pointToRowIndex(const IntPoint& point)
@@ -892,12 +851,11 @@ void PopupListBox::acceptIndex(int index)
if (isSelectableItem(index)) {
RefPtr<PopupListBox> keepAlive(this);
- // Tell the <select> PopupMenuClient what index was selected, and hide ourself.
- m_popupClient->valueChanged(index);
+ // Hide ourselves first since valueChanged may have numerous side-effects.
+ m_popupClient->hidePopup();
- // valueChanged may have torn down the popup!
- if (m_popupClient)
- m_popupClient->hidePopup();
+ // Tell the <select> PopupMenuClient what index was selected.
+ m_popupClient->valueChanged(index);
}
}
@@ -940,7 +898,9 @@ void PopupListBox::invalidateRow(int index)
if (index < 0)
return;
- invalidateRect(getRowBounds(index));
+ // Invalidate in the window contents, as FramelessScrollView::invalidateRect
+ // paints in the window coordinates.
+ invalidateRect(contentsToWindow(getRowBounds(index)));
}
void PopupListBox::scrollToRevealRow(int index)
@@ -959,7 +919,8 @@ void PopupListBox::scrollToRevealRow(int index)
}
}
-bool PopupListBox::isSelectableItem(int index) {
+bool PopupListBox::isSelectableItem(int index)
+{
return m_items[index]->type == TypeOption && m_popupClient->itemIsEnabled(index);
}
@@ -973,7 +934,7 @@ void PopupListBox::clearSelection()
void PopupListBox::selectNextRow()
{
- if (!m_loopSelectionNavigation || m_selectedIndex != numItems() - 1) {
+ if (!m_settings.loopSelectionNavigation || m_selectedIndex != numItems() - 1) {
adjustSelectedIndex(1);
return;
}
@@ -984,7 +945,7 @@ void PopupListBox::selectNextRow()
void PopupListBox::selectPreviousRow()
{
- if (!m_loopSelectionNavigation || m_selectedIndex > 0) {
+ if (!m_settings.loopSelectionNavigation || m_selectedIndex > 0) {
adjustSelectedIndex(-1);
return;
}
@@ -1156,16 +1117,15 @@ PopupMenu::~PopupMenu()
void PopupMenu::show(const IntRect& r, FrameView* v, int index)
{
- p.popup = PopupContainer::create(client(), true);
+ if (!p.popup)
+ p.popup = PopupContainer::create(client(), dropDownSettings);
p.popup->show(r, v, index);
}
void PopupMenu::hide()
{
- if (p.popup) {
+ if (p.popup)
p.popup->hidePopup();
- p.popup = 0;
- }
}
void PopupMenu::updateFromElement()
diff --git a/WebCore/platform/chromium/PopupMenuChromium.h b/WebCore/platform/chromium/PopupMenuChromium.h
index a57383d..cd13c22 100644
--- a/WebCore/platform/chromium/PopupMenuChromium.h
+++ b/WebCore/platform/chromium/PopupMenuChromium.h
@@ -44,7 +44,7 @@ namespace WebCore {
// FIXME: Our FramelessScrollView classes should probably implement HostWindow!
- // This class holds a PopupListBox (see cpp file). Its sole purpose is to be
+ // The PopupContainer class holds a PopupListBox (see cpp file). Its sole purpose is to be
// able to draw a border around its child. All its paint/event handling is
// just forwarded to the child listBox (with the appropriate transforms).
// NOTE: this class is exposed so it can be instantiated direcly for the
@@ -52,9 +52,30 @@ namespace WebCore {
// autofill popup should not be focused when shown and we want to forward the
// key events to it (through handleKeyEvent).
+ struct PopupContainerSettings {
+ // Whether the popup should get the focus when displayed.
+ bool focusOnShow;
+
+ // Whether the PopupMenuClient should be told to change its text when a
+ // new item is selected by using the arrow keys.
+ bool setTextOnIndexChange;
+
+ // Whether the selection should be accepted when the popup menu is
+ // closed (through ESC being pressed or the focus going away).
+ // Note that when TAB is pressed, the selection is always accepted
+ // regardless of this setting.
+ bool acceptOnAbandon;
+
+ // Whether the we should move the selection to the first/last item when
+ // the user presses down/up arrow keys and the last/first item is
+ // selected.
+ bool loopSelectionNavigation;
+ };
+
class PopupContainer : public FramelessScrollView, public RefCounted<PopupContainer> {
public:
- static PassRefPtr<PopupContainer> create(PopupMenuClient*, bool focusOnShow);
+ static PassRefPtr<PopupContainer> create(PopupMenuClient*,
+ const PopupContainerSettings&);
// Whether a key event should be sent to this popup.
virtual bool isInterestedInEventForKey(int keyCode);
@@ -84,31 +105,19 @@ namespace WebCore {
// Compute size of widget and children.
void layout();
- // Sets whether the PopupMenuClient should be told to change its text when a
- // new item is selected (by using the arrow keys). Default is true.
- void setTextOnIndexChange(bool);
-
- // Sets whether the selection should be accepted when the popup menu is
- // closed (through ESC being pressed or the focus going away). Default
- // is true. Note that when TAB is pressed, the selection is always
- // accepted regardless of this setting.
- void setAcceptOnAbandon(bool);
-
- // Sets whether we should move the selection to the first/last item
- // when the user presses down/up arrow keys and the last/first item is
- // selected. Default is false, causing the first/last item to stay
- // selected.
- void setLoopSelectionNavigation(bool);
-
PopupListBox* listBox() const { return m_listBox.get(); }
+ // Gets the index of the item that the user is currently moused-over or
+ // has selected with the keyboard up/down arrows.
+ int selectedIndex() const;
+
// Refresh the popup values from the PopupMenuClient.
void refresh();
private:
friend class WTF::RefCounted<PopupContainer>;
- PopupContainer(PopupMenuClient*, bool focusOnShow);
+ PopupContainer(PopupMenuClient*, const PopupContainerSettings&);
~PopupContainer();
// Paint the border.
@@ -116,8 +125,7 @@ namespace WebCore {
RefPtr<PopupListBox> m_listBox;
- // Whether the window showing this popup should be focused when shown.
- bool m_focusOnShow;
+ PopupContainerSettings m_settings;
};
} // namespace WebCore
diff --git a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp
index de40572..426a078 100644
--- a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp
+++ b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp
@@ -96,7 +96,7 @@ IntRect ScrollbarThemeChromium::forwardButtonRect(Scrollbar* scrollbar, Scrollba
IntRect ScrollbarThemeChromium::trackRect(Scrollbar* scrollbar, bool)
{
IntSize bs = buttonSize(scrollbar);
- int thickness = scrollbarThickness();
+ int thickness = scrollbarThickness(scrollbar->controlSize());
if (scrollbar->orientation() == HorizontalScrollbar) {
if (scrollbar->width() < 2 * thickness)
return IntRect();
@@ -167,26 +167,26 @@ bool ScrollbarThemeChromium::shouldCenterOnThumb(Scrollbar*, const PlatformMouse
IntSize ScrollbarThemeChromium::buttonSize(Scrollbar* scrollbar)
{
+#if defined(__linux__)
+ // On Linux, we don't use buttons
+ return IntSize(0, 0);
+#endif
+
// Our desired rect is essentially thickness by thickness.
// Our actual rect will shrink to half the available space when we have < 2
// times thickness pixels left. This allows the scrollbar to scale down
// and function even at tiny sizes.
- int thickness = scrollbarThickness();
+ int thickness = scrollbarThickness(scrollbar->controlSize());
-#if !defined(__linux__)
// In layout test mode, we force the button "girth" (i.e., the length of
// the button along the axis of the scrollbar) to be a fixed size.
// FIXME: This is retarded! scrollbarThickness is already fixed in layout
// test mode so that should be enough to result in repeatable results, but
// preserving this hack avoids having to rebaseline pixel tests.
const int kLayoutTestModeGirth = 17;
-
int girth = ChromiumBridge::layoutTestMode() ? kLayoutTestModeGirth : thickness;
-#else
- int girth = thickness;
-#endif
if (scrollbar->orientation() == HorizontalScrollbar) {
int width = scrollbar->width() < 2 * girth ? scrollbar->width() / 2 : girth;
diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp
index 95d0f78..a99d778 100644
--- a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp
+++ b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp
@@ -1,10 +1,10 @@
/*
* 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
@@ -14,7 +14,7 @@
* * 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
@@ -37,112 +37,106 @@
#include "Scrollbar.h"
#include "TransformationMatrix.h"
-#include "gtkdrawing.h"
-#include <gtk/gtk.h>
-#include "skia/ext/GdkSkia.h"
-
namespace WebCore {
int ScrollbarThemeChromium::scrollbarThickness(ScrollbarControlSize controlSize)
{
- static int size = 0;
- if (!size) {
- MozGtkScrollbarMetrics metrics;
- moz_gtk_get_scrollbar_metrics(&metrics);
- size = metrics.slider_width;
- }
- return size;
+ return 15;
}
bool ScrollbarThemeChromium::invalidateOnMouseEnterExit()
{
- notImplemented();
return false;
}
-// Given an uninitialised widget state object, set the members such that it's
-// sane for drawing scrollbars
-static void initMozState(GtkWidgetState* mozState)
+static void drawVertLine(SkCanvas* canvas, int x, int y1, int y2, const SkPaint& paint)
{
- mozState->active = true;
- mozState->focused = false;
- mozState->inHover = false;
- mozState->disabled = false;
- mozState->isDefault = false;
- mozState->canDefault = false;
- mozState->depressed = false;
- mozState->curpos = 0;
- mozState->maxpos = 0;
+ SkIRect skrect;
+ skrect.set(x, y1, x + 1, y2 + 1);
+ canvas->drawIRect(skrect, paint);
}
-// Paint a GTK widget
-// gc: context to draw onto
-// rect: the area of the widget
-// widget_type: the type of widget to draw
-// flags: widget dependent flags (e.g. direction of scrollbar arrows etc)
-//
-// See paintMozWiget in RenderThemeGtk.cpp for an explanation of the clipping.
-static void paintScrollbarWidget(GraphicsContext* gc, const IntRect& rect,
- GtkThemeWidgetType widget_type, gint flags)
+static void drawHorizLine(SkCanvas* canvas, int x1, int x2, int y, const SkPaint& paint)
{
- PlatformContextSkia* pcs = gc->platformContext();
-
- GdkRectangle gdkRect = { rect.x(), rect.y(), rect.width(), rect.height() };
-
- const SkIRect clip_region = pcs->canvas()->getTotalClip().getBounds();
- TransformationMatrix ctm = gc->getCTM().inverse();
- IntPoint pos = ctm.mapPoint(
- IntPoint(SkScalarRound(clip_region.fLeft), SkScalarRound(clip_region.fTop)));
- GdkRectangle gdkClipRect;
- gdkClipRect.x = pos.x();
- gdkClipRect.y = pos.y();
- gdkClipRect.width = clip_region.width();
- gdkClipRect.height = clip_region.height();
-
- gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect);
-
- GtkWidgetState mozState;
- initMozState(&mozState);
+ SkIRect skrect;
+ skrect.set(x1, y, x2 + 1, y + 1);
+ canvas->drawIRect(skrect, paint);
+}
- moz_gtk_widget_paint(widget_type, pcs->gdk_skia(), &gdkRect, &gdkClipRect,
- &mozState, flags, GTK_TEXT_DIR_LTR);
+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);
}
void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar,
const IntRect& rect, ScrollbarPart partType)
{
- const bool horz = scrollbar->orientation() == HorizontalScrollbar;
- const GtkThemeWidgetType track_type =
- horz ? MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL : MOZ_GTK_SCROLLBAR_TRACK_VERTICAL;
- paintScrollbarWidget(gc, rect, track_type, 0);
+ SkCanvas* const canvas = gc->platformContext()->canvas();
+ SkPaint paint;
+ SkIRect skrect;
+
+ skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
+ paint.setARGB(0xff, 0xe3, 0xdd, 0xd8);
+ canvas->drawIRect(skrect, paint);
+
+ paint.setARGB(0xff, 0xc5, 0xba, 0xb0);
+ drawBox(canvas, rect, paint);
}
void ScrollbarThemeChromium::paintButton(GraphicsContext* gc, Scrollbar* scrollbar,
- const IntRect& rect, ScrollbarPart part)
+ const IntRect& rect, ScrollbarPart part)
{
- // FIXME: It appears the either we're upsetting GTK by forcing WebKit sizes
- // on it, or the buttons expect the track to be drawn under them. Either
- // way, we end up with unpainted pixels which are upsetting the pixel
- // tests. Thus we paint green under the buttons to, at least, make the
- // pixel output the same between debug and opt builds.
- SkPaint paint;
- paint.setARGB(255, 0, 255, 128);
- SkRect skrect;
- skrect.set(rect.x(), rect.y(), rect.x() + rect.width() - 1, rect.y() + rect.height() - 1);
- gc->platformContext()->canvas()->drawRect(skrect, paint);
-
- const bool horz = scrollbar->orientation() == HorizontalScrollbar;
- gint flags = horz ? 0 : MOZ_GTK_STEPPER_VERTICAL;
- flags |= ForwardButtonEndPart == part ? MOZ_GTK_STEPPER_DOWN : 0;
- paintScrollbarWidget(gc, rect, MOZ_GTK_SCROLLBAR_BUTTON, flags);
+ // We don't use buttons
}
void ScrollbarThemeChromium::paintThumb(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect)
{
- const bool horz = scrollbar->orientation() == HorizontalScrollbar;
- const GtkThemeWidgetType thumb_type =
- horz ? MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL : MOZ_GTK_SCROLLBAR_THUMB_VERTICAL;
- paintScrollbarWidget(gc, rect, thumb_type, 0);
+ 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();
+
+ SkPaint paint;
+ if (hovered)
+ paint.setARGB(0xff, 0xff, 0xff, 0xff);
+ else
+ paint.setARGB(0xff, 0xf4, 0xf2, 0xef);
+
+ 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);
+
+ if (hovered)
+ paint.setARGB(0xff, 0xf4, 0xf2, 0xef);
+ else
+ paint.setARGB(0xff, 0xea, 0xe5, 0xe0);
+
+ if (vertical)
+ skrect.set(midx + 1, rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
+ else
+ skrect.set(rect.x(), midy + 1, rect.x() + rect.width(), rect.y() + rect.height());
+
+ canvas->drawIRect(skrect, paint);
+
+ paint.setARGB(0xff, 0x9d, 0x96, 0x8e);
+ drawBox(canvas, rect, paint);
+
+ if (rect.height() > 10 && rect.width() > 10) {
+ paint.setARGB(0xff, 0x9d, 0x96, 0x8e);
+ drawHorizLine(canvas, midx - 1, midx + 3, midy, paint);
+ drawHorizLine(canvas, midx - 1, midx + 3, midy - 3, paint);
+ drawHorizLine(canvas, midx - 1, midx + 3, midy + 3, paint);
+ }
}
} // namespace WebCore
diff --git a/WebCore/platform/chromium/TemporaryLinkStubs.cpp b/WebCore/platform/chromium/TemporaryLinkStubs.cpp
index 4a028da..f6e77d4 100644
--- a/WebCore/platform/chromium/TemporaryLinkStubs.cpp
+++ b/WebCore/platform/chromium/TemporaryLinkStubs.cpp
@@ -44,11 +44,3 @@ String KURL::fileSystemPath() const { notImplemented(); return String(); }
PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) { notImplemented(); return 0; }
} // namespace WebCore
-
-namespace WTF {
-
-#if !defined(__linux__)
-void scheduleDispatchFunctionsOnMainThread() { notImplemented(); }
-#endif
-
-} // namespace WTF
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp
index 68863df..1d97632 100644
--- a/WebCore/platform/graphics/BitmapImage.cpp
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -53,6 +53,7 @@ BitmapImage::BitmapImage(ImageObserver* observer)
, m_repetitionsComplete(0)
, m_desiredFrameStartTime(0)
, m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
, m_animationFinished(false)
, m_allDataReceived(false)
, m_haveSize(false)
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h
index 110aec4..db05d1c 100644
--- a/WebCore/platform/graphics/BitmapImage.h
+++ b/WebCore/platform/graphics/BitmapImage.h
@@ -166,7 +166,7 @@ protected:
virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator);
#endif
virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
-#if PLATFORM(QT) || PLATFORM(WX)
+#if PLATFORM(WX)
virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
#endif
@@ -218,9 +218,18 @@ protected:
void invalidatePlatformData();
// Checks to see if the image is a 1x1 solid color. We optimize these images and just do a fill rect instead.
+ // This check should happen regardless whether m_checkedForSolidColor is already set, as the frame may have
+ // changed.
void checkForSolidColor();
- virtual bool mayFillWithSolidColor() const { return m_isSolidColor && m_currentFrame == 0; }
+ virtual bool mayFillWithSolidColor()
+ {
+ if (!m_checkedForSolidColor && frameCount() > 0) {
+ checkForSolidColor();
+ ASSERT(m_checkedForSolidColor);
+ }
+ return m_isSolidColor && m_currentFrame == 0;
+ }
virtual Color solidColor() const { return m_solidColor; }
ImageSource m_source;
@@ -242,6 +251,7 @@ protected:
Color m_solidColor; // If we're a 1x1 solid color, this is the color to use to fill.
bool m_isSolidColor; // Whether or not we are a 1x1 solid image.
+ bool m_checkedForSolidColor; // Whether we've checked the frame for solid color.
bool m_animationFinished; // Whether or not we've completed the entire animation.
diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp
index c7e11ee..e85ac00 100644
--- a/WebCore/platform/graphics/Color.cpp
+++ b/WebCore/platform/graphics/Color.cpp
@@ -116,6 +116,15 @@ RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double
static_cast<int>(alpha * scaleFactor));
}
+RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a)
+{
+ double colors = 1 - k;
+ int r = static_cast<int>(nextafter(256, 0) * (colors * (1 - c)));
+ int g = static_cast<int>(nextafter(256, 0) * (colors * (1 - m)));
+ int b = static_cast<int>(nextafter(256, 0) * (colors * (1 - y)));
+ return makeRGBA(r, g, b, static_cast<float>(nextafter(256, 0) * a));
+}
+
// originally moved here from the CSS parser
bool Color::parseHexColor(const String& name, RGBA32& rgb)
{
@@ -312,4 +321,34 @@ void Color::getRGBA(double& r, double& g, double& b, double& a) const
a = alpha() / 255.0;
}
+Color colorFromPremultipliedARGB(unsigned pixelColor)
+{
+ RGBA32 rgba;
+
+ if (unsigned alpha = (pixelColor & 0xFF000000) >> 24) {
+ rgba = makeRGBA(((pixelColor & 0x00FF0000) >> 16) * 255 / alpha,
+ ((pixelColor & 0x0000FF00) >> 8) * 255 / alpha,
+ (pixelColor & 0x000000FF) * 255 / alpha,
+ alpha);
+ } else
+ rgba = pixelColor;
+
+ return Color(rgba);
+}
+
+unsigned premultipliedARGBFromColor(const Color& color)
+{
+ unsigned pixelColor;
+
+ if (unsigned alpha = color.alpha()) {
+ pixelColor = alpha << 24 |
+ ((color.red() * alpha + 254) / 255) << 16 |
+ ((color.green() * alpha + 254) / 255) << 8 |
+ ((color.blue() * alpha + 254) / 255);
+ } else
+ pixelColor = color.rgb();
+
+ return pixelColor;
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h
index 61fc74c..3c889f9 100644
--- a/WebCore/platform/graphics/Color.h
+++ b/WebCore/platform/graphics/Color.h
@@ -60,6 +60,7 @@ RGBA32 makeRGBA(int r, int g, int b, int a);
RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha);
RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a);
RGBA32 makeRGBAFromHSLA(double h, double s, double l, double a);
+RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a);
int differenceSquared(const Color&, const Color&);
@@ -71,6 +72,8 @@ public:
Color(int r, int g, int b, int a) : m_color(makeRGBA(r, g, b, a)), m_valid(true) { }
// Color is currently limited to 32bit RGBA, perhaps some day we'll support better colors
Color(float r, float g, float b, float a) : m_color(makeRGBA32FromFloats(r, g, b, a)), m_valid(true) { }
+ // Creates a new color from the specific CMYK and alpha values.
+ Color(float c, float m, float y, float k, float a) : m_color(makeRGBAFromCMYKA(c, m, y, k, a)), m_valid(true) { }
explicit Color(const String&);
explicit Color(const char*);
@@ -146,9 +149,11 @@ inline bool operator!=(const Color& a, const Color& b)
}
Color focusRingColor();
+Color colorFromPremultipliedARGB(unsigned);
+unsigned premultipliedARGBFromColor(const Color&);
#if PLATFORM(CG)
-CGColorRef cgColor(const Color&);
+CGColorRef createCGColor(const Color&);
#endif
} // namespace WebCore
diff --git a/WebCore/platform/graphics/FloatPoint.cpp b/WebCore/platform/graphics/FloatPoint.cpp
index 564ea86..7765ba9 100644
--- a/WebCore/platform/graphics/FloatPoint.cpp
+++ b/WebCore/platform/graphics/FloatPoint.cpp
@@ -40,7 +40,7 @@ FloatPoint::FloatPoint(const IntPoint& p) : m_x(p.x()), m_y(p.y())
FloatPoint FloatPoint::matrixTransform(const TransformationMatrix& transform) const
{
double newX, newY;
- transform.map(static_cast<double>(m_x), static_cast<double>(m_y), &newX, &newY);
+ transform.map(static_cast<double>(m_x), static_cast<double>(m_y), newX, newY);
return narrowPrecision(newX, newY);
}
diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h
index 35b3036..a3fbeea 100644
--- a/WebCore/platform/graphics/FloatPoint.h
+++ b/WebCore/platform/graphics/FloatPoint.h
@@ -55,7 +55,7 @@ QT_END_NAMESPACE
class TPoint;
#endif
-#if PLATFORM(SKIA)
+#if (PLATFORM(SKIA) || PLATFORM(SGL))
struct SkPoint;
#endif
@@ -99,7 +99,7 @@ public:
FloatPoint(const TPoint&);
#endif
-#if PLATFORM(SKIA)
+#if (PLATFORM(SKIA) || PLATFORM(SGL))
operator SkPoint() const;
FloatPoint(const SkPoint&);
#endif
diff --git a/WebCore/platform/graphics/FloatPoint3D.cpp b/WebCore/platform/graphics/FloatPoint3D.cpp
index e3ba422..8c21ef3 100644
--- a/WebCore/platform/graphics/FloatPoint3D.cpp
+++ b/WebCore/platform/graphics/FloatPoint3D.cpp
@@ -21,7 +21,6 @@
#include "config.h"
-#if ENABLE(SVG)
#include <math.h>
#include "FloatPoint.h"
#include "FloatPoint3D.h"
@@ -62,4 +61,3 @@ void FloatPoint3D::normalize()
} // namespace WebCore
-#endif // ENABLE(SVG)
diff --git a/WebCore/platform/graphics/FloatPoint3D.h b/WebCore/platform/graphics/FloatPoint3D.h
index 184e914..2e71ddd 100644
--- a/WebCore/platform/graphics/FloatPoint3D.h
+++ b/WebCore/platform/graphics/FloatPoint3D.h
@@ -22,8 +22,6 @@
#ifndef FloatPoint3D_h
#define FloatPoint3D_h
-#if ENABLE(SVG)
-
namespace WebCore {
class FloatPoint;
@@ -53,6 +51,4 @@ private:
} // namespace WebCore
-#endif // ENABLE(SVG)
-
#endif // FloatPoint3D_h
diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h
index a87c949..786fb3e 100644
--- a/WebCore/platform/graphics/FloatRect.h
+++ b/WebCore/platform/graphics/FloatRect.h
@@ -51,7 +51,7 @@ QT_END_NAMESPACE
class wxRect2DDouble;
#endif
-#if PLATFORM(SKIA)
+#if (PLATFORM(SKIA) || PLATFORM(SGL))
struct SkRect;
#endif
@@ -143,7 +143,7 @@ public:
operator wxRect2DDouble() const;
#endif
-#if PLATFORM(SKIA)
+#if (PLATFORM(SKIA) || PLATFORM(SGL))
FloatRect(const SkRect&);
operator SkRect() const;
#endif
diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp
index 2d219be..130313d 100644
--- a/WebCore/platform/graphics/FontCache.cpp
+++ b/WebCore/platform/graphics/FontCache.cpp
@@ -139,8 +139,13 @@ static const AtomicString& alternateFamilyName(const AtomicString& familyName)
DEFINE_STATIC_LOCAL(AtomicString, courierNew, ("Courier New"));
if (equalIgnoringCase(familyName, courier))
return courierNew;
+#if !PLATFORM(WIN_OS)
+ // On Windows, Courier New (truetype font) is always present and
+ // Courier is a bitmap font. So, we don't want to map Courier New to
+ // Courier.
if (equalIgnoringCase(familyName, courierNew))
return courier;
+#endif
// Alias Times and Times New Roman.
DEFINE_STATIC_LOCAL(AtomicString, times, ("Times"));
@@ -158,6 +163,21 @@ static const AtomicString& alternateFamilyName(const AtomicString& familyName)
if (equalIgnoringCase(familyName, helvetica))
return arial;
+#if PLATFORM(WIN_OS)
+ // On Windows, bitmap fonts are blocked altogether so that we have to
+ // alias MS Sans Serif (bitmap font) -> Microsoft Sans Serif (truetype font)
+ DEFINE_STATIC_LOCAL(AtomicString, msSans, ("MS Sans Serif"));
+ DEFINE_STATIC_LOCAL(AtomicString, microsoftSans, ("Microsoft Sans Serif"));
+ if (equalIgnoringCase(familyName, msSans))
+ return microsoftSans;
+
+ // Alias MS Serif (bitmap) -> Times New Roman (truetype font). There's no
+ // 'Microsoft Sans Serif-equivalent' for Serif.
+ static AtomicString msSerif("MS Serif");
+ if (equalIgnoringCase(familyName, msSerif))
+ return timesNewRoman;
+#endif
+
return emptyAtom;
}
@@ -216,7 +236,7 @@ struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
static const bool needsDestruction = true;
static const FontPlatformData& emptyValue()
{
- DEFINE_STATIC_LOCAL(FontPlatformData, key, ());
+ DEFINE_STATIC_LOCAL(FontPlatformData, key, (0.f, false, false));
return key;
}
static void constructDeletedValue(FontPlatformData& slot)
@@ -304,7 +324,7 @@ void FontCache::purgeInactiveFontData(int count)
}
Vector<FontPlatformDataCacheKey> keysToRemove;
- keysToRemove.reserveCapacity(gFontPlatformDataCache->size());
+ keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size());
FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end();
for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) {
if (platformData->second && !gFontDataCache->contains(*platformData->second))
@@ -424,7 +444,7 @@ void FontCache::invalidate()
Vector<RefPtr<FontSelector> > clients;
size_t numClients = gClients->size();
- clients.reserveCapacity(numClients);
+ clients.reserveInitialCapacity(numClients);
HashSet<FontSelector*>::iterator end = gClients->end();
for (HashSet<FontSelector*>::iterator it = gClients->begin(); it != end; ++it)
clients.append(*it);
diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h
index fdb306f..dcda419 100644
--- a/WebCore/platform/graphics/GlyphBuffer.h
+++ b/WebCore/platform/graphics/GlyphBuffer.h
@@ -37,7 +37,7 @@
#include <ApplicationServices/ApplicationServices.h>
#endif
-#if PLATFORM(CAIRO)
+#if PLATFORM(CAIRO) || (PLATFORM(WX) && defined(__WXGTK__))
#include <cairo.h>
#endif
diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
index 6b9d23d..bd838de 100644
--- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp
+++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
@@ -218,6 +218,7 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu
}
haveGlyphs |= pageToFill->fill(from, to - from, buffer + from * (start < 0x10000 ? 1 : 2), (to - from) * (start < 0x10000 ? 1 : 2), range.fontData());
if (scratchPage) {
+ ASSERT(to <= static_cast<int>(GlyphPage::size));
for (int j = from; j < to; j++) {
if (!m_page->m_glyphs[j].glyph && pageToFill->m_glyphs[j].glyph)
m_page->m_glyphs[j] = pageToFill->m_glyphs[j];
diff --git a/WebCore/platform/graphics/GlyphWidthMap.cpp b/WebCore/platform/graphics/GlyphWidthMap.cpp
index 6e8d68d..43cab65 100644
--- a/WebCore/platform/graphics/GlyphWidthMap.cpp
+++ b/WebCore/platform/graphics/GlyphWidthMap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,43 +29,22 @@
#include "config.h"
#include "GlyphWidthMap.h"
-namespace WebCore
-{
-
-float GlyphWidthMap::widthForGlyph(Glyph g)
-{
- unsigned pageNumber = (g / GlyphWidthPage::size);
- GlyphWidthPage* page = locatePage(pageNumber);
- if (page)
- return page->widthForGlyph(g);
- return cGlyphWidthUnknown;
-}
-
-void GlyphWidthMap::setWidthForGlyph(Glyph glyph, float width)
-{
- unsigned pageNumber = (glyph / GlyphWidthPage::size);
- GlyphWidthPage* page = locatePage(pageNumber);
- if (page)
- page->setWidthForGlyph(glyph, width);
-}
+namespace WebCore {
-inline GlyphWidthMap::GlyphWidthPage* GlyphWidthMap::locatePage(unsigned pageNumber)
+GlyphWidthMap::GlyphWidthPage* GlyphWidthMap::locatePageSlowCase(unsigned pageNumber)
{
GlyphWidthPage* page;
if (pageNumber == 0) {
- if (m_filledPrimaryPage)
- return &m_primaryPage;
+ ASSERT(!m_filledPrimaryPage);
page = &m_primaryPage;
m_filledPrimaryPage = true;
} else {
if (m_pages) {
- GlyphWidthPage* result = m_pages->get(pageNumber);
- if (result)
- return result;
- }
+ if ((page = m_pages->get(pageNumber)))
+ return page;
+ } else
+ m_pages.set(new HashMap<int, GlyphWidthPage*>);
page = new GlyphWidthPage;
- if (!m_pages)
- m_pages = new HashMap<int, GlyphWidthPage*>;
m_pages->set(pageNumber, page);
}
diff --git a/WebCore/platform/graphics/GlyphWidthMap.h b/WebCore/platform/graphics/GlyphWidthMap.h
index 1633769..e194ecf 100644
--- a/WebCore/platform/graphics/GlyphWidthMap.h
+++ b/WebCore/platform/graphics/GlyphWidthMap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,9 +29,9 @@
#ifndef GlyphWidthMap_h
#define GlyphWidthMap_h
-#include <wtf/unicode/Unicode.h>
-#include <wtf/Noncopyable.h>
#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/unicode/Unicode.h>
namespace WebCore {
@@ -41,34 +41,49 @@ const float cGlyphWidthUnknown = -1;
class GlyphWidthMap : Noncopyable {
public:
- GlyphWidthMap() : m_filledPrimaryPage(false), m_pages(0) {}
- ~GlyphWidthMap() { if (m_pages) { deleteAllValues(*m_pages); delete m_pages; } }
+ GlyphWidthMap() : m_filledPrimaryPage(false) { }
+ ~GlyphWidthMap() { if (m_pages) { deleteAllValues(*m_pages); } }
+
+ float widthForGlyph(Glyph glyph)
+ {
+ return locatePage(glyph / GlyphWidthPage::size)->widthForGlyph(glyph);
+ }
- float widthForGlyph(Glyph);
- void setWidthForGlyph(Glyph, float);
+ void setWidthForGlyph(Glyph glyph, float width)
+ {
+ locatePage(glyph / GlyphWidthPage::size)->setWidthForGlyph(glyph, width);
+ }
private:
struct GlyphWidthPage {
static const size_t size = 256; // Usually covers Latin-1 in a single page.
float m_widths[size];
- float widthForGlyph(Glyph g) const { return m_widths[g % size]; }
- void setWidthForGlyph(Glyph g, float w)
+ float widthForGlyph(Glyph glyph) const { return m_widths[glyph % size]; }
+ void setWidthForGlyph(Glyph glyph, float width)
{
- setWidthForIndex(g % size, w);
+ setWidthForIndex(glyph % size, width);
}
- void setWidthForIndex(unsigned index, float w)
+ void setWidthForIndex(unsigned index, float width)
{
- m_widths[index] = w;
+ m_widths[index] = width;
}
};
- GlyphWidthPage* locatePage(unsigned page);
+ GlyphWidthPage* locatePage(unsigned pageNumber)
+ {
+ if (!pageNumber && m_filledPrimaryPage)
+ return &m_primaryPage;
+ return locatePageSlowCase(pageNumber);
+ }
+
+ GlyphWidthPage* locatePageSlowCase(unsigned pageNumber);
bool m_filledPrimaryPage;
GlyphWidthPage m_primaryPage; // We optimize for the page that contains glyph indices 0-255.
- HashMap<int, GlyphWidthPage*>* m_pages;
+ OwnPtr<HashMap<int, GlyphWidthPage*> > m_pages;
};
}
+
#endif
diff --git a/WebCore/platform/graphics/Gradient.cpp b/WebCore/platform/graphics/Gradient.cpp
index 2e6a5d2..24e8bbf 100644
--- a/WebCore/platform/graphics/Gradient.cpp
+++ b/WebCore/platform/graphics/Gradient.cpp
@@ -39,6 +39,7 @@ Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1)
, m_r1(0)
, m_stopsSorted(false)
, m_lastStop(0)
+ , m_spreadMethod(SpreadMethodPad)
{
platformInit();
}
@@ -146,4 +147,11 @@ int Gradient::findStop(float value) const
return m_lastStop;
}
+void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod)
+{
+ // FIXME: Should it become necessary, allow calls to this method after m_gradient has been set.
+ ASSERT(m_gradient == 0);
+ m_spreadMethod = spreadMethod;
+}
+
} //namespace
diff --git a/WebCore/platform/graphics/Gradient.h b/WebCore/platform/graphics/Gradient.h
index 00ef2b6..764deee 100644
--- a/WebCore/platform/graphics/Gradient.h
+++ b/WebCore/platform/graphics/Gradient.h
@@ -29,6 +29,8 @@
#include "FloatPoint.h"
#include "Generator.h"
+#include "GraphicsTypes.h"
+#include "TransformationMatrix.h"
#include <wtf/PassRefPtr.h>
#include <wtf/Vector.h>
@@ -93,6 +95,12 @@ namespace WebCore {
void setStopsSorted(bool s) { m_stopsSorted = s; }
+ void setSpreadMethod(GradientSpreadMethod);
+ GradientSpreadMethod spreadMethod() { return m_spreadMethod; }
+ void setGradientSpaceTransform(const TransformationMatrix& gradientSpaceTransformation) { m_gradientSpaceTransformation = gradientSpaceTransformation; }
+ // Qt and CG transform the gradient at draw time
+ TransformationMatrix gradientSpaceTransform() { return m_gradientSpaceTransformation; }
+
virtual void fill(GraphicsContext*, const FloatRect&);
private:
@@ -112,6 +120,8 @@ namespace WebCore {
mutable Vector<ColorStop> m_stops;
mutable bool m_stopsSorted;
mutable int m_lastStop;
+ GradientSpreadMethod m_spreadMethod;
+ TransformationMatrix m_gradientSpaceTransformation;
PlatformGradient m_gradient;
};
diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp
index 8426011..8cad794 100644
--- a/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/WebCore/platform/graphics/GraphicsContext.cpp
@@ -128,6 +128,11 @@ void GraphicsContext::setStrokeColor(const Color& color)
setPlatformStrokeColor(color);
}
+ColorSpace GraphicsContext::strokeColorSpace() const
+{
+ return m_common->state.strokeColorSpace;
+}
+
void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color)
{
m_common->state.shadowSize = size;
@@ -178,16 +183,6 @@ void GraphicsContext::setFillRule(WindRule fillRule)
m_common->state.fillRule = fillRule;
}
-GradientSpreadMethod GraphicsContext::spreadMethod() const
-{
- return m_common->state.spreadMethod;
-}
-
-void GraphicsContext::setSpreadMethod(GradientSpreadMethod spreadMethod)
-{
- m_common->state.spreadMethod = spreadMethod;
-}
-
void GraphicsContext::setFillColor(const Color& color)
{
m_common->state.fillColorSpace = SolidColorSpace;
@@ -255,6 +250,31 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
m_common->state.fillGradient = gradient;
}
+Gradient* GraphicsContext::fillGradient() const
+{
+ return m_common->state.fillGradient.get();
+}
+
+ColorSpace GraphicsContext::fillColorSpace() const
+{
+ return m_common->state.fillColorSpace;
+}
+
+Gradient* GraphicsContext::strokeGradient() const
+{
+ return m_common->state.strokeGradient.get();
+}
+
+Pattern* GraphicsContext::fillPattern() const
+{
+ return m_common->state.fillPattern.get();
+}
+
+Pattern* GraphicsContext::strokePattern() const
+{
+ return m_common->state.strokePattern.get();
+}
+
void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms)
{
m_common->state.shadowsIgnoreTransforms = ignoreTransforms;
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index c27f38f..7c1c4b0 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -123,6 +123,18 @@ namespace WebCore {
DashedStroke
};
+// FIXME: This is a place-holder until we decide to add
+// real color space support to WebCore. At that time, ColorSpace will be a
+// class and instances will be held off of Colors. There will be
+// special singleton Gradient and Pattern color spaces to mark when
+// a fill or stroke is using a gradient or pattern instead of a solid color.
+// https://bugs.webkit.org/show_bug.cgi?id=20558
+ enum ColorSpace {
+ SolidColorSpace,
+ PatternColorSpace,
+ GradientColorSpace
+ };
+
enum InterpolationQuality {
InterpolationDefault,
InterpolationNone,
@@ -131,14 +143,6 @@ namespace WebCore {
InterpolationHigh
};
- // FIXME: Currently these constants have to match the values used in the SVG
- // DOM API. That's a mistake. We need to make cut that dependency.
- enum GradientSpreadMethod {
- SpreadMethodPad = 1,
- SpreadMethodReflect = 2,
- SpreadMethodRepeat = 3
- };
-
class GraphicsContext : Noncopyable {
public:
GraphicsContext(PlatformGraphicsContext*);
@@ -152,17 +156,28 @@ namespace WebCore {
void setStrokeStyle(const StrokeStyle& style);
Color strokeColor() const;
void setStrokeColor(const Color&);
+
+ ColorSpace strokeColorSpace() const;
+
void setStrokePattern(PassRefPtr<Pattern>);
+ Pattern* strokePattern() const;
+
void setStrokeGradient(PassRefPtr<Gradient>);
+ Gradient* strokeGradient() const;
WindRule fillRule() const;
void setFillRule(WindRule);
- GradientSpreadMethod spreadMethod() const;
- void setSpreadMethod(GradientSpreadMethod);
Color fillColor() const;
void setFillColor(const Color&);
+
void setFillPattern(PassRefPtr<Pattern>);
+ Pattern* fillPattern() const;
+
void setFillGradient(PassRefPtr<Gradient>);
+ Gradient* fillGradient() const;
+
+ ColorSpace fillColorSpace() const;
+
void setShadowsIgnoreTransforms(bool);
void setShouldAntialias(bool);
@@ -206,6 +221,9 @@ namespace WebCore {
void restore();
// These draw methods will do both stroking and filling.
+ // FIXME: ...except drawRect(), which fills properly but always strokes
+ // using a 1-pixel stroke inset from the rect borders (of the correct
+ // stroke color).
void drawRect(const IntRect&);
void drawLine(const IntPoint&, const IntPoint&);
void drawEllipse(const IntRect&);
@@ -402,3 +420,4 @@ namespace WebCore {
} // namespace WebCore
#endif // GraphicsContext_h
+
diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h
index 87123eb..98baab1 100644
--- a/WebCore/platform/graphics/GraphicsContextPrivate.h
+++ b/WebCore/platform/graphics/GraphicsContextPrivate.h
@@ -33,18 +33,6 @@
namespace WebCore {
-// FIXME: This is a place-holder until we decide to add
-// real color space support to WebCore. At that time, ColorSpace will be a
-// class and instances will be held off of Colors. There will be
-// special singleton Gradient and Pattern color spaces to mark when
-// a fill or stroke is using a gradient or pattern instead of a solid color.
-// https://bugs.webkit.org/show_bug.cgi?id=20558
- enum ColorSpace {
- SolidColorSpace,
- PatternColorSpace,
- GradientColorSpace
- };
-
struct GraphicsContextState {
GraphicsContextState()
: textDrawingMode(cTextFill)
@@ -80,7 +68,6 @@ namespace WebCore {
RefPtr<Pattern> strokePattern;
WindRule fillRule;
- GradientSpreadMethod spreadMethod;
ColorSpace fillColorSpace;
Color fillColor;
RefPtr<Gradient> fillGradient;
diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp
new file mode 100644
index 0000000..0c442a2
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsLayer.cpp
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayer.h"
+
+#include "FloatPoint.h"
+#include "RotateTransformOperation.h"
+#include "TextStream.h"
+
+namespace WebCore {
+
+void GraphicsLayer::FloatValue::set(float key, float value, const TimingFunction* timingFunction)
+{
+ m_key = key;
+ m_value = value;
+ if (timingFunction != m_timingFunction) {
+ if (timingFunction)
+ m_timingFunction.set(new TimingFunction(*timingFunction));
+ else
+ m_timingFunction.clear();
+ }
+}
+
+void GraphicsLayer::TransformValue::set(float key, const TransformOperations* value, const TimingFunction* timingFunction)
+{
+ m_key = key;
+ if (value != m_value) {
+ if (value)
+ m_value.set(new TransformOperations(*value));
+ else
+ m_value.clear();
+ }
+ if (timingFunction != m_timingFunction) {
+ if (timingFunction)
+ m_timingFunction.set(new TimingFunction(*timingFunction));
+ else
+ m_timingFunction.clear();
+ }
+}
+
+void GraphicsLayer::FloatValueList::insert(float key, float value, const TimingFunction* timingFunction)
+{
+ for (size_t i = 0; i < m_values.size(); ++i) {
+ FloatValue& curFloatValue = m_values[i];
+ if (curFloatValue.key() == key) {
+ curFloatValue.set(key, value, timingFunction);
+ return;
+ }
+ if (curFloatValue.key() > key) {
+ // insert before
+ m_values.insert(i, FloatValue(key, value, timingFunction));
+ return;
+ }
+ }
+
+ // append
+ m_values.append(FloatValue(key, value, timingFunction));
+}
+
+void GraphicsLayer::TransformValueList::insert(float key, const TransformOperations* value, const TimingFunction* timingFunction)
+{
+ for (size_t i = 0; i < m_values.size(); ++i) {
+ TransformValue& curTransValue = m_values[i];
+ if (curTransValue.key() == key) {
+ curTransValue.set(key, value, timingFunction);
+ return;
+ }
+ if (curTransValue.key() > key) {
+ // insert before
+ m_values.insert(i, TransformValue(key, value, timingFunction));
+ return;
+ }
+ }
+
+ // append
+ m_values.append(TransformValue(key, value, timingFunction));
+}
+
+// An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix
+// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is
+// true if the rotation between any two keyframes is >= 180 degrees.
+void GraphicsLayer::TransformValueList::makeFunctionList(FunctionList& list, bool& isValid, bool& hasBigRotation) const
+{
+ list.clear();
+ isValid = false;
+ hasBigRotation = false;
+
+ if (m_values.size() < 2)
+ return;
+
+ // empty transforms match anything, so find the first non-empty entry as the reference
+ size_t firstIndex = 0;
+ for ( ; firstIndex < m_values.size(); ++firstIndex) {
+ if (m_values[firstIndex].value()->operations().size() > 0)
+ break;
+ }
+
+ if (firstIndex >= m_values.size())
+ return;
+
+ const TransformOperations* firstVal = m_values[firstIndex].value();
+
+ // see if the keyframes are valid
+ for (size_t i = firstIndex + 1; i < m_values.size(); ++i) {
+ const TransformOperations* val = m_values[i].value();
+
+ // a null transform matches anything
+ if (val->operations().isEmpty())
+ continue;
+
+ if (firstVal->operations().size() != val->operations().size())
+ return;
+
+ for (size_t j = 0; j < firstVal->operations().size(); ++j) {
+ if (!firstVal->operations().at(j)->isSameType(*val->operations().at(j)))
+ return;
+ }
+ }
+
+ // keyframes are valid, fill in the list
+ isValid = true;
+
+ double lastRotAngle = 0.0;
+ double maxRotAngle = -1.0;
+
+ list.resize(firstVal->operations().size());
+ for (size_t j = 0; j < firstVal->operations().size(); ++j) {
+ TransformOperation::OperationType type = firstVal->operations().at(j)->getOperationType();
+ list[j] = type;
+
+ // if this is a rotation entry, we need to see if any angle differences are >= 180 deg
+ if (type == TransformOperation::ROTATE_X ||
+ type == TransformOperation::ROTATE_Y ||
+ type == TransformOperation::ROTATE_Z ||
+ type == TransformOperation::ROTATE_3D) {
+ lastRotAngle = static_cast<RotateTransformOperation*>(firstVal->operations().at(j).get())->angle();
+
+ if (maxRotAngle < 0)
+ maxRotAngle = fabs(lastRotAngle);
+
+ for (size_t i = firstIndex + 1; i < m_values.size(); ++i) {
+ const TransformOperations* val = m_values[i].value();
+ double rotAngle = val->operations().isEmpty() ? 0 : (static_cast<RotateTransformOperation*>(val->operations().at(j).get())->angle());
+ double diffAngle = fabs(rotAngle - lastRotAngle);
+ if (diffAngle > maxRotAngle)
+ maxRotAngle = diffAngle;
+ lastRotAngle = rotAngle;
+ }
+ }
+ }
+
+ hasBigRotation = maxRotAngle >= 180.0;
+}
+
+GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
+ : m_client(client)
+ , m_anchorPoint(0.5f, 0.5f, 0)
+ , m_opacity(1)
+#ifndef NDEBUG
+ , m_zPosition(0)
+#endif
+ , m_backgroundColorSet(false)
+ , m_contentsOpaque(false)
+ , m_preserves3D(false)
+ , m_backfaceVisibility(true)
+ , m_usingTiledLayer(false)
+ , m_masksToBounds(false)
+ , m_drawsContent(false)
+ , m_paintingPhase(GraphicsLayerPaintAllMask)
+ , m_parent(0)
+#ifndef NDEBUG
+ , m_repaintCount(0)
+#endif
+{
+}
+
+GraphicsLayer::~GraphicsLayer()
+{
+ removeAllAnimations();
+
+ removeAllChildren();
+ removeFromParent();
+}
+
+void GraphicsLayer::addChild(GraphicsLayer* childLayer)
+{
+ ASSERT(childLayer != this);
+
+ if (childLayer->parent())
+ childLayer->removeFromParent();
+
+ childLayer->setParent(this);
+ m_children.append(childLayer);
+}
+
+void GraphicsLayer::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+ ASSERT(childLayer != this);
+
+ if (childLayer->parent())
+ childLayer->removeFromParent();
+
+ childLayer->setParent(this);
+ m_children.insert(index, childLayer);
+}
+
+void GraphicsLayer::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ ASSERT(childLayer != this);
+ childLayer->removeFromParent();
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i, childLayer);
+ found = true;
+ break;
+ }
+ }
+
+ childLayer->setParent(this);
+
+ if (!found)
+ m_children.append(childLayer);
+}
+
+void GraphicsLayer::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ childLayer->removeFromParent();
+ ASSERT(childLayer != this);
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i+1, childLayer);
+ found = true;
+ break;
+ }
+ }
+
+ childLayer->setParent(this);
+
+ if (!found)
+ m_children.append(childLayer);
+}
+
+bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ ASSERT(!newChild->parent());
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (oldChild == m_children[i]) {
+ m_children[i] = newChild;
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ oldChild->setParent(0);
+
+ newChild->removeFromParent();
+ newChild->setParent(this);
+ return true;
+ }
+ return false;
+}
+
+void GraphicsLayer::removeAllChildren()
+{
+ while (m_children.size()) {
+ GraphicsLayer* curLayer = m_children[0];
+ ASSERT(curLayer->parent());
+ curLayer->removeFromParent();
+ }
+}
+
+void GraphicsLayer::removeFromParent()
+{
+ if (m_parent) {
+ unsigned i;
+ for (i = 0; i < m_parent->m_children.size(); i++) {
+ if (this == m_parent->m_children[i]) {
+ m_parent->m_children.remove(i);
+ break;
+ }
+ }
+
+ setParent(0);
+ }
+}
+
+void GraphicsLayer::setBackgroundColor(const Color& inColor, const Animation*, double /*beginTime*/)
+{
+ m_backgroundColor = inColor;
+ m_backgroundColorSet = true;
+}
+
+void GraphicsLayer::clearBackgroundColor()
+{
+ m_backgroundColor = Color();
+ m_backgroundColorSet = false;
+}
+
+bool GraphicsLayer::setOpacity(float opacity, const Animation*, double)
+{
+ m_opacity = opacity;
+ return false; // not animating
+}
+
+void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const IntRect& clip)
+{
+ m_client->paintContents(this, context, m_paintingPhase, clip);
+}
+
+String GraphicsLayer::propertyIdToString(AnimatedPropertyID property)
+{
+ switch (property) {
+ case AnimatedPropertyWebkitTransform:
+ return "transform";
+ case AnimatedPropertyOpacity:
+ return "opacity";
+ case AnimatedPropertyBackgroundColor:
+ return "backgroundColor";
+ case AnimatedPropertyInvalid:
+ ASSERT_NOT_REACHED();
+ }
+ ASSERT_NOT_REACHED();
+ return "";
+}
+
+int GraphicsLayer::findAnimationEntry(AnimatedPropertyID property, short index) const
+{
+ for (size_t i = 0; i < m_animations.size(); ++i) {
+ if (m_animations[i].matches(property, index))
+ return static_cast<int>(i);
+ }
+ return -1;
+}
+
+void GraphicsLayer::addAnimationEntry(AnimatedPropertyID property, short index, bool isTransition, const Animation* transition)
+{
+ int i = findAnimationEntry(property, index);
+
+ if (i >= 0)
+ m_animations[i].reset(transition, isTransition);
+ else
+ m_animations.append(AnimationEntry(transition, property, index, isTransition));
+}
+
+void GraphicsLayer::removeAllAnimations()
+{
+ size_t size = m_animations.size();
+ for (size_t i = 0; i < size; ++i)
+ removeAnimation(0, true);
+}
+
+void GraphicsLayer::removeAllAnimationsForProperty(AnimatedPropertyID property)
+{
+ for (short j = 0; ; ++j) {
+ int i = findAnimationEntry(property, j);
+ if (i < 0)
+ break;
+ removeAnimation(i, false);
+ }
+}
+
+void GraphicsLayer::removeFinishedAnimations(const String& name, int /*index*/, bool reset)
+{
+ size_t size = m_animations.size();
+ for (size_t i = 0; i < size; ) {
+ AnimationEntry& anim = m_animations[i];
+ if (!anim.isTransition() && anim.animation()->name() == name) {
+ removeAnimation(i, reset);
+ --size;
+ } else
+ ++i;
+ }
+}
+
+void GraphicsLayer::removeFinishedTransitions(AnimatedPropertyID property)
+{
+ size_t size = m_animations.size();
+ for (size_t i = 0; i < size; ) {
+ AnimationEntry& anim = m_animations[i];
+ if (anim.isTransition() && property == anim.property()) {
+ removeAnimation(i, false);
+ --size;
+ } else
+ ++i;
+ }
+}
+
+void GraphicsLayer::suspendAnimations()
+{
+}
+
+void GraphicsLayer::resumeAnimations()
+{
+}
+
+#ifndef NDEBUG
+void GraphicsLayer::updateDebugIndicators()
+{
+ if (GraphicsLayer::showDebugBorders()) {
+ if (drawsContent()) {
+ if (m_usingTiledLayer)
+ setDebugBorder(Color(0, 255, 0, 204), 2.0f); // tiled layer: green
+ else
+ setDebugBorder(Color(255, 0, 0, 204), 2.0f); // normal layer: red
+ } else if (masksToBounds()) {
+ setDebugBorder(Color(128, 255, 255, 178), 2.0f); // masking layer: pale blue
+ if (GraphicsLayer::showDebugBorders())
+ setDebugBackgroundColor(Color(128, 255, 255, 52));
+ } else
+ setDebugBorder(Color(255, 255, 0, 204), 2.0f); // container: yellow
+ }
+}
+
+void GraphicsLayer::setZPosition(float position)
+{
+ m_zPosition = position;
+}
+#endif
+
+static void writeIndent(TextStream& ts, int indent)
+{
+ for (int i = 0; i != indent; ++i)
+ ts << " ";
+}
+
+void GraphicsLayer::dumpLayer(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "(" << "GraphicsLayer" << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this));
+ ts << " \"" << m_name << "\"\n";
+ dumpProperties(ts, indent);
+ writeIndent(ts, indent);
+ ts << ")\n";
+}
+
+void GraphicsLayer::dumpProperties(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent + 1);
+ ts << "(position " << m_position.x() << " " << m_position.y() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(bounds " << m_size.width() << " " << m_size.height() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(opacity " << m_opacity << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(usingTiledLayer " << m_usingTiledLayer << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(m_preserves3D " << m_preserves3D << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(drawsContent " << m_drawsContent << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(m_backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(client ";
+ if (m_client)
+ ts << static_cast<void*>(m_client);
+ else
+ ts << "none";
+ ts << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(backgroundColor ";
+ if (!m_backgroundColorSet)
+ ts << "none";
+ else
+ ts << m_backgroundColor.name();
+ ts << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(transform ";
+ if (m_transform.isIdentity())
+ ts << "identity";
+ else {
+ ts << "[" << m_transform.m11() << " " << m_transform.m12() << " " << m_transform.m13() << " " << m_transform.m14() << "] ";
+ ts << "[" << m_transform.m21() << " " << m_transform.m22() << " " << m_transform.m23() << " " << m_transform.m24() << "] ";
+ ts << "[" << m_transform.m31() << " " << m_transform.m32() << " " << m_transform.m33() << " " << m_transform.m34() << "] ";
+ ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "]";
+ }
+ ts << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(childrenTransform ";
+ if (m_childrenTransform.isIdentity())
+ ts << "identity";
+ else {
+ ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] ";
+ ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] ";
+ ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] ";
+ ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "]";
+ }
+ ts << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(children " << m_children.size() << "\n";
+
+ unsigned i;
+ for (i = 0; i < m_children.size(); i++)
+ m_children[i]->dumpLayer(ts, indent+2);
+ writeIndent(ts, indent + 1);
+ ts << ")\n";
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h
new file mode 100644
index 0000000..f928ce8
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsLayer.h
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsLayer_h
+#define GraphicsLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Animation.h"
+#include "Color.h"
+#include "FloatPoint.h"
+#include "FloatPoint3D.h"
+#include "FloatSize.h"
+#include "GraphicsLayerClient.h"
+#include "TransformationMatrix.h"
+#include "TransformOperations.h"
+#include <wtf/OwnPtr.h>
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+@class WebLayer;
+@class CALayer;
+typedef WebLayer PlatformLayer;
+typedef CALayer* NativeLayer;
+#else
+typedef void* PlatformLayer;
+typedef void* NativeLayer;
+#endif
+#else
+typedef void* PlatformLayer;
+typedef void* NativeLayer;
+#endif
+
+namespace WebCore {
+
+class FloatPoint3D;
+class GraphicsContext;
+class Image;
+class TextStream;
+class TimingFunction;
+
+// GraphicsLayer is an abstraction for a rendering surface with backing store,
+// which may have associated transformation and animations.
+
+class GraphicsLayer {
+public:
+ // Used to store one float value of a keyframe animation.
+ class FloatValue {
+ public:
+ FloatValue(float key, float value, const TimingFunction* timingFunction = 0)
+ : m_key(key), m_value(value), m_timingFunction(0)
+ {
+ if (timingFunction)
+ m_timingFunction.set(new TimingFunction(*timingFunction));
+ }
+
+ FloatValue(const FloatValue& other)
+ : m_key(other.key()), m_value(other.value()), m_timingFunction(0)
+ {
+ if (other.timingFunction())
+ m_timingFunction.set(new TimingFunction(*other.timingFunction()));
+ }
+
+ const FloatValue& operator=(const FloatValue& other)
+ {
+ if (&other != this)
+ set(other.key(), other.value(), other.timingFunction());
+ return *this;
+ }
+
+ void set(float key, float value, const TimingFunction*);
+
+ float key() const { return m_key; }
+ float value() const { return m_value; }
+ const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
+
+ private:
+ float m_key;
+ float m_value;
+ OwnPtr<TimingFunction> m_timingFunction;
+ };
+
+
+ class FloatValueList {
+ public:
+ void insert(float key, float value, const TimingFunction* timingFunction);
+
+ size_t size() const { return m_values.size(); }
+ const FloatValue& at(size_t i) const { return m_values.at(i); }
+ const Vector<FloatValue>& values() const { return m_values; }
+
+ private:
+ Vector<FloatValue> m_values;
+ };
+
+ // Used to store one transform in a keyframe list.
+ class TransformValue {
+ public:
+ TransformValue(float key = NAN, const TransformOperations* value = 0, const TimingFunction* timingFunction = 0)
+ : m_key(key)
+ {
+ if (value)
+ m_value.set(new TransformOperations(*value));
+ if (timingFunction)
+ m_timingFunction.set(new TimingFunction(*timingFunction));
+ }
+
+ TransformValue(const TransformValue& other)
+ : m_key(other.key())
+ {
+ if (other.value())
+ m_value.set(new TransformOperations(*other.value()));
+ if (other.timingFunction())
+ m_timingFunction.set(new TimingFunction(*other.timingFunction()));
+ }
+
+ const TransformValue& operator=(const TransformValue& other)
+ {
+ if (&other != this)
+ set(other.key(), other.value(), other.timingFunction());
+ return *this;
+ }
+
+ void set(float key, const TransformOperations* value, const TimingFunction* timingFunction);
+
+ float key() const { return m_key; }
+ const TransformOperations* value() const { return m_value.get(); }
+ const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
+
+ private:
+ float m_key;
+ OwnPtr<TransformOperations> m_value;
+ OwnPtr<TimingFunction> m_timingFunction;
+ };
+
+ // Used to store a series of transforms in a keyframe list.
+ class TransformValueList {
+ public:
+ typedef Vector<TransformOperation::OperationType> FunctionList;
+
+ size_t size() const { return m_values.size(); }
+ const TransformValue& at(size_t i) const { return m_values.at(i); }
+ const Vector<TransformValue>& values() const { return m_values; }
+
+ void insert(float key, const TransformOperations* value, const TimingFunction* timingFunction);
+
+ // return a list of the required functions. List is empty if keyframes are not valid
+ // If return value is true, functions contain rotations of >= 180 degrees
+ void makeFunctionList(FunctionList& list, bool& isValid, bool& hasBigRotation) const;
+ private:
+ Vector<TransformValue> m_values;
+ };
+
+ static GraphicsLayer* createGraphicsLayer(GraphicsLayerClient*);
+
+ virtual ~GraphicsLayer();
+
+ GraphicsLayerClient* client() const { return m_client; }
+
+ // Layer name. Only used to identify layers in debug output
+ const String& name() const { return m_name; }
+ virtual void setName(const String& name) { m_name = name; }
+
+ // For hosting this GraphicsLayer in a native layer hierarchy.
+ virtual NativeLayer nativeLayer() const { return 0; }
+
+ GraphicsLayer* parent() const { return m_parent; };
+ void setParent(GraphicsLayer* layer) { m_parent = layer; } // Internal use only.
+
+ const Vector<GraphicsLayer*>& children() const { return m_children; }
+
+ // Add child layers. If the child is already parented, it will be removed from its old parent.
+ virtual void addChild(GraphicsLayer*);
+ virtual void addChildAtIndex(GraphicsLayer*, int index);
+ virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+
+ void removeAllChildren();
+ virtual void removeFromParent();
+
+ // Offset is origin of the renderer minus origin of the graphics layer (so either zero or negative).
+ IntSize offsetFromRenderer() const { return m_offsetFromRenderer; }
+ void setOffsetFromRenderer(const IntSize& offset) { m_offsetFromRenderer = offset; }
+
+ // The position of the layer (the location of its top-left corner in its parent)
+ const FloatPoint& position() const { return m_position; }
+ virtual void setPosition(const FloatPoint& p) { m_position = p; }
+
+ // Anchor point: (0, 0) is top left, (1, 1) is bottom right. The anchor point
+ // affects the origin of the transforms.
+ const FloatPoint3D& anchorPoint() const { return m_anchorPoint; }
+ virtual void setAnchorPoint(const FloatPoint3D& p) { m_anchorPoint = p; }
+
+ // The bounds of the layer
+ const FloatSize& size() const { return m_size; }
+ virtual void setSize(const FloatSize& size) { m_size = size; }
+
+ const TransformationMatrix& transform() const { return m_transform; }
+ virtual void setTransform(const TransformationMatrix& t) { m_transform = t; }
+
+ const TransformationMatrix& childrenTransform() const { return m_childrenTransform; }
+ virtual void setChildrenTransform(const TransformationMatrix& t) { m_childrenTransform = t; }
+
+ bool preserves3D() const { return m_preserves3D; }
+ virtual void setPreserves3D(bool b) { m_preserves3D = b; }
+
+ bool masksToBounds() const { return m_masksToBounds; }
+ virtual void setMasksToBounds(bool b) { m_masksToBounds = b; }
+
+ bool drawsContent() const { return m_drawsContent; }
+ virtual void setDrawsContent(bool b) { m_drawsContent = b; }
+
+ // The color used to paint the layer backgrounds
+ const Color& backgroundColor() const { return m_backgroundColor; }
+ virtual void setBackgroundColor(const Color&, const Animation* = 0, double beginTime = 0);
+ virtual void clearBackgroundColor();
+ bool backgroundColorSet() const { return m_backgroundColorSet; }
+
+ // opaque means that we know the layer contents have no alpha
+ bool contentsOpaque() const { return m_contentsOpaque; }
+ virtual void setContentsOpaque(bool b) { m_contentsOpaque = b; }
+
+ bool backfaceVisibility() const { return m_backfaceVisibility; }
+ virtual void setBackfaceVisibility(bool b) { m_backfaceVisibility = b; }
+
+ float opacity() const { return m_opacity; }
+ // return true if we started an animation
+ virtual bool setOpacity(float o, const Animation* = 0, double beginTime = 0);
+
+ // Some GraphicsLayers paint only the foreground or the background content
+ GraphicsLayerPaintingPhase drawingPhase() const { return m_paintingPhase; }
+ void setDrawingPhase(GraphicsLayerPaintingPhase phase) { m_paintingPhase = phase; }
+
+ virtual void setNeedsDisplay() = 0;
+ // mark the given rect (in layer coords) as needing dispay. Never goes deep.
+ virtual void setNeedsDisplayInRect(const FloatRect&) = 0;
+
+ virtual bool animateTransform(const TransformValueList&, const IntSize&, const Animation*, double beginTime, bool isTransition) = 0;
+ virtual bool animateFloat(AnimatedPropertyID, const FloatValueList&, const Animation*, double beginTime) = 0;
+
+ void removeFinishedAnimations(const String& name, int index, bool reset);
+ void removeFinishedTransitions(AnimatedPropertyID);
+ void removeAllAnimations();
+
+ virtual void suspendAnimations();
+ virtual void resumeAnimations();
+
+ // Layer contents
+ virtual void setContentsToImage(Image*) { }
+ virtual void setContentsToVideo(PlatformLayer*) { }
+ virtual void setContentsBackgroundColor(const Color&) { }
+ virtual void clearContents() { }
+
+ virtual void updateContentsRect() { }
+
+ // Callback from the underlying graphics system to draw layer contents.
+ void paintGraphicsLayerContents(GraphicsContext&, const IntRect& clip);
+
+ virtual PlatformLayer* platformLayer() const { return 0; }
+
+ void dumpLayer(TextStream&, int indent = 0) const;
+
+#ifndef NDEBUG
+ int repaintCount() const { return m_repaintCount; }
+ int incrementRepaintCount() { return ++m_repaintCount; }
+#endif
+
+ // Platform behaviors
+ static bool graphicsContextsFlipped();
+
+#ifndef NDEBUG
+ static bool showDebugBorders();
+ static bool showRepaintCounter();
+
+ void updateDebugIndicators();
+
+ virtual void setDebugBackgroundColor(const Color&) { }
+ virtual void setDebugBorder(const Color&, float /*borderWidth*/) { }
+ // z-position is the z-equivalent of position(). It's only used for debugging purposes.
+ virtual float zPosition() const { return m_zPosition; }
+ virtual void setZPosition(float);
+#endif
+
+ static String propertyIdToString(AnimatedPropertyID);
+
+protected:
+ GraphicsLayer(GraphicsLayerClient*);
+
+ void dumpProperties(TextStream&, int indent) const;
+
+ // returns -1 if not found
+ int findAnimationEntry(AnimatedPropertyID, short index) const;
+ void addAnimationEntry(AnimatedPropertyID, short index, bool isTransition, const Animation*);
+
+ virtual void removeAnimation(int /*index*/, bool /*reset*/) {}
+ void removeAllAnimationsForProperty(AnimatedPropertyID);
+
+ GraphicsLayerClient* m_client;
+ String m_name;
+
+ // Offset from the owning renderer
+ IntSize m_offsetFromRenderer;
+
+ // Position is relative to the parent GraphicsLayer
+ FloatPoint m_position;
+ FloatPoint3D m_anchorPoint;
+ FloatSize m_size;
+ TransformationMatrix m_transform;
+ TransformationMatrix m_childrenTransform;
+
+ Color m_backgroundColor;
+ float m_opacity;
+#ifndef NDEBUG
+ float m_zPosition;
+#endif
+
+ bool m_backgroundColorSet : 1;
+ bool m_contentsOpaque : 1;
+ bool m_preserves3D: 1;
+ bool m_backfaceVisibility : 1;
+ bool m_usingTiledLayer : 1;
+ bool m_masksToBounds : 1;
+ bool m_drawsContent : 1;
+
+ GraphicsLayerPaintingPhase m_paintingPhase;
+
+ Vector<GraphicsLayer*> m_children;
+ GraphicsLayer* m_parent;
+
+ // AnimationEntry represents an animation of a property on this layer.
+ // For transform only, there may be more than one, in which case 'index'
+ // is an index into the list of transforms.
+ class AnimationEntry {
+ public:
+ AnimationEntry(const Animation* animation, AnimatedPropertyID property, short index, bool isTransition)
+ : m_animation(const_cast<Animation*>(animation))
+ , m_property(property)
+ , m_index(index)
+ , m_isCurrent(true)
+ , m_isTransition(isTransition)
+ {
+ }
+
+ const Animation* animation() const { return m_animation.get(); }
+ AnimatedPropertyID property() const { return m_property; }
+ int index() const { return m_index; }
+ bool isCurrent() const { return m_isCurrent; }
+ void setIsCurrent(bool b = true) { m_isCurrent = b; }
+ bool isTransition() const { return m_isTransition; }
+
+ bool matches(AnimatedPropertyID property, short index) const
+ {
+ return m_property == property && m_index == index;
+ }
+
+ void reset(const Animation* animation, bool isTransition)
+ {
+ m_animation = const_cast<Animation*>(animation);
+ m_isTransition = isTransition;
+ m_isCurrent = true;
+ }
+
+ private:
+ RefPtr<Animation> m_animation;
+ AnimatedPropertyID m_property : 14;
+ short m_index : 16;
+ bool m_isCurrent : 1;
+ bool m_isTransition : 1;
+ };
+
+ Vector<AnimationEntry> m_animations; // running animations/transitions
+
+#ifndef NDEBUG
+ int m_repaintCount;
+#endif
+};
+
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayer_h
+
diff --git a/WebCore/platform/graphics/GraphicsLayerClient.h b/WebCore/platform/graphics/GraphicsLayerClient.h
new file mode 100644
index 0000000..46382f2
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsLayerClient.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsLayerClient_h
+#define GraphicsLayerClient_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+namespace WebCore {
+
+class GraphicsContext;
+class GraphicsLayer;
+class IntPoint;
+class IntRect;
+class FloatPoint;
+
+enum GraphicsLayerPaintingPhase {
+ GraphicsLayerPaintBackgroundMask = (1 << 0),
+ GraphicsLayerPaintForegroundMask = (1 << 1),
+ GraphicsLayerPaintAllMask = (GraphicsLayerPaintBackgroundMask | GraphicsLayerPaintForegroundMask)
+};
+
+enum AnimatedPropertyID {
+ AnimatedPropertyInvalid,
+ AnimatedPropertyWebkitTransform,
+ AnimatedPropertyOpacity,
+ AnimatedPropertyBackgroundColor
+};
+
+class GraphicsLayerClient {
+public:
+ virtual ~GraphicsLayerClient() {}
+
+ // Callbacks for when hardware-accelerated transitions and animation started
+ virtual void notifyAnimationStarted(const GraphicsLayer*, double time) = 0;
+
+ virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) = 0;
+
+ // Return a rect for the "contents" of the graphics layer, i.e. video or image content, in GraphicsLayer coordinates.
+ virtual IntRect contentsBox(const GraphicsLayer*) = 0;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayerClient_h
diff --git a/WebCore/platform/graphics/GraphicsTypes.h b/WebCore/platform/graphics/GraphicsTypes.h
index cdf5e31..769207a 100644
--- a/WebCore/platform/graphics/GraphicsTypes.h
+++ b/WebCore/platform/graphics/GraphicsTypes.h
@@ -50,6 +50,14 @@ namespace WebCore {
CompositePlusLighter
};
+ // FIXME: Currently these constants have to match the values used in the SVG
+ // DOM API. That's a mistake. We need to make cut that dependency.
+ enum GradientSpreadMethod {
+ SpreadMethodPad = 1,
+ SpreadMethodReflect = 2,
+ SpreadMethodRepeat = 3
+ };
+
enum LineCap { ButtCap, RoundCap, SquareCap };
enum LineJoin { MiterJoin, RoundJoin, BevelJoin };
diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp
index 49961e1..08d96b4 100644
--- a/WebCore/platform/graphics/Image.cpp
+++ b/WebCore/platform/graphics/Image.cpp
@@ -119,7 +119,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl
FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(),
scaledTileSize.height() / intrinsicTileSize.height());
- TransformationMatrix patternTransform = TransformationMatrix().scale(scale.width(), scale.height());
+ TransformationMatrix patternTransform = TransformationMatrix().scaleNonUniform(scale.width(), scale.height());
FloatRect oneTileRect;
oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width()));
@@ -158,7 +158,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const Flo
vRule = RepeatTile;
FloatSize scale = calculatePatternScale(dstRect, srcRect, hRule, vRule);
- TransformationMatrix patternTransform = TransformationMatrix().scale(scale.width(), scale.height());
+ TransformationMatrix patternTransform = TransformationMatrix().scaleNonUniform(scale.width(), scale.height());
// We want to construct the phase such that the pattern is centered (when stretch is not
// set for a particular rule).
diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h
index c3cf2e7..70f6d49 100644
--- a/WebCore/platform/graphics/Image.h
+++ b/WebCore/platform/graphics/Image.h
@@ -118,9 +118,9 @@ public:
SharedBuffer* data() { return m_data.get(); }
- // It may look unusual that there is no start animation call as public API. This is because
- // we start and stop animating lazily. Animation begins whenever someone draws the image. It will
- // automatically pause once all observers no longer want to render the image anywhere.
+ // Animation begins whenever someone draws the image, so startAnimation() is not normally called.
+ // It will automatically pause once all observers no longer want to render the image anywhere.
+ virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) { }
virtual void stopAnimation() {}
virtual void resetAnimation() {}
@@ -164,11 +164,9 @@ protected:
void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator);
// Supporting tiled drawing
- virtual bool mayFillWithSolidColor() const { return false; }
+ virtual bool mayFillWithSolidColor() { return false; }
virtual Color solidColor() const { return Color(); }
- virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) { }
-
virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
#if PLATFORM(CG)
diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h
index cb24b4e..a05b1f0 100644
--- a/WebCore/platform/graphics/IntPoint.h
+++ b/WebCore/platform/graphics/IntPoint.h
@@ -59,7 +59,7 @@ class TPoint;
class wxPoint;
#endif
-#if PLATFORM(SKIA)
+#if (PLATFORM(SKIA) || PLATFORM(SGL))
struct SkPoint;
struct SkIPoint;
#endif
@@ -128,7 +128,7 @@ public:
operator wxPoint() const;
#endif
-#if PLATFORM(SKIA)
+#if (PLATFORM(SKIA) || PLATFORM(SGL))
IntPoint(const SkIPoint&);
operator SkIPoint() const;
operator SkPoint() const;
diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h
index 03784a3..1be98b8 100644
--- a/WebCore/platform/graphics/IntRect.h
+++ b/WebCore/platform/graphics/IntRect.h
@@ -58,7 +58,7 @@ class TRect;
class wxRect;
#endif
-#if PLATFORM(SKIA)
+#if (PLATFORM(SKIA) || PLATFORM(SGL))
struct SkRect;
struct SkIRect;
#endif
@@ -158,7 +158,7 @@ public:
operator CGRect() const;
#endif
-#if PLATFORM(SKIA)
+#if (PLATFORM(SKIA) || PLATFORM(SGL))
IntRect(const SkIRect&);
operator SkRect() const;
operator SkIRect() const;
diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp
index 21e31fc..99d6aa4 100644
--- a/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,7 +27,9 @@
#if ENABLE(VIDEO)
#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
+#include "ContentType.h"
#include "IntRect.h"
#include "MIMETypeRegistry.h"
#include "FrameView.h"
@@ -47,26 +49,196 @@
#endif
namespace WebCore {
+
+// a null player to make MediaPlayer logic simpler
+
+class NullMediaPlayerPrivate : public MediaPlayerPrivateInterface {
+public:
+ NullMediaPlayerPrivate(MediaPlayer*) { }
+
+ virtual void load(const String&) { }
+ virtual void cancelLoad() { }
+
+ virtual void play() { }
+ virtual void pause() { }
+
+ virtual IntSize naturalSize() const { return IntSize(0, 0); }
+
+ virtual bool hasVideo() const { return false; }
+
+ virtual void setVisible(bool) { }
+
+ virtual float duration() const { return 0; }
+
+ virtual float currentTime() const { return 0; }
+ virtual void seek(float) { }
+ virtual bool seeking() const { return false; }
+
+ virtual void setEndTime(float) { }
+
+ virtual void setRate(float) { }
+ virtual bool paused() const { return false; }
+
+ virtual void setVolume(float) { }
+
+ virtual MediaPlayer::NetworkState networkState() const { return MediaPlayer::Empty; }
+ virtual MediaPlayer::ReadyState readyState() const { return MediaPlayer::HaveNothing; }
+
+ virtual float maxTimeSeekable() const { return 0; }
+ virtual float maxTimeBuffered() const { return 0; }
+
+ virtual int dataRate() const { return 0; }
+
+ virtual bool totalBytesKnown() const { return false; }
+ virtual unsigned totalBytes() const { return 0; }
+ virtual unsigned bytesLoaded() const { return 0; }
+
+ virtual void setSize(const IntSize&) { }
+
+ virtual void paint(GraphicsContext*, const IntRect&) { }
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ virtual void setPoster(const String& /*url*/) { }
+ virtual void deliverNotification(MediaPlayerProxyNotificationType) { }
+ virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) { }
+#endif
+};
+
+static MediaPlayerPrivateInterface* createNullMediaPlayer(MediaPlayer* player)
+{
+ return new NullMediaPlayerPrivate(player);
+}
+
+
+// engine support
+
+struct MediaPlayerFactory {
+ MediaPlayerFactory(CreateMediaEnginePlayer constructor, MediaEngineSupportedTypes getSupportedTypes, MediaEngineSupportsType supportsTypeAndCodecs)
+ : constructor(constructor)
+ , getSupportedTypes(getSupportedTypes)
+ , supportsTypeAndCodecs(supportsTypeAndCodecs)
+ {
+ }
+
+ CreateMediaEnginePlayer constructor;
+ MediaEngineSupportedTypes getSupportedTypes;
+ MediaEngineSupportsType supportsTypeAndCodecs;
+};
+
+static void addMediaEngine(CreateMediaEnginePlayer, MediaEngineSupportedTypes, MediaEngineSupportsType);
+static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, const String& codecs);
+
+static Vector<MediaPlayerFactory*>& installedMediaEngines()
+{
+ DEFINE_STATIC_LOCAL(Vector<MediaPlayerFactory*>, installedEngines, ());
+ static bool enginesQueried = false;
+
+ if (!enginesQueried) {
+ enginesQueried = true;
+ MediaPlayerPrivate::registerMediaEngine(addMediaEngine);
+
+ // register additional engines here
+ }
- MediaPlayer::MediaPlayer(MediaPlayerClient* client)
+ return installedEngines;
+}
+
+static void addMediaEngine(CreateMediaEnginePlayer constructor, MediaEngineSupportedTypes getSupportedTypes, MediaEngineSupportsType supportsType)
+{
+ ASSERT(constructor);
+ ASSERT(getSupportedTypes);
+ ASSERT(supportsType);
+ installedMediaEngines().append(new MediaPlayerFactory(constructor, getSupportedTypes, supportsType));
+}
+
+static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, const String& codecs)
+{
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+
+ if (engines.isEmpty())
+ return 0;
+
+ MediaPlayerFactory* engine = 0;
+ MediaPlayer::SupportsType supported = MediaPlayer::IsNotSupported;
+
+ unsigned count = engines.size();
+ for (unsigned ndx = 0; ndx < count; ndx++) {
+ MediaPlayer::SupportsType engineSupport = engines[ndx]->supportsTypeAndCodecs(type, codecs);
+ if (engineSupport > supported) {
+ supported = engineSupport;
+ engine = engines[ndx];
+ }
+ }
+
+ return engine;
+}
+
+// media player
+
+MediaPlayer::MediaPlayer(MediaPlayerClient* client)
: m_mediaPlayerClient(client)
- , m_private(new MediaPlayerPrivate(this))
+ , m_private(createNullMediaPlayer(this))
+ , m_currentMediaEngine(0)
, m_frameView(0)
, m_visible(false)
, m_rate(1.0f)
, m_volume(1.0f)
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ , m_playerProxy(0)
+#endif
{
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+ if (!engines.isEmpty()) {
+ m_currentMediaEngine = engines[0];
+ m_private.clear();
+ m_private.set(engines[0]->constructor(this));
+ }
+#endif
}
MediaPlayer::~MediaPlayer()
{
- delete m_private;
}
-void MediaPlayer::load(const String& url)
+void MediaPlayer::load(const String& url, const ContentType& contentType)
+{
+ String type = contentType.type();
+ String codecs = contentType.parameter("codecs");
+
+ // if we don't know the MIME type, see if the path can help
+ if (type.isEmpty())
+ type = MIMETypeRegistry::getMIMETypeForPath(url);
+
+ MediaPlayerFactory* engine = chooseBestEngineForTypeAndCodecs(type, codecs);
+
+ // if we didn't find an engine that claims the MIME type, just use the first engine
+ if (!engine)
+ engine = installedMediaEngines()[0];
+
+ // don't delete and recreate the player unless it comes from a different engine
+ if (engine && m_currentMediaEngine != engine) {
+ m_currentMediaEngine = engine;
+ m_private.clear();
+ m_private.set(engine->constructor(this));
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ m_private->setMediaPlayerProxy(m_playerProxy);
+#endif
+
+ }
+
+ if (m_private)
+ m_private->load(url);
+ else
+ m_private.set(createNullMediaPlayer(this));
+}
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+void MediaPlayer::setPoster(const String& url)
{
- m_private->load(url);
+ m_private->setPoster(url);
}
+#endif
void MediaPlayer::cancelLoad()
{
@@ -90,7 +262,7 @@ float MediaPlayer::duration() const
float MediaPlayer::currentTime() const
{
- return m_private->currentTime();
+ return m_private->currentTime();
}
void MediaPlayer::seek(float time)
@@ -193,10 +365,10 @@ unsigned MediaPlayer::totalBytes()
return m_private->totalBytes();
}
-void MediaPlayer::setRect(const IntRect& r)
+void MediaPlayer::setSize(const IntSize& size)
{
- m_rect = r;
- m_private->setRect(r);
+ m_size = size;
+ m_private->setSize(size);
}
bool MediaPlayer::visible() const
@@ -215,29 +387,47 @@ void MediaPlayer::paint(GraphicsContext* p, const IntRect& r)
m_private->paint(p, r);
}
-bool MediaPlayer::supportsType(const String& type)
+MediaPlayer::SupportsType MediaPlayer::supportsType(ContentType contentType)
{
- HashSet<String> types;
- getSupportedTypes(types);
- return MIMETypeRegistry::isSupportedMediaMIMEType(type) && types.contains(type);
+ String type = contentType.type();
+ String codecs = contentType.parameter("codecs");
+ MediaPlayerFactory* engine = chooseBestEngineForTypeAndCodecs(type, codecs);
+
+ if (!engine)
+ return IsNotSupported;
+
+ return engine->supportsTypeAndCodecs(type, codecs);
}
void MediaPlayer::getSupportedTypes(HashSet<String>& types)
{
- MediaPlayerPrivate::getSupportedTypes(types);
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+ if (engines.isEmpty())
+ return;
+
+ unsigned count = engines.size();
+ for (unsigned ndx = 0; ndx < count; ndx++)
+ engines[ndx]->getSupportedTypes(types);
}
-
+
bool MediaPlayer::isAvailable()
{
- static bool availabityKnown = false;
- static bool isAvailable;
- if (!availabityKnown) {
- isAvailable = MediaPlayerPrivate::isAvailable();
- availabityKnown = true;
- }
- return isAvailable;
+ return !installedMediaEngines().isEmpty();
}
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+void MediaPlayer::deliverNotification(MediaPlayerProxyNotificationType notification)
+{
+ m_private->deliverNotification(notification);
+}
+
+void MediaPlayer::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
+{
+ m_playerProxy = proxy;
+ m_private->setMediaPlayerProxy(proxy);
+}
+#endif
+
void MediaPlayer::networkStateChanged()
{
if (m_mediaPlayerClient)
@@ -262,11 +452,29 @@ void MediaPlayer::timeChanged()
m_mediaPlayerClient->mediaPlayerTimeChanged(this);
}
+void MediaPlayer::sizeChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerSizeChanged(this);
+}
+
void MediaPlayer::repaint()
{
if (m_mediaPlayerClient)
m_mediaPlayerClient->mediaPlayerRepaint(this);
}
+void MediaPlayer::durationChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerDurationChanged(this);
+}
+
+void MediaPlayer::rateChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerRateChanged(this);
+}
+
}
#endif
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
index 203f299..7d90e44 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -28,52 +28,78 @@
#if ENABLE(VIDEO)
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "MediaPlayerProxy.h"
+#endif
+
#include "IntRect.h"
#include "StringHash.h"
#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
#include <wtf/Noncopyable.h>
namespace WebCore {
+class ContentType;
class FrameView;
class GraphicsContext;
+class IntRect;
class IntSize;
class MediaPlayer;
-class MediaPlayerPrivate;
+class MediaPlayerPrivateInterface;
class String;
class MediaPlayerClient {
public:
virtual ~MediaPlayerClient() { }
+
+ // the network state has changed
virtual void mediaPlayerNetworkStateChanged(MediaPlayer*) { }
+
+ // the ready state has changed
virtual void mediaPlayerReadyStateChanged(MediaPlayer*) { }
+
+ // the volume or muted state has changed
virtual void mediaPlayerVolumeChanged(MediaPlayer*) { }
+
+ // time has jumped, eg. not as a result of normal playback
virtual void mediaPlayerTimeChanged(MediaPlayer*) { }
+
+ // a new frame of video is available
virtual void mediaPlayerRepaint(MediaPlayer*) { }
+
+ // the media file duration has changed, or is now known
+ virtual void mediaPlayerDurationChanged(MediaPlayer*) { }
+
+ // the playback rate has changed
+ virtual void mediaPlayerRateChanged(MediaPlayer*) { }
+
+ // the movie size has changed
+ virtual void mediaPlayerSizeChanged(MediaPlayer*) { }
};
class MediaPlayer : Noncopyable {
public:
MediaPlayer(MediaPlayerClient*);
virtual ~MediaPlayer();
-
- static bool isAvailable();
- static bool supportsType(const String&);
+
+ // media engine support
+ enum SupportsType { IsNotSupported, IsSupported, MayBeSupported };
+ static MediaPlayer::SupportsType supportsType(ContentType contentType);
static void getSupportedTypes(HashSet<String>&);
+ static bool isAvailable();
IntSize naturalSize();
bool hasVideo();
void setFrameView(FrameView* frameView) { m_frameView = frameView; }
+ FrameView* frameView() { return m_frameView; }
bool inMediaDocument();
- // FIXME: it would be better to just have a getter and setter for size.
- // This is currently an absolute rect, which is not appropriate for
- // content with transforms
- IntRect rect() const { return m_rect; }
- void setRect(const IntRect& r);
+ IntSize size() const { return m_size; }
+ void setSize(const IntSize& size);
- void load(const String& url);
+ void load(const String& url, const ContentType& contentType);
void cancelLoad();
bool visible() const;
@@ -96,7 +122,7 @@ public:
float maxTimeBuffered();
float maxTimeSeekable();
-
+
unsigned bytesLoaded();
bool totalBytesKnown();
unsigned totalBytes();
@@ -108,33 +134,55 @@ public:
void paint(GraphicsContext*, const IntRect&);
- enum NetworkState { Empty, LoadFailed, Loading, LoadedMetaData, LoadedFirstFrame, Loaded };
+ enum NetworkState { Empty, Idle, Loading, Loaded, FormatError, NetworkError, DecodeError };
NetworkState networkState();
- enum ReadyState { DataUnavailable, CanShowCurrentFrame, CanPlay, CanPlayThrough };
+ enum ReadyState { HaveNothing, HaveMetadata, HaveCurrentData, HaveFutureData, HaveEnoughData };
ReadyState readyState();
void networkStateChanged();
void readyStateChanged();
void volumeChanged();
void timeChanged();
+ void sizeChanged();
+ void rateChanged();
+ void durationChanged();
void repaint();
-
+
+ MediaPlayerClient* mediaPlayerClient() const { return m_mediaPlayerClient; }
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ void setPoster(const String& url);
+ void deliverNotification(MediaPlayerProxyNotificationType notification);
+ void setMediaPlayerProxy(WebMediaPlayerProxy* proxy);
+#endif
+
private:
-
- friend class MediaPlayerPrivate;
-
+ static void initializeMediaEngines();
+
MediaPlayerClient* m_mediaPlayerClient;
- MediaPlayerPrivate* m_private;
+ OwnPtr<MediaPlayerPrivateInterface*> m_private;
+ void* m_currentMediaEngine;
FrameView* m_frameView;
- IntRect m_rect;
+ IntSize m_size;
bool m_visible;
float m_rate;
float m_volume;
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ WebMediaPlayerProxy* m_playerProxy; // not owned or used, passed to m_private
+#endif
};
+typedef MediaPlayerPrivateInterface* (*CreateMediaEnginePlayer)(MediaPlayer*);
+typedef void (*MediaEngineSupportedTypes)(HashSet<String>& types);
+typedef MediaPlayer::SupportsType (*MediaEngineSupportsType)(const String& type, const String& codecs);
+
+typedef void (*MediaEngineRegistrar)(CreateMediaEnginePlayer, MediaEngineSupportedTypes, MediaEngineSupportsType);
+
+
}
-#endif
+#endif // ENABLE(VIDEO)
+
#endif
diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h
new file mode 100644
index 0000000..2e73e7e
--- /dev/null
+++ b/WebCore/platform/graphics/MediaPlayerPrivate.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaPlayerPrivate_h
+#define MediaPlayerPrivate_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayer.h"
+
+namespace WebCore {
+
+class IntRect;
+class IntSize;
+class String;
+
+class MediaPlayerPrivateInterface {
+public:
+ virtual ~MediaPlayerPrivateInterface() { }
+
+ virtual void load(const String& url) = 0;
+ virtual void cancelLoad() = 0;
+
+ virtual void play() = 0;
+ virtual void pause() = 0;
+
+ virtual IntSize naturalSize() const = 0;
+
+ virtual bool hasVideo() const = 0;
+
+ virtual void setVisible(bool) = 0;
+
+ virtual float duration() const = 0;
+
+ virtual float currentTime() const = 0;
+ virtual void seek(float time) = 0;
+ virtual bool seeking() const = 0;
+
+ virtual void setEndTime(float time) = 0;
+
+ virtual void setRate(float) = 0;
+ virtual bool paused() const = 0;
+
+ virtual void setVolume(float) = 0;
+
+ virtual MediaPlayer::NetworkState networkState() const = 0;
+ virtual MediaPlayer::ReadyState readyState() const = 0;
+
+ virtual float maxTimeSeekable() const = 0;
+ virtual float maxTimeBuffered() const = 0;
+
+ virtual int dataRate() const = 0;
+
+ virtual bool totalBytesKnown() const { return totalBytes() > 0; }
+ virtual unsigned totalBytes() const = 0;
+ virtual unsigned bytesLoaded() const = 0;
+
+ virtual void setSize(const IntSize&) = 0;
+
+ virtual void paint(GraphicsContext*, const IntRect&) = 0 ;
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ virtual void setPoster(const String& url) = 0;
+ virtual void deliverNotification(MediaPlayerProxyNotificationType) = 0;
+ virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) = 0;
+#endif
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h
index 716a645..6981748 100644
--- a/WebCore/platform/graphics/Pattern.h
+++ b/WebCore/platform/graphics/Pattern.h
@@ -30,6 +30,7 @@
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include "TransformationMatrix.h"
#if PLATFORM(CG)
typedef struct CGPattern* CGPatternRef;
@@ -67,7 +68,9 @@ namespace WebCore {
Image* tileImage() const { return m_tileImage.get(); }
- PlatformPatternPtr createPlatformPattern(const TransformationMatrix& patternTransform) const;
+ // Pattern space is an abstract space that maps to the default user space by the transformation 'userSpaceTransformation'
+ PlatformPatternPtr createPlatformPattern(const TransformationMatrix& userSpaceTransformation) const;
+ void setPatternSpaceTransform(const TransformationMatrix& patternSpaceTransformation) { m_patternSpaceTransformation = patternSpaceTransformation; }
private:
Pattern(Image*, bool repeatX, bool repeatY);
@@ -75,6 +78,7 @@ namespace WebCore {
RefPtr<Image> m_tileImage;
bool m_repeatX;
bool m_repeatY;
+ TransformationMatrix m_patternSpaceTransformation;
};
} //namespace
diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp
index 9670b55..9f51037 100644
--- a/WebCore/platform/graphics/SimpleFontData.cpp
+++ b/WebCore/platform/graphics/SimpleFontData.cpp
@@ -136,20 +136,6 @@ SimpleFontData::~SimpleFontData()
}
}
-#if !PLATFORM(QT)
-float SimpleFontData::widthForGlyph(Glyph glyph) const
-{
- float width = m_glyphToWidthMap.widthForGlyph(glyph);
- if (width != cGlyphWidthUnknown)
- return width;
-
- width = platformWidthForGlyph(glyph);
- m_glyphToWidthMap.setWidthForGlyph(glyph, width);
-
- return width;
-}
-#endif
-
const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
{
return this;
diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h
index e572e30..d2dd0b9 100644
--- a/WebCore/platform/graphics/SimpleFontData.h
+++ b/WebCore/platform/graphics/SimpleFontData.h
@@ -131,7 +131,7 @@ public:
#endif
#if PLATFORM(WX)
- wxFont getWxFont() const { return m_font.font(); }
+ wxFont* getWxFont() const { return m_font.font(); }
#endif
private:
@@ -205,6 +205,21 @@ public:
mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties;
#endif
};
+
+
+#if !PLATFORM(QT)
+ALWAYS_INLINE float SimpleFontData::widthForGlyph(Glyph glyph) const
+{
+ float width = m_glyphToWidthMap.widthForGlyph(glyph);
+ if (width != cGlyphWidthUnknown)
+ return width;
+
+ width = platformWidthForGlyph(glyph);
+ m_glyphToWidthMap.setWidthForGlyph(glyph, width);
+
+ return width;
+}
+#endif
} // namespace WebCore
diff --git a/WebCore/platform/graphics/android/FontPlatformData.h b/WebCore/platform/graphics/android/FontPlatformData.h
index 2bb8834..56c7827 100644
--- a/WebCore/platform/graphics/android/FontPlatformData.h
+++ b/WebCore/platform/graphics/android/FontPlatformData.h
@@ -42,6 +42,8 @@ public:
FontPlatformData(const FontPlatformData&);
FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic);
FontPlatformData(const FontPlatformData& src, float textSize);
+ FontPlatformData(float size, bool syntheticBold, bool syntheticOblique);
+
~FontPlatformData();
FontPlatformData(WTF::HashTableDeletedValueType)
@@ -54,6 +56,7 @@ public:
bool operator==(const FontPlatformData& a) const;
void setupPaint(SkPaint*) const;
+ float size() const { return mTextSize; }
unsigned hash() const;
private:
diff --git a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
index e82c1f6..4496408 100644
--- a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
+++ b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
@@ -103,6 +103,13 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
trace(4);
}
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+ : mTypeface(NULL), mTextSize(size), mFakeBold(bold), mFakeItalic(oblique)
+{
+ inc_count();
+ trace(5);
+}
+
FontPlatformData::~FontPlatformData()
{
dec_count();
diff --git a/WebCore/platform/graphics/android/GradientAndroid.cpp b/WebCore/platform/graphics/android/GradientAndroid.cpp
index 71b7f73..8334d1c 100644
--- a/WebCore/platform/graphics/android/GradientAndroid.cpp
+++ b/WebCore/platform/graphics/android/GradientAndroid.cpp
@@ -42,6 +42,7 @@ public:
SkShader* m_shader;
SkShader::TileMode m_tileMode;
+ int m_colorCountWhenShaderWasBuilt;
};
namespace WebCore {
@@ -57,45 +58,54 @@ static U8CPU F2B(float x)
return (int)(x * 255);
}
-SkShader* Gradient::getShader(SkShader::TileMode mode) {
- if (NULL == m_gradient) {
+SkShader* Gradient::getShader(SkShader::TileMode mode)
+{
+ if (NULL == m_gradient)
m_gradient = new PlatformGradientRec;
- } else if (m_gradient->m_tileMode == mode) {
+ else if (mode == m_gradient->m_tileMode)
return m_gradient->m_shader;
+
+ // need to ensure that the m_stops array is sorted. We call getColor()
+ // which, as a side effect, does the sort.
+ // TODO: refactor Gradient.h to formally expose a sort method
+ {
+ float r, g, b, a;
+ this->getColor(0, &r, &g, &b, &a);
}
- SkPoint pts[2];
+ SkPoint pts[2] = { m_p0, m_p1 }; // convert to SkPoint
- android_setpt(&pts[0], m_p0);
- android_setpt(&pts[1], m_p1);
- size_t count = m_stops.size();
+ const size_t count = m_stops.size();
SkAutoMalloc storage(count * (sizeof(SkColor) + sizeof(SkScalar)));
SkColor* colors = (SkColor*)storage.get();
SkScalar* pos = (SkScalar*)(colors + count);
Vector<ColorStop>::iterator iter = m_stops.begin();
- int i = -1;
- while (i++, iter != m_stops.end()) {
+ for (int i = 0; iter != m_stops.end(); i++) {
pos[i] = SkFloatToScalar(iter->stop);
colors[i] = SkColorSetARGB(F2B(iter->alpha), F2B(iter->red),
- F2B(iter->green), F2B(iter->blue));
+ F2B(iter->green), F2B(iter->blue));
++iter;
}
SkShader* s;
- if (0 == count) {
- // it seems the spec says a zero-size gradient draws transparent
- s = new SkColorShader(0);
- } else if (m_radial) {
- s = SkGradientShader::CreateRadial(pts[0], SkFloatToScalar(m_r0),
- colors, pos, count, mode);
- } else {
+ if (m_radial)
+ // FIXME: SVG always passes 0 for m_r0
+ s = SkGradientShader::CreateRadial(pts[0],
+ SkFloatToScalar(m_r0 ? m_r0 : m_r1), colors, pos, count, mode);
+ else
s = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
- }
+ if (NULL == s)
+ s = new SkColorShader(0);
+
+ // zap our previous shader, if present
m_gradient->m_shader->safeUnref();
m_gradient->m_shader = s;
m_gradient->m_tileMode = mode;
+ SkMatrix matrix = m_gradientSpaceTransformation;
+ s->setLocalMatrix(matrix);
+
return s;
}
@@ -109,7 +119,7 @@ void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
paint.setAntiAlias(true);
paint.setShader(this->getShader(mode));
- android_gc2canvas(context)->drawRect(*android_setrect(&r, rect), paint);
+ android_gc2canvas(context)->drawRect(rect, paint);
}
diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
index 90ce354..3b4d9a9 100644
--- a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
+++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -46,6 +46,7 @@
#include "SkGradientShader.h"
#include "SkBitmapRef.h"
#include "SkString.h"
+#include "SkiaUtils.h"
using namespace std;
@@ -84,6 +85,7 @@ public:
struct State {
SkPath* mPath;
+ SkPathEffect* mPathEffect;
float mMiterLimit;
float mAlpha;
float mStrokeThickness;
@@ -98,6 +100,7 @@ public:
State() {
mPath = NULL; // lazily allocated
+ mPathEffect = 0;
mMiterLimit = 4;
mAlpha = 1;
mStrokeThickness = 0.0f; // Same as default in GraphicsContextPrivate.h
@@ -114,10 +117,12 @@ public:
State(const State& other) {
memcpy(this, &other, sizeof(State));
mPath = deepCopyPtr<SkPath>(other.mPath);
+ mPathEffect->safeRef();
}
~State() {
delete mPath;
+ mPathEffect->safeUnref();
}
void setShadow(int radius, int dx, int dy, SkColor c) {
@@ -269,6 +274,11 @@ public:
rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
}
+ SkPathEffect* pe = mState->mPathEffect;
+ if (pe) {
+ paint->setPathEffect(pe);
+ return false;
+ }
switch (mCG->strokeStyle()) {
case NoStroke:
case SolidStroke:
@@ -284,7 +294,7 @@ public:
if (width > 0) {
SkScalar intervals[] = { width, width };
- SkPathEffect* pe = new SkDashPathEffect(intervals, 2, 0);
+ pe = new SkDashPathEffect(intervals, 2, 0);
paint->setPathEffect(pe)->unref();
// return true if we're basically a dotted dash of squares
return RoundToInt(width) == RoundToInt(paint->getStrokeWidth());
@@ -315,7 +325,8 @@ static SkShader::TileMode SpreadMethod2TileMode(GradientSpreadMethod sm) {
}
static void extactShader(SkPaint* paint, ColorSpace cs, Pattern* pat,
- Gradient* grad, GradientSpreadMethod sm) {
+ Gradient* grad)
+{
switch (cs) {
case PatternColorSpace:
// createPlatformPattern() returns a new inst
@@ -324,6 +335,7 @@ static void extactShader(SkPaint* paint, ColorSpace cs, Pattern* pat,
break;
case GradientColorSpace: {
// grad->getShader() returns a cached obj
+ GradientSpreadMethod sm = grad->spreadMethod();
paint->setShader(grad->getShader(SpreadMethod2TileMode(sm)));
break;
}
@@ -400,9 +412,7 @@ void GraphicsContext::drawRect(const IntRect& rect)
return;
SkPaint paint;
- SkRect r;
-
- android_setrect(&r, rect);
+ SkRect r(rect);
if (fillColor().alpha()) {
m_data->setup_paint_fill(&paint);
@@ -488,9 +498,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
canvas->drawPoints(SkCanvas::kPoints_PointMode, count, verts, paint);
canvas->restore();
} else {
- SkPoint pts[2];
- android_setpt(&pts[0], point1);
- android_setpt(&pts[1], point2);
+ SkPoint pts[2] = { point1, point2 };
canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
}
}
@@ -546,10 +554,8 @@ void GraphicsContext::drawEllipse(const IntRect& rect)
return;
SkPaint paint;
- SkRect oval;
+ SkRect oval(rect);
- android_setrect(&oval, rect);
-
if (fillColor().rgb() & 0xFF000000) {
m_data->setup_paint_fill(&paint);
GC2Canvas(this)->drawOval(oval, paint);
@@ -579,10 +585,8 @@ void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
SkPath path;
SkPaint paint;
- SkRect oval;
+ SkRect oval(r);
- android_setrect(&oval, r);
-
if (strokeStyle() == NoStroke) {
m_data->setup_paint_fill(&paint); // we want the fill color
paint.setStyle(SkPaint::kStroke_Style);
@@ -644,7 +648,6 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
SkPaint paint;
SkPath path;
SkScalar radii[8];
- SkRect r;
radii[0] = SkIntToScalar(topLeft.width());
radii[1] = SkIntToScalar(topLeft.height());
@@ -654,7 +657,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
radii[5] = SkIntToScalar(bottomRight.height());
radii[6] = SkIntToScalar(bottomLeft.width());
radii[7] = SkIntToScalar(bottomLeft.height());
- path.addRoundRect(*android_setrect(&r, rect), radii);
+ path.addRoundRect(rect, radii);
m_data->setup_paint_fill(&paint);
GC2Canvas(this)->drawPath(path, paint);
@@ -663,16 +666,14 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
void GraphicsContext::fillRect(const FloatRect& rect)
{
SkPaint paint;
- SkRect r;
- android_setrect(&r, rect);
m_data->setup_paint_fill(&paint);
extactShader(&paint, m_common->state.fillColorSpace,
m_common->state.fillPattern.get(),
- m_common->state.fillGradient.get(), spreadMethod());
+ m_common->state.fillGradient.get());
- GC2Canvas(this)->drawRect(r, paint);
+ GC2Canvas(this)->drawRect(rect, paint);
}
void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
@@ -682,13 +683,11 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
if (color.rgb() & 0xFF000000) {
SkPaint paint;
- SkRect r;
- android_setrect(&r, rect);
m_data->setup_paint_common(&paint);
paint.setColor(color.rgb()); // punch in the specified color
paint.setShader(NULL); // in case we had one set
- GC2Canvas(this)->drawRect(r, paint);
+ GC2Canvas(this)->drawRect(rect, paint);
}
}
@@ -697,9 +696,7 @@ void GraphicsContext::clip(const FloatRect& rect)
if (paintingDisabled())
return;
- SkRect r;
-
- GC2Canvas(this)->clipRect(*android_setrect(&r, rect));
+ GC2Canvas(this)->clipRect(rect);
}
void GraphicsContext::clip(const Path& path)
@@ -720,8 +717,8 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness
//printf("-------- addInnerRoundedRectClip: [%d %d %d %d] thickness=%d\n", rect.x(), rect.y(), rect.width(), rect.height(), thickness);
SkPath path;
- SkRect r;
- android_setrect(&r, rect);
+ SkRect r(rect);
+
path.addOval(r, SkPath::kCW_Direction);
// only perform the inset if we won't invert r
if (2*thickness < rect.width() && 2*thickness < rect.height())
@@ -737,9 +734,7 @@ void GraphicsContext::clipOut(const IntRect& r)
if (paintingDisabled())
return;
- SkRect rect;
-
- GC2Canvas(this)->clipRect(*android_setrect(&rect, r), SkRegion::kDifference_Op);
+ GC2Canvas(this)->clipRect(r, SkRegion::kDifference_Op);
}
void GraphicsContext::clipOutEllipseInRect(const IntRect& r)
@@ -747,13 +742,24 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& r)
if (paintingDisabled())
return;
- SkRect oval;
- SkPath path;
+ SkPath path;
- path.addOval(*android_setrect(&oval, r), SkPath::kCCW_Direction);
+ path.addOval(r, SkPath::kCCW_Direction);
GC2Canvas(this)->clipPath(path, SkRegion::kDifference_Op);
}
+#if ENABLE(SVG)
+void GraphicsContext::clipPath(WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+ const SkPath* oldPath = m_data->getPath();
+ SkPath path(*oldPath);
+ path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
+ GC2Canvas(this)->clipPath(path);
+}
+#endif
+
void GraphicsContext::clipOut(const Path& p)
{
if (paintingDisabled())
@@ -893,7 +899,7 @@ void GraphicsContext::setAlpha(float alpha)
void GraphicsContext::setCompositeOperation(CompositeOperator op)
{
- m_data->mState->mPorterDuffMode = android_convert_compositeOp(op);
+ m_data->mState->mPorterDuffMode = WebCoreCompositeToSkiaComposite(op);
}
void GraphicsContext::clearRect(const FloatRect& rect)
@@ -902,12 +908,10 @@ void GraphicsContext::clearRect(const FloatRect& rect)
return;
SkPaint paint;
- SkRect r;
- android_setrect(&r, rect);
m_data->setup_paint_fill(&paint);
paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
- GC2Canvas(this)->drawRect(r, paint);
+ GC2Canvas(this)->drawRect(rect, paint);
}
void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
@@ -916,13 +920,10 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
return;
SkPaint paint;
- SkRect r;
-
- android_setrect(&r, rect);
m_data->setup_paint_stroke(&paint, NULL);
paint.setStrokeWidth(SkFloatToScalar(lineWidth));
- GC2Canvas(this)->drawRect(r, paint);
+ GC2Canvas(this)->drawRect(rect, paint);
}
void GraphicsContext::setLineCap(LineCap cap)
@@ -943,6 +944,29 @@ void GraphicsContext::setLineCap(LineCap cap)
}
}
+#if ENABLE(SVG)
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ if (paintingDisabled())
+ return;
+
+ size_t dashLength = dashes.size();
+ if (!dashLength)
+ return;
+
+ size_t count = (dashLength % 2) == 0 ? dashLength : dashLength * 2;
+ SkScalar* intervals = new SkScalar[count];
+
+ for (unsigned int i = 0; i < count; i++)
+ intervals[i] = SkFloatToScalar(dashes[i % dashLength]);
+ SkPathEffect **effectPtr = &m_data->mState->mPathEffect;
+ (*effectPtr)->safeUnref();
+ *effectPtr = new SkDashPathEffect(intervals, count, SkFloatToScalar(dashOffset));
+
+ delete[] intervals;
+}
+#endif
+
void GraphicsContext::setLineJoin(LineJoin join)
{
switch (join) {
@@ -997,8 +1021,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
return FloatRect();
const SkMatrix& matrix = GC2Canvas(this)->getTotalMatrix();
- SkRect r;
- android_setrect(&r, rect);
+ SkRect r(rect);
matrix.mapRect(&r);
FloatRect result(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop), SkScalarToFloat(r.width()), SkScalarToFloat(r.height()));
return result;
@@ -1041,7 +1064,13 @@ void GraphicsContext::setPlatformShouldAntialias(bool useAA)
TransformationMatrix GraphicsContext::getCTM() const
{
- return TransformationMatrix(GC2Canvas(this)->getTotalMatrix());
+ const SkMatrix& m = GC2Canvas(this)->getTotalMatrix();
+ return TransformationMatrix(SkScalarToDouble(m.getScaleX()), // a
+ SkScalarToDouble(m.getSkewY()), // b
+ SkScalarToDouble(m.getSkewX()), // c
+ SkScalarToDouble(m.getScaleY()), // d
+ SkScalarToDouble(m.getTranslateX()), // e
+ SkScalarToDouble(m.getTranslateY())); // f
}
///////////////////////////////////////////////////////////////////////////////
@@ -1056,12 +1085,6 @@ void GraphicsContext::addPath(const Path& p)
m_data->addPath(*p.platformPath());
}
-void GraphicsContext::drawPath()
-{
- this->fillPath();
- this->strokePath();
-}
-
void GraphicsContext::fillPath()
{
SkPath* path = m_data->getPath();
@@ -1082,7 +1105,7 @@ void GraphicsContext::fillPath()
extactShader(&paint, m_common->state.fillColorSpace,
m_common->state.fillPattern.get(),
- m_common->state.fillGradient.get(), spreadMethod());
+ m_common->state.fillGradient.get());
GC2Canvas(this)->drawPath(*path, paint);
}
@@ -1090,7 +1113,7 @@ void GraphicsContext::fillPath()
void GraphicsContext::strokePath()
{
const SkPath* path = m_data->getPath();
- if (paintingDisabled() || !path || strokeStyle() == NoStroke)
+ if (paintingDisabled() || !path)
return;
SkPaint paint;
@@ -1098,7 +1121,7 @@ void GraphicsContext::strokePath()
extactShader(&paint, m_common->state.strokeColorSpace,
m_common->state.strokePattern.get(),
- m_common->state.strokeGradient.get(), spreadMethod());
+ m_common->state.strokeGradient.get());
GC2Canvas(this)->drawPath(*path, paint);
}
diff --git a/WebCore/platform/graphics/android/ImageAndroid.cpp b/WebCore/platform/graphics/android/ImageAndroid.cpp
index 769ac43..5d81b56 100644
--- a/WebCore/platform/graphics/android/ImageAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageAndroid.cpp
@@ -42,6 +42,7 @@
#include "SkShader.h"
#include "SkString.h"
#include "SkTemplates.h"
+#include "SkiaUtils.h"
#include <utils/AssetManager.h>
@@ -78,6 +79,7 @@ BitmapImage::BitmapImage(SkBitmapRef* ref, ImageObserver* observer)
, m_frames(0)
, m_frameTimer(0)
, m_repetitionCount(0)
+ , m_repetitionCountStatus(Unknown)
, m_repetitionsComplete(0)
, m_isSolidColor(false)
, m_animationFinished(true)
@@ -111,6 +113,7 @@ void BitmapImage::invalidatePlatformData()
void BitmapImage::checkForSolidColor()
{
+ m_checkedForSolidColor = true;
m_isSolidColor = false;
if (frameCount() == 1) {
SkBitmapRef* ref = frameAtIndex(0);
@@ -148,12 +151,29 @@ void BitmapImage::checkForSolidColor()
return; // keep solid == false
}
m_isSolidColor = true;
- m_solidColor = android_SkPMColorToWebCoreColor(color);
+ m_solidColor = SkPMColorToWebCoreColor(color);
}
}
+static void round(SkIRect* dst, const WebCore::FloatRect& src)
+{
+ dst->set(SkScalarRound(SkFloatToScalar(src.x())),
+ SkScalarRound(SkFloatToScalar(src.y())),
+ SkScalarRound(SkFloatToScalar((src.x() + src.width()))),
+ SkScalarRound(SkFloatToScalar((src.y() + src.height()))));
+}
+
+static void round_scaled(SkIRect* dst, const WebCore::FloatRect& src,
+ float sx, float sy)
+{
+ dst->set(SkScalarRound(SkFloatToScalar(src.x() * sx)),
+ SkScalarRound(SkFloatToScalar(src.y() * sy)),
+ SkScalarRound(SkFloatToScalar((src.x() + src.width()) * sx)),
+ SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
+}
+
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
- const FloatRect& srcRect, CompositeOperator compositeOp)
+ const FloatRect& srcRect, CompositeOperator compositeOp)
{
startAnimation();
@@ -174,12 +194,11 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
}
SkIRect srcR;
- SkRect dstR;
+ SkRect dstR(dstRect);
float invScaleX = (float)bitmap.width() / image->origWidth();
float invScaleY = (float)bitmap.height() / image->origHeight();
- android_setrect(&dstR, dstRect);
- android_setrect_scaled(&srcR, srcRect, invScaleX, invScaleY);
+ round_scaled(&srcR, srcRect, invScaleX, invScaleY);
if (srcR.isEmpty() || dstR.isEmpty()) {
#ifdef TRACE_SKIPPED_BITMAPS
SkDebugf("----- skip bitmapimage: [%d %d] src-empty %d dst-empty %d\n",
@@ -194,7 +213,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
ctxt->setupFillPaint(&paint); // need global alpha among other things
paint.setFilterBitmap(true);
- paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
+ paint.setPorterDuffXfermode(WebCoreCompositeToSkiaComposite(compositeOp));
canvas->drawBitmapRect(bitmap, &srcR, dstR, &paint);
#ifdef TRACE_SUBSAMPLED_BITMAPS
@@ -214,7 +233,7 @@ void BitmapImage::setURL(const String& str)
///////////////////////////////////////////////////////////////////////////////
-void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect,
const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator compositeOp,
const FloatRect& destRect)
@@ -223,19 +242,40 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
if (!image) { // If it's too early we won't have an image yet.
return;
}
-
+
// in case we get called with an incomplete bitmap
- const SkBitmap& bitmap = image->bitmap();
- if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
+ const SkBitmap& origBitmap = image->bitmap();
+ if (origBitmap.getPixels() == NULL && origBitmap.pixelRef() == NULL) {
return;
}
-
- SkRect dstR;
- android_setrect(&dstR, destRect);
+
+ SkRect dstR(destRect);
if (dstR.isEmpty()) {
return;
}
-
+
+ SkIRect srcR;
+ // we may have to scale if the image has been subsampled (so save RAM)
+ bool imageIsSubSampled = image->origWidth() != origBitmap.width() ||
+ image->origHeight() != origBitmap.height();
+ float scaleX = 1;
+ float scaleY = 1;
+ if (imageIsSubSampled) {
+ scaleX = (float)image->origWidth() / origBitmap.width();
+ scaleY = (float)image->origHeight() / origBitmap.height();
+// SkDebugf("----- subsampled %g %g\n", scaleX, scaleY);
+ round_scaled(&srcR, srcRect, 1 / scaleX, 1 / scaleY);
+ } else {
+ round(&srcR, srcRect);
+ }
+
+ // now extract the proper subset of the src image
+ SkBitmap bitmap;
+ if (!origBitmap.extractSubset(&bitmap, srcR)) {
+ SkDebugf("--- Image::drawPattern calling extractSubset failed\n");
+ return;
+ }
+
SkCanvas* canvas = ctxt->platformContext()->mCanvas;
SkPaint paint;
ctxt->setupFillPaint(&paint); // need global alpha among other things
@@ -245,20 +285,32 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
SkShader::kRepeat_TileMode);
paint.setShader(shader)->unref();
// now paint is the only owner of shader
- paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
+ paint.setPorterDuffXfermode(WebCoreCompositeToSkiaComposite(compositeOp));
paint.setFilterBitmap(true);
-
+
SkMatrix matrix(patternTransform);
-
- float scaleX = (float)image->origWidth() / bitmap.width();
- float scaleY = (float)image->origHeight() / bitmap.height();
- matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY));
-
- matrix.postTranslate(SkFloatToScalar(phase.x()),
- SkFloatToScalar(phase.y()));
+
+ if (imageIsSubSampled) {
+ matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY));
+ }
+ // We also need to translate it such that the origin of the pattern is the
+ // origin of the destination rect, which is what WebKit expects. Skia uses
+ // the coordinate system origin as the base for the patter. If WebKit wants
+ // a shifted image, it will shift it from there using the patternTransform.
+ float tx = phase.x() + srcRect.x() * patternTransform.a();
+ float ty = phase.y() + srcRect.y() * patternTransform.d();
+ matrix.postTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty));
shader->setLocalMatrix(matrix);
+#if 0
+ SkDebugf("--- drawPattern: src [%g %g %g %g] dst [%g %g %g %g] transform [%g %g %g %g %g %g] matrix [%g %g %g %g %g %g]\n",
+ srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(),
+ destRect.x(), destRect.y(), destRect.width(), destRect.height(),
+ patternTransform.a(), patternTransform.b(), patternTransform.c(),
+ patternTransform.d(), patternTransform.e(), patternTransform.f(),
+ matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
+#endif
canvas->drawRect(dstR, paint);
-
+
#ifdef TRACE_SUBSAMPLED_BITMAPS
if (bitmap.width() != image->origWidth() ||
bitmap.height() != image->origHeight()) {
diff --git a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
index 4c6a246..70730d8 100644
--- a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
@@ -329,7 +329,11 @@ SkBitmapRef* ImageSource::createFrameAtIndex(size_t index)
m_decoder.m_gifDecoder->frameBufferAtIndex(index);
if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
return 0;
- return new SkBitmapRef(buffer->bitmap());
+ SkBitmap& bitmap = buffer->bitmap();
+ SkPixelRef* pixelRef = bitmap.pixelRef();
+ if (pixelRef)
+ pixelRef->setURI(m_decoder.m_url);
+ return new SkBitmapRef(bitmap);
}
#else
SkASSERT(index == 0);
diff --git a/WebCore/platform/graphics/android/PathAndroid.cpp b/WebCore/platform/graphics/android/PathAndroid.cpp
index cfcd2bc..e7c61d1 100644
--- a/WebCore/platform/graphics/android/PathAndroid.cpp
+++ b/WebCore/platform/graphics/android/PathAndroid.cpp
@@ -31,6 +31,7 @@
#include "StrokeStyleApplier.h"
#include "TransformationMatrix.h"
+#include "SkPaint.h"
#include "SkPath.h"
#include "SkRegion.h"
@@ -89,9 +90,7 @@ void Path::translate(const FloatSize& size)
FloatRect Path::boundingRect() const
{
- SkRect r;
-
- m_path->computeBounds(&r, SkPath::kExact_BoundsType);
+ const SkRect& r = m_path->getBounds();
return FloatRect( SkScalarToFloat(r.fLeft),
SkScalarToFloat(r.fTop),
SkScalarToFloat(r.width()),
@@ -196,18 +195,12 @@ void Path::addArc(const FloatPoint& p, float r, float sa, float ea,
void Path::addRect(const FloatRect& rect)
{
- SkRect r;
-
- android_setrect(&r, rect);
- m_path->addRect(r);
+ m_path->addRect(rect);
}
void Path::addEllipse(const FloatRect& rect)
{
- SkRect r;
-
- android_setrect(&r, rect);
- m_path->addOval(r);
+ m_path->addOval(rect);
}
void Path::clear()
@@ -254,7 +247,7 @@ void Path::apply(void* info, PathApplierFunction function) const
break;
case SkPath::kClose_Verb:
elem.type = PathElementCloseSubpath;
- elem.points = NULL;
+ elem.points = setfpts(fpts, 0, 0);
break;
case SkPath::kDone_Verb:
return;
@@ -268,6 +261,64 @@ void Path::transform(const TransformationMatrix& xform)
m_path->transform(xform);
}
+#if ENABLE(SVG)
+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();
+}
+#endif
+
///////////////////////////////////////////////////////////////////////////////
// Computes the bounding box for the stroke and style currently selected into
@@ -283,9 +334,9 @@ static FloatRect boundingBoxForCurrentStroke(GraphicsContext* context)
context->setupStrokePaint(&paint);
SkPath fillPath;
paint.getFillPath(*path, &fillPath);
- SkRect r;
- fillPath.computeBounds(&r, SkPath::kExact_BoundsType);
- return FloatRect(r.fLeft, r.fTop, r.width(), r.height());
+ const SkRect& r = fillPath.getBounds();
+ return FloatRect(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop),
+ SkScalarToFloat(r.width()), SkScalarToFloat(r.height()));
}
static GraphicsContext* scratchContext()
@@ -313,4 +364,30 @@ FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
return r;
}
+#if ENABLE(SVG)
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+#if 0
+ ASSERT(applier);
+ GraphicsContext* scratch = scratchContext();
+ scratch->save();
+
+ applier->strokeStyle(scratch);
+
+ SkPaint paint;
+ scratch->platformContext()->setupPaintForStroking(&paint, 0, 0);
+ SkPath strokePath;
+ paint.getFillPath(*platformPath(), &strokePath);
+ bool contains = SkPathContainsPoint(&strokePath, point,
+ SkPath::kWinding_FillType);
+
+ scratch->restore();
+ return contains;
+#else
+ // FIXME:
+ return false;
+#endif
+}
+#endif
+
}
diff --git a/WebCore/platform/graphics/android/PatternAndroid.cpp b/WebCore/platform/graphics/android/PatternAndroid.cpp
index ffdbbb1..ff2b522 100644
--- a/WebCore/platform/graphics/android/PatternAndroid.cpp
+++ b/WebCore/platform/graphics/android/PatternAndroid.cpp
@@ -40,14 +40,13 @@ static SkShader::TileMode toTileMode(bool doRepeat) {
return doRepeat ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
}
-SkShader* Pattern::createPlatformPattern(const TransformationMatrix& transform) const
+SkShader* Pattern::createPlatformPattern(const TransformationMatrix& ) const
{
SkBitmapRef* ref = tileImage()->nativeImageForCurrentFrame();
SkShader* s = SkShader::CreateBitmapShader(ref->bitmap(),
toTileMode(m_repeatX),
toTileMode(m_repeatY));
-
- // TODO: do I treat transform as a local matrix???
+ s->setLocalMatrix(m_patternSpaceTransformation);
return s;
}
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
index b13f45f..e0aecfa 100644
--- a/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
@@ -35,12 +35,9 @@ PlatformGraphicsContext::PlatformGraphicsContext(SkCanvas* canvas, WTF::Vector<C
{
}
-PlatformGraphicsContext::PlatformGraphicsContext() : m_deleteCanvas(true)
+PlatformGraphicsContext::PlatformGraphicsContext()
+ : mCanvas(new SkCanvas), m_deleteCanvas(true), m_buttons(0)
{
- mCanvas = new SkCanvas;
- // Since this is our own private SkCanvas, and has no relation to a picture
- // storing button references would be meaningless.
- m_buttons = NULL;
}
PlatformGraphicsContext::~PlatformGraphicsContext()
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
index dce8ef3..4eeb4c1 100644
--- a/WebCore/platform/graphics/android/PlatformGraphicsContext.h
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
@@ -34,7 +34,6 @@
#include "SkTDArray.h"
class SkCanvas;
-class WebCore::Node;
class Container {
public:
@@ -149,9 +148,6 @@ public:
PlatformGraphicsContext(SkCanvas* canvas, WTF::Vector<Container>* buttons);
~PlatformGraphicsContext();
- void setupFillPaint(GraphicsContext*, SkPaint*);
- void setupStrokePaint(GraphicsContext*, SkPaint*);
-
SkCanvas* mCanvas;
bool deleteUs() const { return m_deleteCanvas; }
diff --git a/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp b/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp
deleted file mode 100644
index 154d4f3..0000000
--- a/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright 2007, The Android Open Source Project
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "TransformationMatrix.h"
-
-#include "FloatRect.h"
-#include "IntRect.h"
-
-#include "android_graphics.h"
-
-namespace WebCore {
-
-static const double deg2rad = 0.017453292519943295769; // pi/180
-
-TransformationMatrix::TransformationMatrix()
-{
- m_transform.reset();
-}
-
-TransformationMatrix::TransformationMatrix(const SkMatrix& mat) : m_transform(mat) {}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform.reset();
-
- m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
- m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
- m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
-
- m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
- m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(c));
- m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
- m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
- m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
-
- m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
- m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(c));
- m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
-}
-
-void TransformationMatrix::map(double x, double y, double *x2, double *y2) const
-{
- SkPoint pt;
-
- m_transform.mapXY(SkDoubleToScalar(x), SkDoubleToScalar(y), &pt);
- *x2 = SkScalarToDouble(pt.fX);
- *y2 = SkScalarToDouble(pt.fY);
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect &rect) const
-{
- SkRect src, dst;
- SkIRect ir;
-
- android_setrect(&src, rect);
- m_transform.mapRect(&dst, src);
- // we round out to mimic enclosingIntRect()
- dst.roundOut(&ir);
-
- return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
-{
- SkRect r;
-
- android_setrect(&r, rect);
- m_transform.mapRect(&r);
-
- return FloatRect(r.fLeft, r.fTop, r.width(), r.height());
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return m_transform.isIdentity();
-}
-
-void TransformationMatrix::reset()
-{
- m_transform.reset();
-}
-
-double TransformationMatrix::a() const
-{
- return SkScalarToDouble(m_transform[0]);
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.set(0, SkDoubleToScalar(a));
-}
-
-double TransformationMatrix::b() const
-{
- return SkScalarToDouble(m_transform[1]);
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.set(1, SkDoubleToScalar(b));
-}
-
-double TransformationMatrix::c() const
-{
- return SkScalarToDouble(m_transform[3]);
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.set(3, SkDoubleToScalar(c));
-}
-
-double TransformationMatrix::d() const {
- return SkScalarToDouble(m_transform[4]);
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.set(4, SkDoubleToScalar(d));
-}
-
-double TransformationMatrix::e() const
-{
- return SkScalarToDouble(m_transform[2]);
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.set(2, SkDoubleToScalar(e));
-}
-
-double TransformationMatrix::f() const {
- return SkScalarToDouble(m_transform[5]);
-}
-void TransformationMatrix::setF(double f) {
- m_transform.set(5, SkDoubleToScalar(f));
-}
-
-TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
-{
- m_transform.preScale(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::rotate(double d)
-{
- m_transform.preRotate(SkDoubleToScalar(d));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
-{
- m_transform.preTranslate(SkDoubleToScalar(tx), SkDoubleToScalar(ty));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
-{
- m_transform.preSkew(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return SkScalarToDouble(m_transform[SkMatrix::kMScaleX]) * SkScalarToDouble(m_transform[SkMatrix::kMScaleY]) -
- SkScalarToDouble(m_transform[SkMatrix::kMSkewX]) * SkScalarToDouble(m_transform[SkMatrix::kMSkewY]);
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- // the constructor initializes inverse to the identity
- TransformationMatrix inverse;
-
- // if we are not invertible, inverse will stay identity
- m_transform.invert(&inverse.m_transform);
-
- return inverse;
-}
-
-TransformationMatrix::operator SkMatrix() const
-{
- return m_transform;
-}
-
-bool TransformationMatrix::operator==(const TransformationMatrix &m2) const
-{
- return m_transform == m2.m_transform;
-}
-
-TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2)
-{
- m_transform.setConcat(m2.m_transform, m_transform);
- return *this;
-}
-
-TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2)
-{
- TransformationMatrix cat;
-
- cat.m_transform.setConcat(m2.m_transform, m_transform);
- return cat;
-}
-
-}
diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp
index 1decfd8..cdd8afe 100644
--- a/WebCore/platform/graphics/android/android_graphics.cpp
+++ b/WebCore/platform/graphics/android/android_graphics.cpp
@@ -25,175 +25,38 @@
#include "config.h"
#include "android_graphics.h"
-#include "IntPoint.h"
#include "IntRect.h"
-#include "FloatPoint.h"
-#include "FloatRect.h"
#include "SkCanvas.h"
-#include "SkColorPriv.h"
#include "SkCornerPathEffect.h"
-#include "SkGradientShader.h"
#include "SkPath.h"
#include "SkRegion.h"
-SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src)
-{
- dst->set(SkIntToScalar(src.x()), SkIntToScalar(src.y()));
- return dst;
-}
-
-SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src)
-{
- dst->set(SkFloatToScalar(src.x()), SkFloatToScalar(src.y()));
- return dst;
-}
-
-SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src)
-{
- dst->set(SkIntToScalar(src.x()),
- SkIntToScalar(src.y()),
- SkIntToScalar(src.x() + src.width()),
- SkIntToScalar(src.y() + src.height()));
- return dst;
-}
-
-SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src)
-{
- dst->set(src.x(), src.y(),
- src.x() + src.width(),
- src.y() + src.height());
- return dst;
-}
-
-SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src)
-{
- dst->set(SkFloatToScalar(src.x()),
- SkFloatToScalar(src.y()),
- SkFloatToScalar(src.x() + src.width()),
- SkFloatToScalar(src.y() + src.height()));
- return dst;
-}
-
-SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src)
-{
- dst->set(SkScalarRound(SkFloatToScalar(src.x())),
- SkScalarRound(SkFloatToScalar(src.y())),
- SkScalarRound(SkFloatToScalar(src.x() + src.width())),
- SkScalarRound(SkFloatToScalar(src.y() + src.height())));
- return dst;
-}
-
-SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
- float sx, float sy)
-{
- dst->set(SkScalarRound(SkFloatToScalar(src.x() * sx)),
- SkScalarRound(SkFloatToScalar(src.y() * sy)),
- SkScalarRound(SkFloatToScalar((src.x() + src.width()) * sx)),
- SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
- return dst;
-}
-
-static const struct CompositOpToPorterDuffMode {
- uint8_t mCompositOp;
- uint8_t mPorterDuffMode;
-} gMapCompositOpsToPorterDuffModes[] = {
- { WebCore::CompositeClear, SkPorterDuff::kClear_Mode },
- { WebCore::CompositeCopy, SkPorterDuff::kSrc_Mode },
- { WebCore::CompositeSourceOver, SkPorterDuff::kSrcOver_Mode },
- { WebCore::CompositeSourceIn, SkPorterDuff::kSrcIn_Mode },
- { WebCore::CompositeSourceOut, SkPorterDuff::kSrcOut_Mode },
- { WebCore::CompositeSourceAtop, SkPorterDuff::kSrcATop_Mode },
- { WebCore::CompositeDestinationOver, SkPorterDuff::kDstOver_Mode },
- { WebCore::CompositeDestinationIn, SkPorterDuff::kDstIn_Mode },
- { WebCore::CompositeDestinationOut, SkPorterDuff::kDstOut_Mode },
- { WebCore::CompositeDestinationAtop, SkPorterDuff::kDstATop_Mode },
- { WebCore::CompositeXOR, SkPorterDuff::kXor_Mode },
- { WebCore::CompositePlusDarker, SkPorterDuff::kDarken_Mode },
- { WebCore::CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO
- { WebCore::CompositePlusLighter, SkPorterDuff::kLighten_Mode }
-};
-
-SkPorterDuff::Mode android_convert_compositeOp(WebCore::CompositeOperator op)
-{
- const CompositOpToPorterDuffMode* table = gMapCompositOpsToPorterDuffModes;
-
- for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToPorterDuffModes); i++) {
- if (table[i].mCompositOp == op) {
- return (SkPorterDuff::Mode)table[i].mPorterDuffMode;
- }
- }
-
- SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositOperator %d\n", op));
- return SkPorterDuff::kSrcOver_Mode; // fall-back
-}
-
-SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule rule)
-{
- // stretch == clamp
- // repeat == repeat
- // RoundTile???
-
- return WebCore::Image::RepeatTile == rule ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
-{
- SkASSERT(component == (uint8_t)component);
- return (component * scale + 0x8000) >> 16;
-}
-
-// move this guy into SkColor.h
-static SkColor SkPMColorToColor(SkPMColor pm)
-{
- if (0 == pm)
- return 0;
-
- unsigned a = SkGetPackedA32(pm);
- uint32_t scale = (255 << 16) / a;
-
- return SkColorSetARGB(a,
- InvScaleByte(SkGetPackedR32(pm), scale),
- InvScaleByte(SkGetPackedG32(pm), scale),
- InvScaleByte(SkGetPackedB32(pm), scale));
-}
-
-WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm)
-{
- SkColor c = SkPMColorToColor(pm);
-
- // need the cast to find the right constructor
- return WebCore::Color((int)SkColorGetR(c), (int)SkColorGetG(c),
- (int)SkColorGetB(c), (int)SkColorGetA(c));
-}
+///////////////////////////////////////////////////////////////////////////////
-const static SkColor focusOuterColors[] = {
- SkColorSetARGB(0xff, 0xB3, 0x3F, 0x08), // normal focus ring select
- SkColorSetARGB(0xff, 0x46, 0xb0, 0x00), // fake focus ring select, for phone, email, text
- SkColorSetARGB(0xff, 0xb0, 0x16, 0x00), // invalid focus ring color
- SkColorSetARGB(0xff, 0xAD, 0x5C, 0x0A), // normal focus ring pressed
- SkColorSetARGB(0xff, 0x36, 0xc0, 0x00) // fake focus ring pressed
+const static SkColor cursorOuterColors[] = {
+ SkColorSetARGB(0xff, 0xB3, 0x3F, 0x08), // normal ring select
+ SkColorSetARGB(0xff, 0x46, 0xb0, 0x00), // fake ring select, for phone, email, text
+ SkColorSetARGB(0xff, 0xAD, 0x5C, 0x0A), // normal ring pressed
+ SkColorSetARGB(0xff, 0x36, 0xc0, 0x00) // fake ring pressed
};
-const static SkColor focusInnerColors[] = {
- SkColorSetARGB(0xff, 0xFE, 0x92, 0x30), // normal focus ring select
- SkColorSetARGB(0xff, 0x8c, 0xd9, 0x00), // fake focus ring select, for phone, email, text
- SkColorSetARGB(0xff, 0xd9, 0x2c, 0x00), // invalid focus ring color
- SkColorSetARGB(0xff, 0xFE, 0xBD, 0x3A), // normal focus ring pressed
- SkColorSetARGB(0xff, 0x7c, 0xe9, 0x00) // fake focus ring pressed
+const static SkColor cursorInnerColors[] = {
+ SkColorSetARGB(0xff, 0xFE, 0x92, 0x30), // normal ring select
+ SkColorSetARGB(0xff, 0x8c, 0xd9, 0x00), // fake ring select, for phone, email, text
+ SkColorSetARGB(0xff, 0xFE, 0xBD, 0x3A), // normal ring pressed
+ SkColorSetARGB(0xff, 0x7c, 0xe9, 0x00) // fake ring pressed
};
-const static SkColor focusPressedColors[] = {
- SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B), // normal focus ring pressed
- SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00) // fake focus ring pressed
+const static SkColor cursorPressedColors[] = {
+ SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B), // normal ring pressed
+ SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00) // fake ring pressed
};
-#define FOCUS_RING_ROUNDEDNESS SkIntToScalar(5) // used to draw corners
-#define FOCUS_RING_INNER_DIAMETER SkFixedToScalar(SkIntToFixed(3)>>1) // 3/2 == 1.5
-#define FOCUS_RING_OUTER_OUTSET 2 // used to inflate rects added to region
+#define CURSOR_RING_ROUNDEDNESS SkIntToScalar(5) // used to draw corners
+#define CURSOR_RING_INNER_DIAMETER SkFixedToScalar(SkIntToFixed(3)>>1) // 3/2 == 1.5
+#define CURSOR_RING_OUTER_OUTSET 2 // used to inflate rects added to region
-void FocusRing::DrawRing(SkCanvas* canvas,
+void CursorRing::DrawRing(SkCanvas* canvas,
const Vector<WebCore::IntRect>& rects, Flavor flavor)
{
unsigned rectCount = rects.size();
@@ -201,27 +64,28 @@ void FocusRing::DrawRing(SkCanvas* canvas,
SkPath path;
for (unsigned i = 0; i < rectCount; i++)
{
- SkIRect r;
+ SkRect r(rects[i]);
+ SkIRect ir;
- android_setrect(&r, rects[i]);
- r.inset(-FOCUS_RING_OUTER_OUTSET, -FOCUS_RING_OUTER_OUTSET);
- rgn.op(r, SkRegion::kUnion_Op);
+ r.round(&ir);
+ ir.inset(-CURSOR_RING_OUTER_OUTSET, -CURSOR_RING_OUTER_OUTSET);
+ rgn.op(ir, SkRegion::kUnion_Op);
}
rgn.getBoundaryPath(&path);
SkPaint paint;
paint.setAntiAlias(true);
- paint.setPathEffect(new SkCornerPathEffect(FOCUS_RING_ROUNDEDNESS))->unref();
+ paint.setPathEffect(new SkCornerPathEffect(CURSOR_RING_ROUNDEDNESS))->unref();
if (flavor >= NORMAL_ANIMATING) { // pressed
- paint.setColor(focusPressedColors[flavor - NORMAL_ANIMATING]);
+ paint.setColor(cursorPressedColors[flavor - NORMAL_ANIMATING]);
canvas->drawPath(path, paint);
}
paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(FOCUS_RING_OUTER_DIAMETER);
- paint.setColor(focusOuterColors[flavor]);
+ paint.setStrokeWidth(CURSOR_RING_OUTER_DIAMETER);
+ paint.setColor(cursorOuterColors[flavor]);
canvas->drawPath(path, paint);
- paint.setStrokeWidth(FOCUS_RING_INNER_DIAMETER);
- paint.setColor(focusInnerColors[flavor]);
+ paint.setStrokeWidth(CURSOR_RING_INNER_DIAMETER);
+ paint.setColor(cursorInnerColors[flavor]);
canvas->drawPath(path, paint);
}
diff --git a/WebCore/platform/graphics/android/android_graphics.h b/WebCore/platform/graphics/android/android_graphics.h
index 21492cf..348daf1 100644
--- a/WebCore/platform/graphics/android/android_graphics.h
+++ b/WebCore/platform/graphics/android/android_graphics.h
@@ -26,64 +26,39 @@
#ifndef android_graphics_DEFINED
#define android_graphics_DEFINED
-#include "Color.h"
-#include "Image.h"
#include "wtf/Vector.h"
-#include "SkColor.h"
-#include "SkPorterDuff.h"
-#include "SkScalar.h"
-#include "SkShader.h"
+#include "SkTypes.h"
class SkCanvas;
-struct SkPoint;
-struct SKRect;
namespace WebCore {
- class FloatRect;
- class IntPoint;
class IntRect;
class GraphicsContext;
}
-SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src);
-SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src);
-SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src);
-SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src);
-SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src);
-SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src);
-SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
- float sx, float sy);
-
-SkPorterDuff::Mode android_convert_compositeOp(WebCore::CompositeOperator);
-SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule);
-
-WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm);
-
SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc);
-// Data and methods for focus rings
+// Data and methods for cursor rings
// used to inflate node cache entry
-#define FOCUS_RING_HIT_TEST_RADIUS 5
+#define CURSOR_RING_HIT_TEST_RADIUS 5
-// used to inval rectangle enclosing pressed state of focus ring
-#define FOCUS_RING_OUTER_DIAMETER SkFixedToScalar(SkIntToFixed(13)>>2) // 13/4 == 3.25
+// used to inval rectangle enclosing pressed state of ring
+#define CURSOR_RING_OUTER_DIAMETER SkFixedToScalar(SkIntToFixed(13)>>2) // 13/4 == 3.25
-struct FocusRing {
+struct CursorRing {
public:
enum Flavor {
NORMAL_FLAVOR,
FAKE_FLAVOR,
- INVALID_FLAVOR,
NORMAL_ANIMATING,
FAKE_ANIMATING,
ANIMATING_COUNT = 2
};
-
- static void DrawRing(SkCanvas* ,
+
+ static void DrawRing(SkCanvas* ,
const Vector<WebCore::IntRect>& rects, Flavor );
};
#endif
-
diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp
index 9da9426..b23182d 100644
--- a/WebCore/platform/graphics/cairo/FontCairo.cpp
+++ b/WebCore/platform/graphics/cairo/FontCairo.cpp
@@ -2,6 +2,7 @@
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
* Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,8 +30,11 @@
#include "Font.h"
#include "GlyphBuffer.h"
+#include "Gradient.h"
#include "GraphicsContext.h"
+#include "Pattern.h"
#include "SimpleFontData.h"
+#include "TransformationMatrix.h"
namespace WebCore {
@@ -78,18 +82,51 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
}
if (context->textDrawingMode() & cTextFill) {
- float red, green, blue, alpha;
- fillColor.getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(cr, red, green, blue, alpha);
-
+ if (context->fillGradient()) {
+ cairo_set_source(cr, context->fillGradient()->platformGradient());
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else if (context->fillPattern()) {
+ TransformationMatrix affine;
+ cairo_set_source(cr, context->fillPattern()->createPlatformPattern(affine));
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else {
+ float red, green, blue, alpha;
+ fillColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
+ }
cairo_show_glyphs(cr, glyphs, numGlyphs);
}
if (context->textDrawingMode() & cTextStroke) {
- Color strokeColor = context->strokeColor();
- float red, green, blue, alpha;
- strokeColor.getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(cr, red, green, blue, alpha);
+ if (context->strokeGradient()) {
+ cairo_set_source(cr, context->strokeGradient()->platformGradient());
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else if (context->strokePattern()) {
+ TransformationMatrix affine;
+ cairo_set_source(cr, context->strokePattern()->createPlatformPattern(affine));
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else {
+ Color strokeColor = context->strokeColor();
+ float red, green, blue, alpha;
+ 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);
diff --git a/WebCore/platform/graphics/cairo/GradientCairo.cpp b/WebCore/platform/graphics/cairo/GradientCairo.cpp
index 7776424..72fb0c5 100644
--- a/WebCore/platform/graphics/cairo/GradientCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GradientCairo.cpp
@@ -57,6 +57,22 @@ cairo_pattern_t* Gradient::platformGradient()
++stopIterator;
}
+ switch (m_spreadMethod) {
+ case SpreadMethodPad:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_PAD);
+ break;
+ case SpreadMethodReflect:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REFLECT);
+ break;
+ case SpreadMethodRepeat:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REPEAT);
+ break;
+ }
+
+ cairo_matrix_t matrix = m_gradientSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(m_gradient, &matrix);
+
return m_gradient;
}
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index ef748cf..35ebd3c 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -87,22 +87,6 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const
cairo_fill(cr);
}
-static inline cairo_pattern_t* applySpreadMethod(cairo_pattern_t* pattern, GradientSpreadMethod spreadMethod)
-{
- switch (spreadMethod) {
- case SpreadMethodPad:
- cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
- break;
- case SpreadMethodReflect:
- cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REFLECT);
- break;
- case SpreadMethodRepeat:
- cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
- break;
- }
- return pattern;
-}
-
GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr)
: m_common(createGraphicsContextPrivate())
, m_data(new GraphicsContextPlatformPrivate)
@@ -122,7 +106,7 @@ TransformationMatrix GraphicsContext::getCTM() const
cairo_t* cr = platformContext();
cairo_matrix_t m;
cairo_get_matrix(cr, &m);
- return m;
+ return TransformationMatrix(m.xx, m.yx, m.xy, m.yy, m.x0, m.y0);
}
cairo_t* GraphicsContext::platformContext() const
@@ -463,7 +447,6 @@ void GraphicsContext::fillPath()
}
case GradientColorSpace:
cairo_pattern_t* pattern = m_common->state.fillGradient->platformGradient();
- pattern = applySpreadMethod(pattern, spreadMethod());
cairo_set_source(cr, pattern);
cairo_clip(cr);
cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
@@ -501,7 +484,6 @@ void GraphicsContext::strokePath()
}
case GradientColorSpace:
cairo_pattern_t* pattern = m_common->state.strokeGradient->platformGradient();
- pattern = applySpreadMethod(pattern, spreadMethod());
cairo_set_source(cr, pattern);
if (m_common->state.globalAlpha < 1.0f) {
cairo_push_group(cr);
@@ -750,8 +732,8 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform)
return;
cairo_t* cr = m_data->cr;
- const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
- cairo_transform(cr, matrix);
+ const cairo_matrix_t matrix = cairo_matrix_t(transform);
+ cairo_transform(cr, &matrix);
m_data->concatCTM(transform);
}
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
index 535f70d..55b2e25 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
+++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -51,6 +51,7 @@ public:
// NOTE: These may note be needed: review and remove once Cairo implementation is complete
, m_hdc(0)
, m_transparencyCount(0)
+ , m_shouldIncludeChildWindows(false)
#endif
{
}
@@ -94,6 +95,7 @@ public:
#elif PLATFORM(WIN)
HDC m_hdc;
unsigned m_transparencyCount;
+ bool m_shouldIncludeChildWindows;
#endif
};
diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index 3e06669..dff39b7 100644
--- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2007 Holger Hans Peter Freyther <zecke@selfish.org>
- * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
#include "Base64.h"
#include "BitmapImage.h"
+#include "Color.h"
#include "GraphicsContext.h"
#include "ImageData.h"
#include "MIMETypeRegistry.h"
@@ -126,17 +127,15 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
unsigned char* destRows = dataDst + desty * destBytesPerRow + destx * 4;
for (int y = 0; y < numRows; ++y) {
- unsigned char *row = dataSrc + stride * (y + originy);
+ unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * (y + originy));
for (int x = 0; x < numColumns; x++) {
- uint32_t *pixel = (uint32_t *) row + x + originx;
int basex = x * 4;
- if (unsigned int alpha = (*pixel & 0xff000000) >> 24) {
- destRows[basex] = (*pixel & 0x00ff0000) >> 16;
- destRows[basex + 1] = (*pixel & 0x0000ff00) >> 8;
- destRows[basex + 2] = (*pixel & 0x000000ff);
- destRows[basex + 3] = alpha;
- } else
- reinterpret_cast<uint32_t*>(destRows + basex)[0] = pixel[0];
+ unsigned* pixel = row + x + originx;
+ Color pixelColor = colorFromPremultipliedARGB(*pixel);
+ destRows[basex] = pixelColor.red();
+ destRows[basex + 1] = pixelColor.green();
+ destRows[basex + 2] = pixelColor.blue();
+ destRows[basex + 3] = pixelColor.alpha();
}
destRows += destBytesPerRow;
}
@@ -181,14 +180,15 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con
unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
for (int y = 0; y < numRows; ++y) {
- unsigned char *row = dataDst + stride * (y + desty);
+ unsigned* row = reinterpret_cast<unsigned*>(dataDst + stride * (y + desty));
for (int x = 0; x < numColumns; x++) {
- uint32_t *pixel = (uint32_t *) row + x + destx;
int basex = x * 4;
- if (unsigned int alpha = srcRows[basex + 3]) {
- *pixel = alpha << 24 | srcRows[basex] << 16 | srcRows[basex + 1] << 8 | srcRows[basex + 2];
- } else
- pixel[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0];
+ unsigned* pixel = row + x + destx;
+ Color pixelColor(srcRows[basex],
+ srcRows[basex + 1],
+ srcRows[basex + 2],
+ srcRows[basex + 3]);
+ *pixel = premultipliedARGBFromColor(pixelColor);
}
srcRows += srcBytesPerRow;
}
diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp
index 2850488..224154e 100644
--- a/WebCore/platform/graphics/cairo/ImageCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,10 +30,11 @@
#if PLATFORM(CAIRO)
-#include "TransformationMatrix.h"
+#include "Color.h"
#include "FloatRect.h"
#include "GraphicsContext.h"
#include "ImageObserver.h"
+#include "TransformationMatrix.h"
#include <cairo.h>
#include <math.h>
@@ -60,6 +62,7 @@ BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer)
, m_repetitionCountStatus(Unknown)
, m_repetitionsComplete(0)
, m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
, m_animationFinished(true)
, m_allDataReceived(true)
, m_haveSize(true)
@@ -180,8 +183,28 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con
void BitmapImage::checkForSolidColor()
{
- // FIXME: It's easy to implement this optimization. Just need to check the RGBA32 buffer to see if it is 1x1.
m_isSolidColor = false;
+ m_checkedForSolidColor = true;
+
+ if (frameCount() > 1)
+ return;
+
+ cairo_surface_t* frameSurface = frameAtIndex(0);
+ if (!frameSurface)
+ return;
+
+ ASSERT(cairo_surface_get_type(frameSurface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ int width = cairo_image_surface_get_width(frameSurface);
+ int height = cairo_image_surface_get_height(frameSurface);
+
+ if (width != 1 || height != 1)
+ return;
+
+ unsigned* pixelColor = reinterpret_cast<unsigned*>(cairo_image_surface_get_data(frameSurface));
+ m_solidColor = colorFromPremultipliedARGB(*pixelColor);
+
+ m_isSolidColor = true;
}
}
diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
index 6841599..c6d54f2 100644
--- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
@@ -111,7 +111,7 @@ void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer*
delete m_decoder;
m_decoder = 0;
if (data)
- setData(data, allDataReceived);
+ setData(data, allDataReceived);
}
bool ImageSource::initialized() const
diff --git a/WebCore/platform/graphics/cairo/PatternCairo.cpp b/WebCore/platform/graphics/cairo/PatternCairo.cpp
index 7d75db3..58c5d00 100644
--- a/WebCore/platform/graphics/cairo/PatternCairo.cpp
+++ b/WebCore/platform/graphics/cairo/PatternCairo.cpp
@@ -26,23 +26,26 @@
#include "config.h"
#include "Pattern.h"
-#include "TransformationMatrix.h"
#include "GraphicsContext.h"
+#include "TransformationMatrix.h"
#include <cairo.h>
namespace WebCore {
-cairo_pattern_t* Pattern::createPlatformPattern(const TransformationMatrix& patternTransform) const
+cairo_pattern_t* Pattern::createPlatformPattern(const TransformationMatrix&) const
{
cairo_surface_t* surface = tileImage()->nativeImageForCurrentFrame();
if (!surface)
return 0;
cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
- const TransformationMatrix& inverse = patternTransform.inverse();
- const cairo_matrix_t* pattern_matrix = reinterpret_cast<const cairo_matrix_t*>(&inverse);
- cairo_pattern_set_matrix(pattern, pattern_matrix);
+
+ // cairo merges patter space and user space itself
+ cairo_matrix_t matrix = m_patternSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(pattern, &matrix);
+
if (m_repeatX || m_repeatY)
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
return pattern;
diff --git a/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp b/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
index b78620f..1b83a29 100644
--- a/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
+++ b/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
@@ -32,248 +32,18 @@
namespace WebCore {
-static const double deg2rad = 0.017453292519943295769; // pi/180
-
-TransformationMatrix::TransformationMatrix()
-{
- cairo_matrix_init_identity(&m_transform);
-}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- cairo_matrix_init(&m_transform, a, b, c, d, tx, ty);
-}
-
-TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix)
-{
- m_transform = matrix;
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- cairo_matrix_init(&m_transform, a, b, c, d, tx, ty);
-}
-
-void TransformationMatrix::map(double x, double y, double* x2, double* y2) const
-{
- *x2 = x;
- *y2 = y;
- cairo_matrix_transform_point(&m_transform, x2, y2);
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect &rect) const
-{
- FloatRect floatRect(rect);
- FloatRect enclosingFloatRect = this->mapRect(floatRect);
-
- return enclosingIntRect(enclosingFloatRect);
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
-{
- double rectMinX = rect.x();
- double rectMaxX = rect.x() + rect.width();
- double rectMinY = rect.y();
- double rectMaxY = rect.y() + rect.height();
-
- double px = rectMinX;
- double py = rectMinY;
- cairo_matrix_transform_point(&m_transform, &px, &py);
-
- double enclosingRectMinX = px;
- double enclosingRectMinY = py;
- double enclosingRectMaxX = px;
- double enclosingRectMaxY = py;
-
- px = rectMaxX;
- py = rectMinY;
- cairo_matrix_transform_point(&m_transform, &px, &py);
- if (px < enclosingRectMinX)
- enclosingRectMinX = px;
- else if (px > enclosingRectMaxX)
- enclosingRectMaxX = px;
- if (py < enclosingRectMinY)
- enclosingRectMinY = py;
- else if (py > enclosingRectMaxY)
- enclosingRectMaxY = py;
-
- px = rectMaxX;
- py = rectMaxY;
- cairo_matrix_transform_point(&m_transform, &px, &py);
- if (px < enclosingRectMinX)
- enclosingRectMinX = px;
- else if (px > enclosingRectMaxX)
- enclosingRectMaxX = px;
- if (py < enclosingRectMinY)
- enclosingRectMinY = py;
- else if (py > enclosingRectMaxY)
- enclosingRectMaxY = py;
-
- px = rectMinX;
- py = rectMaxY;
- cairo_matrix_transform_point(&m_transform, &px, &py);
- if (px < enclosingRectMinX)
- enclosingRectMinX = px;
- else if (px > enclosingRectMaxX)
- enclosingRectMaxX = px;
- if (py < enclosingRectMinY)
- enclosingRectMinY = py;
- else if (py > enclosingRectMaxY)
- enclosingRectMaxY = py;
-
-
- double enclosingRectWidth = enclosingRectMaxX - enclosingRectMinX;
- double enclosingRectHeight = enclosingRectMaxY - enclosingRectMinY;
-
- return FloatRect(enclosingRectMinX, enclosingRectMinY, enclosingRectWidth, enclosingRectHeight);
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return ((m_transform.xx == 1) && (m_transform.yy == 1)
- && (m_transform.xy == 0) && (m_transform.yx == 0)
- && (m_transform.x0 == 0) && (m_transform.y0 == 0));
-}
-
-double TransformationMatrix::a() const
-{
- return m_transform.xx;
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.xx = a;
-}
-
-double TransformationMatrix::b() const
-{
- return m_transform.yx;
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.yx = b;
-}
-
-double TransformationMatrix::c() const
-{
- return m_transform.xy;
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.xy = c;
-}
-
-double TransformationMatrix::d() const
-{
- return m_transform.yy;
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.yy = d;
-}
-
-double TransformationMatrix::e() const
-{
- return m_transform.x0;
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.x0 = e;
-}
-
-double TransformationMatrix::f() const
-{
- return m_transform.y0;
-}
-
-void TransformationMatrix::setF(double f)
-{
- m_transform.y0 = f;
-}
-
-void TransformationMatrix::reset()
-{
- cairo_matrix_init_identity(&m_transform);
-}
-
-TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
-{
- cairo_matrix_scale(&m_transform, sx, sy);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::rotate(double d)
-{
- cairo_matrix_rotate(&m_transform, d * deg2rad);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
-{
- cairo_matrix_translate(&m_transform, tx, ty);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
-{
- cairo_matrix_t shear;
- cairo_matrix_init(&shear, 1, sy, sx, 1, 0, 0);
-
- cairo_matrix_t result;
- cairo_matrix_multiply(&result, &shear, &m_transform);
- m_transform = result;
-
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return m_transform.xx * m_transform.yy - m_transform.xy * m_transform.yx;
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- if (!isInvertible()) return TransformationMatrix();
-
- cairo_matrix_t result = m_transform;
- cairo_matrix_invert(&result);
- return TransformationMatrix(result);
-}
-
TransformationMatrix::operator cairo_matrix_t() const
{
- return m_transform;
-}
+ cairo_matrix_t m;
-bool TransformationMatrix::operator== (const TransformationMatrix &m2) const
-{
- return ((m_transform.xx == m2.m_transform.xx)
- && (m_transform.yy == m2.m_transform.yy)
- && (m_transform.xy == m2.m_transform.xy)
- && (m_transform.yx == m2.m_transform.yx)
- && (m_transform.x0 == m2.m_transform.x0)
- && (m_transform.y0 == m2.m_transform.y0));
-
-}
-
-TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2)
-{
- cairo_matrix_t result;
- cairo_matrix_multiply(&result, &m_transform, &m2.m_transform);
- m_transform = result;
-
- return *this;
-}
-
-TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2)
-{
- cairo_matrix_t result;
- cairo_matrix_multiply(&result, &m_transform, &m2.m_transform);
- return result;
+ cairo_matrix_init (&m,
+ a(),
+ b(),
+ c(),
+ d(),
+ e(),
+ f());
+ return m;
}
}
diff --git a/WebCore/platform/graphics/cg/ColorCG.cpp b/WebCore/platform/graphics/cg/ColorCG.cpp
index 48ce9f2..0465c0b 100644
--- a/WebCore/platform/graphics/cg/ColorCG.cpp
+++ b/WebCore/platform/graphics/cg/ColorCG.cpp
@@ -67,9 +67,9 @@ Color::Color(CGColorRef color)
m_color = makeRGBA(r * 255, g * 255, b * 255, a * 255);
}
-#if !PLATFORM(MAC)
+#if PLATFORM(WIN_OS)
-CGColorRef cgColor(const Color& c)
+CGColorRef createCGColor(const Color& c)
{
CGColorRef color = NULL;
CMProfileRef prof = NULL;
@@ -89,7 +89,7 @@ CGColorRef cgColor(const Color& c)
return color;
}
-#endif // !PLATFORM(MAC)
+#endif // PLATFORM(WIN_OS)
}
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
index 1cc55a4..4b8a555 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -504,6 +504,7 @@ void GraphicsContext::fillPath()
CGContextEOClip(context);
else
CGContextClip(context);
+ CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform());
CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
CGContextRestoreGState(context);
break;
@@ -529,6 +530,7 @@ void GraphicsContext::strokePath()
CGContextSaveGState(context);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
+ CGContextConcatCTM(context, m_common->state.strokeGradient->gradientSpaceTransform());
CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient());
CGContextRestoreGState(context);
break;
@@ -552,6 +554,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
case GradientColorSpace:
CGContextSaveGState(context);
CGContextClipToRect(context, rect);
+ CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform());
CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
CGContextRestoreGState(context);
break;
@@ -734,7 +737,7 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Col
if (!color.isValid())
CGContextSetShadow(context, CGSizeMake(width, height), blurRadius);
else {
- CGColorRef colorCG = cgColor(color);
+ CGColorRef colorCG = createCGColor(color);
CGContextSetShadowWithColor(context,
CGSizeMake(width, height),
blurRadius,
@@ -907,7 +910,8 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform)
TransformationMatrix GraphicsContext::getCTM() const
{
- return CGContextGetCTM(platformContext());
+ CGAffineTransform t = CGContextGetCTM(platformContext());
+ return TransformationMatrix(t.a, t.b, t.c, t.d, t.tx, t.ty);
}
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp
index 13c8c07..dbf1d85 100644
--- a/WebCore/platform/graphics/cg/ImageCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageCG.cpp
@@ -73,6 +73,7 @@ BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
, m_repetitionCountStatus(Unknown)
, m_repetitionsComplete(0)
, m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
, m_animationFinished(true)
, m_allDataReceived(true)
, m_haveSize(true)
@@ -99,6 +100,7 @@ BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
void BitmapImage::checkForSolidColor()
{
+ m_checkedForSolidColor = true;
if (frameCount() > 1)
m_isSolidColor = false;
else {
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
index 0b276cc..c059985 100644
--- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -58,7 +58,7 @@ void ImageSource::clear(bool, size_t, SharedBuffer* data, bool allDataReceived)
m_decoder = 0;
}
if (data)
- setData(data, allDataReceived);
+ setData(data, allDataReceived);
}
static CFDictionaryRef imageSourceOptions()
diff --git a/WebCore/platform/graphics/cg/PatternCG.cpp b/WebCore/platform/graphics/cg/PatternCG.cpp
index 2b9c12f..697bc57 100644
--- a/WebCore/platform/graphics/cg/PatternCG.cpp
+++ b/WebCore/platform/graphics/cg/PatternCG.cpp
@@ -50,12 +50,13 @@ static void patternReleaseCallback(void* info)
static_cast<Image*>(info)->deref();
}
-CGPatternRef Pattern::createPlatformPattern(const TransformationMatrix& transform) const
+CGPatternRef Pattern::createPlatformPattern(const TransformationMatrix& userSpaceTransformation) const
{
IntRect tileRect = tileImage()->rect();
- TransformationMatrix patternTransform = transform;
- patternTransform.scale(1, -1);
+ TransformationMatrix patternTransform = m_patternSpaceTransformation;
+ patternTransform.multiply(userSpaceTransformation);
+ patternTransform.scaleNonUniform(1, -1);
patternTransform.translate(0, -tileRect.height());
// If FLT_MAX should also be used for xStep or yStep, nothing is rendered. Using fractions of FLT_MAX also
diff --git a/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
index 9b3181a..568a6b3 100644
--- a/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
+++ b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
@@ -28,187 +28,19 @@
#if PLATFORM(CG)
+#include <CoreGraphics/CGAffineTransform.h>
#include "FloatConversion.h"
-#include "FloatRect.h"
-#include "IntRect.h"
-
-#include <wtf/MathExtras.h>
namespace WebCore {
-TransformationMatrix::TransformationMatrix()
- : m_transform(CGAffineTransformIdentity)
-{
-}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a),
- narrowPrecisionToCGFloat(b),
- narrowPrecisionToCGFloat(c),
- narrowPrecisionToCGFloat(d),
- narrowPrecisionToCGFloat(tx),
- narrowPrecisionToCGFloat(ty));
-}
-
-TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& t)
- : m_transform(t)
-{
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a),
- narrowPrecisionToCGFloat(b),
- narrowPrecisionToCGFloat(c),
- narrowPrecisionToCGFloat(d),
- narrowPrecisionToCGFloat(tx),
- narrowPrecisionToCGFloat(ty));
-}
-
-void TransformationMatrix::map(double x, double y, double *x2, double *y2) const
-{
- CGPoint result = CGPointApplyAffineTransform(CGPointMake(narrowPrecisionToCGFloat(x), narrowPrecisionToCGFloat(y)), m_transform);
- *x2 = result.x;
- *y2 = result.y;
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect &rect) const
-{
- return enclosingIntRect(CGRectApplyAffineTransform(CGRect(rect), m_transform));
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
-{
- return FloatRect(CGRectApplyAffineTransform(CGRect(rect), m_transform));
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return CGAffineTransformIsIdentity(m_transform);
-}
-
-double TransformationMatrix::a() const
-{
- return m_transform.a;
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.a = narrowPrecisionToCGFloat(a);
-}
-
-double TransformationMatrix::b() const
-{
- return m_transform.b;
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.b = narrowPrecisionToCGFloat(b);
-}
-
-double TransformationMatrix::c() const
-{
- return m_transform.c;
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.c = narrowPrecisionToCGFloat(c);
-}
-
-double TransformationMatrix::d() const
-{
- return m_transform.d;
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.d = narrowPrecisionToCGFloat(d);
-}
-
-double TransformationMatrix::e() const
-{
- return m_transform.tx;
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.tx = narrowPrecisionToCGFloat(e);
-}
-
-double TransformationMatrix::f() const
-{
- return m_transform.ty;
-}
-
-void TransformationMatrix::setF(double f)
-{
- m_transform.ty = narrowPrecisionToCGFloat(f);
-}
-
-void TransformationMatrix::reset()
-{
- m_transform = CGAffineTransformIdentity;
-}
-
-TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
-{
- m_transform = CGAffineTransformScale(m_transform, narrowPrecisionToCGFloat(sx), narrowPrecisionToCGFloat(sy));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::rotate(double d)
-{
- m_transform = CGAffineTransformRotate(m_transform, narrowPrecisionToCGFloat(deg2rad(d)));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
-{
- m_transform = CGAffineTransformTranslate(m_transform, narrowPrecisionToCGFloat(tx), narrowPrecisionToCGFloat(ty));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
-{
- CGAffineTransform shear = CGAffineTransformMake(1.0f, narrowPrecisionToCGFloat(sy), narrowPrecisionToCGFloat(sx), 1.0f, 0.0f, 0.0f);
- m_transform = CGAffineTransformConcat(shear, m_transform);
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return m_transform.a * m_transform.d - m_transform.b * m_transform.c;
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- if (isInvertible())
- return TransformationMatrix(CGAffineTransformInvert(m_transform));
- return TransformationMatrix();
-}
-
-TransformationMatrix::operator PlatformTransformationMatrix() const
-{
- return m_transform;
-}
-
-bool TransformationMatrix::operator== (const TransformationMatrix &m2) const
-{
- return CGAffineTransformEqualToTransform(m_transform, CGAffineTransform(m2));
-}
-
-TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2)
-{
- m_transform = CGAffineTransformConcat(m_transform, CGAffineTransform(m2));
- return *this;
-}
-
-TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2)
+TransformationMatrix::operator CGAffineTransform() const
{
- return CGAffineTransformConcat(m_transform, CGAffineTransform(m2));
+ return CGAffineTransformMake(narrowPrecisionToCGFloat(a()),
+ narrowPrecisionToCGFloat(b()),
+ narrowPrecisionToCGFloat(c()),
+ narrowPrecisionToCGFloat(d()),
+ narrowPrecisionToCGFloat(e()),
+ narrowPrecisionToCGFloat(f()));
}
}
diff --git a/WebCore/platform/graphics/chromium/ColorChromium.cpp b/WebCore/platform/graphics/chromium/ColorChromium.cpp
index 16ca17d..647169c 100644
--- a/WebCore/platform/graphics/chromium/ColorChromium.cpp
+++ b/WebCore/platform/graphics/chromium/ColorChromium.cpp
@@ -28,35 +28,15 @@
namespace WebCore {
+#if !PLATFORM(DARWIN)
+// On OS X, there's code to monitor changes in the focus color system setting.
+// On Windows/Linux there is no equivalent system setting and therefore a static
+// color is all we need.
Color focusRingColor()
{
-// FIXME: This should be split up to ColorChromiumWin and ColorChromiumMac.
-#if PLATFORM(DARWIN)
- // To avoid the Mac Chromium build having to rebasline 500+ layout tests and
- // continue to do this w/ new tests that get landed in WebKit, we want to
- // run the layout tests w/ the same color that stock WebKit uses.
- //
- // TODO: For now we've hard coded the color that WebKit uses for layout
- // tests. We need to revisit this and do either of the following:
- // A. Fully honor the color from the UI, which means collecting the color
- // (and change notifications) in the browser process, and messaging the
- // color to the render process.
- // B. Adding a "layout tests" flag, to control the orage vs. blue colors
- // depending if we're running layout tests.
- // To see the WebKit implementation of using the UI color and/or a flag for
- // layout tests see WebKit/WebCore/platform/graphics/mac/ColorMac.mm.
- // (Reality is we just need an api to override the focus color and both
- // of the above are covered for what this file needs to provide, the
- // two options would be details that happen in other places.)
-
- // From WebKit:
- // static RGBA32 oldAquaFocusRingColorRGBA = 0xFF7DADD9;
- static Color oldAquaFocusRingColor(0x7D, 0xAD, 0xD9, 0xFF);
- return oldAquaFocusRingColor;
-#else
static Color focusRingColor(229, 151, 0, 255);
return focusRingColor;
-#endif
}
+#endif
} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/ColorChromiumMac.mm b/WebCore/platform/graphics/chromium/ColorChromiumMac.mm
new file mode 100644
index 0000000..01dff7e
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/ColorChromiumMac.mm
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#import <AppKit/NSColor.h>
+#import <wtf/Assertions.h>
+#import <wtf/StdLibExtras.h>
+#import <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+Color focusRingColor()
+{
+ // To avoid the Mac Chromium build having to rebasline 500+ layout tests and
+ // continue to do this w/ new tests that get landed in WebKit, we want to
+ // run the layout tests w/ the same color that stock WebKit uses.
+ //
+ // FIXME: For now we've hard coded the color that WebKit uses for layout
+ // tests. We need to revisit this and do either of the following:
+ // A. Fully honor the color from the UI, which means collecting the color
+ // (and change notifications) in the browser process, and messaging the
+ // color to the render process.
+ // B. Adding a "layout tests" flag, to control the orage vs. blue colors
+ // depending if we're running layout tests.
+ // To see the WebKit implementation of using the UI color and/or a flag for
+ // layout tests see WebKit/WebCore/platform/graphics/mac/ColorMac.mm.
+ // (Reality is we just need an api to override the focus color and both
+ // of the above are covered for what this file needs to provide, the
+ // two options would be details that happen in other places.)
+
+ // From WebKit:
+ // static RGBA32 oldAquaFocusRingColorRGBA = 0xFF7DADD9;
+ static Color oldAquaFocusRingColor(0x7D, 0xAD, 0xD9, 0xFF);
+ return oldAquaFocusRingColor;
+}
+
+// createCGColor() and the functions it calls are verbatum copies of
+// graphics/mac/ColorMac.mm. These are copied here so that we don't need to
+// include ColorMac.mm in the Chromium build.
+// FIXME: Check feasibility of using pure CG calls and unifying this copy with
+// ColorMac.mm's under graphics/cg.
+
+NSColor* nsColor(const Color& color)
+{
+ unsigned c = color.rgb();
+ switch (c) {
+ case 0: {
+ // Need this to avoid returning nil because cachedRGBAValues will default to 0.
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:0.0f]));
+ return clearColor.get();
+ }
+ case Color::black: {
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:1.0f]));
+ return blackColor.get();
+ }
+ case Color::white: {
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:1.0f]));
+ return whiteColor.get();
+ }
+ default: {
+ const int cacheSize = 32;
+ static unsigned cachedRGBAValues[cacheSize];
+ static RetainPtr<NSColor>* cachedColors = new RetainPtr<NSColor>[cacheSize];
+
+ for (int i = 0; i != cacheSize; ++i)
+ if (cachedRGBAValues[i] == c)
+ return cachedColors[i].get();
+
+ NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f
+ green:color.green() / 255.0f
+ blue:color.blue() / 255.0f
+ alpha:color.alpha() /255.0f];
+
+ static int cursor;
+ cachedRGBAValues[cursor] = c;
+ cachedColors[cursor] = result;
+ if (++cursor == cacheSize)
+ cursor = 0;
+ return result;
+ }
+ }
+}
+
+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.
+ NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+ CGFloat red = [deviceColor redComponent];
+ CGFloat green = [deviceColor greenComponent];
+ CGFloat blue = [deviceColor blueComponent];
+ CGFloat alpha = [deviceColor alphaComponent];
+ const CGFloat components[4] = { red, green, blue, alpha };
+ 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/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
index 03583a0..129776e 100644
--- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
@@ -394,53 +394,18 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, cons
family = panUniFonts[i];
data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)));
}
- if (i < numFonts) // we found the font that covers this character !
+ // When i-th font (0-base) in |panUniFonts| contains a character and
+ // we get out of the loop, |i| will be |i + 1|. That is, if only the
+ // last font in the array covers the character, |i| will be numFonts.
+ // So, we have to use '<=" rather than '<' to see if we found a font
+ // covering the character.
+ if (i <= numFonts)
return getCachedFontData(data);
return 0;
}
-const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName)
-{
- // Note that mapping to Courier is removed because
- // because it's a bitmap font on Windows.
- // Alias Courier -> Courier New
- static AtomicString courier("Courier"), courierNew("Courier New");
- if (equalIgnoringCase(familyName, courier))
- return courierNew;
-
- // Alias Times <-> Times New Roman.
- static AtomicString times("Times"), timesNewRoman("Times New Roman");
- if (equalIgnoringCase(familyName, times))
- return timesNewRoman;
- if (equalIgnoringCase(familyName, timesNewRoman))
- return times;
-
- // Alias Helvetica <-> Arial
- static AtomicString arial("Arial"), helvetica("Helvetica");
- if (equalIgnoringCase(familyName, helvetica))
- return arial;
- if (equalIgnoringCase(familyName, arial))
- return helvetica;
-
- // We block bitmap fonts altogether so that we have to
- // alias MS Sans Serif (bitmap font) -> Microsoft Sans Serif (truetype font)
- static AtomicString msSans("MS Sans Serif");
- static AtomicString microsoftSans("Microsoft Sans Serif");
- if (equalIgnoringCase(familyName, msSans))
- return microsoftSans;
-
- // Alias MS Serif (bitmap) -> Times New Roman (truetype font). There's no
- // 'Microsoft Sans Serif-equivalent' for Serif.
- static AtomicString msSerif("MS Serif");
- if (equalIgnoringCase(familyName, msSerif))
- return timesNewRoman;
-
- // FIXME: should we map 'system' to something ('Tahoma') ?
- return emptyAtom;
-}
-
FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
{
return 0;
diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
index f187c55..89433e1 100644
--- a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
@@ -91,16 +91,6 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font,
return ret;
}
-const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName)
-{
- notImplemented();
-
- // This is just to stop GCC emitting a warning about returning a reference
- // to a temporary variable
- static AtomicString a;
- return a;
-}
-
FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
{
return 0;
diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
index 3cf18a6..1b71946 100644
--- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
@@ -32,7 +32,6 @@
#include "config.h"
#include "Font.h"
-#include "TransformationMatrix.h"
#include "ChromiumBridge.h"
#include "FontFallbackList.h"
#include "GlyphBuffer.h"
@@ -40,6 +39,7 @@
#include "SimpleFontData.h"
#include "SkiaFontWin.h"
#include "SkiaUtils.h"
+#include "TransparencyWin.h"
#include "UniscribeHelperTextRun.h"
#include "skia/ext/platform_canvas_win.h"
@@ -49,122 +49,274 @@
namespace WebCore {
-static bool windowsCanHandleTextDrawing(GraphicsContext* context)
+namespace {
+
+bool canvasHasMultipleLayers(const SkCanvas* canvas)
+{
+ SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false);
+ iter.next(); // There is always at least one layer.
+ return !iter.done(); // There is > 1 layer if the the iterator can stil advance.
+}
+
+class TransparencyAwareFontPainter {
+public:
+ TransparencyAwareFontPainter(GraphicsContext*, const FloatPoint&);
+ ~TransparencyAwareFontPainter();
+
+protected:
+ // Called by our subclass' constructor to initialize GDI if necessary. This
+ // is a separate function so it can be called after the subclass finishes
+ // construction (it calls virtual functions).
+ void init();
+
+ virtual IntRect estimateTextBounds() = 0;
+
+ // Use the context from the transparency helper when drawing with GDI. It
+ // may point to a temporary one.
+ GraphicsContext* m_graphicsContext;
+ PlatformGraphicsContext* m_platformContext;
+
+ FloatPoint m_point;
+
+ // Set when Windows can handle the type of drawing we're doing.
+ bool m_useGDI;
+
+ // These members are valid only when m_useGDI is set.
+ HDC m_hdc;
+ TransparencyWin m_transparency;
+
+private:
+ // Call when we're using GDI mode to initialize the TransparencyWin to help
+ // us draw GDI text.
+ void initializeForGDI();
+
+ bool m_createdTransparencyLayer; // We created a layer to give the font some alpha.
+};
+
+TransparencyAwareFontPainter::TransparencyAwareFontPainter(GraphicsContext* context,
+ const FloatPoint& point)
+ : m_graphicsContext(context)
+ , m_platformContext(context->platformContext())
+ , m_point(point)
+ , m_useGDI(windowsCanHandleTextDrawing(context))
+ , m_hdc(0)
+ , m_createdTransparencyLayer(false)
+{
+}
+
+void TransparencyAwareFontPainter::init()
{
- // Check for non-translation transforms. Sometimes zooms will look better in
- // Skia, and sometimes better in Windows. The main problem is that zooming
- // in using Skia will show you the hinted outlines for the smaller size,
- // which look weird. All else being equal, it's better to use Windows' text
- // drawing, so we don't check for zooms.
- const TransformationMatrix& matrix = context->getCTM();
- if (matrix.b() != 0 || matrix.c() != 0) // Check for skew.
- return false;
-
- // Check for stroke effects.
- if (context->platformContext()->getTextDrawingMode() != cTextFill)
- return false;
-
- // Check for shadow effects.
- if (context->platformContext()->getDrawLooper())
- return false;
-
- return true;
+ if (m_useGDI)
+ initializeForGDI();
}
-// Skia equivalents to Windows text drawing functions. They
-// will get the outlines from Windows and draw then using Skia using the given
-// parameters in the paint arguments. This allows more complex effects and
-// transforms to be drawn than Windows allows.
-//
-// These functions will be significantly slower than Windows GDI, and the text
-// will look different (no ClearType), so use only when necessary.
-//
-// When you call a Skia* text drawing function, various glyph outlines will be
-// cached. As a result, you should call SkiaWinOutlineCache::removePathsForFont
-// when the font is destroyed so that the cache does not outlive the font (since
-// the HFONTs are recycled).
-
-// Analog of the Windows GDI function DrawText, except using the given SkPaint
-// attributes for the text. See above for more.
-//
-// Returns true of the text was drawn successfully. False indicates an error
-// from Windows.
-static bool skiaDrawText(HFONT hfont,
- SkCanvas* canvas,
- const SkPoint& point,
- SkPaint* paint,
- const WORD* glyphs,
- const int* advances,
- int numGlyphs)
+void TransparencyAwareFontPainter::initializeForGDI()
{
- HDC dc = GetDC(0);
- HGDIOBJ oldFont = SelectObject(dc, hfont);
-
- canvas->save();
- canvas->translate(point.fX, point.fY);
-
- for (int i = 0; i < numGlyphs; i++) {
- const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]);
- if (!path)
- return false;
- canvas->drawPath(*path, *paint);
- canvas->translate(advances[i], 0);
+ SkColor color = m_platformContext->effectiveFillColor();
+ if (SkColorGetA(color) != 0xFF) {
+ // When the font has some transparency, apply it by creating a new
+ // transparency layer with that opacity applied.
+ m_createdTransparencyLayer = true;
+ m_graphicsContext->beginTransparencyLayer(SkColorGetA(color) / 255.0f);
+ // The color should be opaque now.
+ color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
}
- canvas->restore();
+ TransparencyWin::LayerMode layerMode;
+ IntRect layerRect;
+ if (m_platformContext->isDrawingToImageBuffer()) {
+ // Assume if we're drawing to an image buffer that the background
+ // is not opaque and we have to undo ClearType. We may want to
+ // enhance this to actually check, since it will often be opaque
+ // and we could do ClearType in that case.
+ layerMode = TransparencyWin::TextComposite;
+ layerRect = estimateTextBounds();
+
+ // The transparency helper requires that we draw text in black in
+ // this mode and it will apply the color.
+ m_transparency.setTextCompositeColor(color);
+ color = SkColorSetRGB(0, 0, 0);
+ } else if (canvasHasMultipleLayers(m_platformContext->canvas())) {
+ // When we're drawing a web page, we know the background is opaque,
+ // but if we're drawing to a layer, we still need extra work.
+ layerMode = TransparencyWin::OpaqueCompositeLayer;
+ layerRect = estimateTextBounds();
+ } else {
+ // Common case of drawing onto the bottom layer of a web page: we
+ // know everything is opaque so don't need to do anything special.
+ layerMode = TransparencyWin::NoLayer;
+ }
+ m_transparency.init(m_graphicsContext, layerMode, TransparencyWin::KeepTransform, layerRect);
- SelectObject(dc, oldFont);
- ReleaseDC(0, dc);
- return true;
+ // Set up the DC, using the one from the transparency helper.
+ m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint();
+ SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
+ SetBkMode(m_hdc, TRANSPARENT);
}
-static bool paintSkiaText(PlatformContextSkia* platformContext,
- HFONT hfont,
- int numGlyphs,
- const WORD* glyphs,
- const int* advances,
- const SkPoint& origin)
+TransparencyAwareFontPainter::~TransparencyAwareFontPainter()
{
- int textMode = platformContext->getTextDrawingMode();
-
- // Filling (if necessary). This is the common case.
- SkPaint paint;
- platformContext->setupPaintForFilling(&paint);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
- bool didFill = false;
- if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) {
- if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs))
- return false;
- didFill = true;
- }
+ if (!m_useGDI)
+ return; // Nothing to do.
+ m_transparency.composite();
+ if (m_createdTransparencyLayer)
+ m_graphicsContext->endTransparencyLayer();
+ m_platformContext->canvas()->endPlatformPaint();
+}
- // Stroking on top (if necessary).
- if ((textMode & WebCore::cTextStroke)
- && platformContext->getStrokeStyle() != NoStroke
- && platformContext->getStrokeThickness() > 0) {
-
- paint.reset();
- platformContext->setupPaintForStroking(&paint, 0, 0);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
- if (didFill) {
- // If there is a shadow and we filled above, there will already be
- // a shadow. We don't want to draw it again or it will be too dark
- // and it will go on top of the fill.
- //
- // Note that this isn't strictly correct, since the stroke could be
- // very thick and the shadow wouldn't account for this. The "right"
- // thing would be to draw to a new layer and then draw that layer
- // with a shadow. But this is a lot of extra work for something
- // that isn't normally an issue.
- paint.setLooper(0)->safeUnref();
- }
+// Specialization for simple GlyphBuffer painting.
+class TransparencyAwareGlyphPainter : public TransparencyAwareFontPainter {
+ public:
+ TransparencyAwareGlyphPainter(GraphicsContext*,
+ const SimpleFontData*,
+ const GlyphBuffer&,
+ int from, int numGlyphs,
+ const FloatPoint&);
+ ~TransparencyAwareGlyphPainter();
+
+ // Draws the partial string of glyphs, starting at |startAdvance| to the
+ // left of m_point. We express it this way so that if we're using the Skia
+ // drawing path we can use floating-point positioning, even though we have
+ // to use integer positioning in the GDI path.
+ bool drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances, int startAdvance) const;
+
+ private:
+ virtual IntRect estimateTextBounds();
+
+ const SimpleFontData* m_font;
+ const GlyphBuffer& m_glyphBuffer;
+ int m_from;
+ int m_numGlyphs;
+
+ // When m_useGdi is set, this stores the previous HFONT selected into the
+ // m_hdc so we can restore it.
+ HGDIOBJ m_oldFont; // For restoring the DC to its original state.
+};
+
+TransparencyAwareGlyphPainter::TransparencyAwareGlyphPainter(
+ GraphicsContext* context,
+ const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs,
+ const FloatPoint& point)
+ : TransparencyAwareFontPainter(context, point)
+ , m_font(font)
+ , m_glyphBuffer(glyphBuffer)
+ , m_from(from)
+ , m_numGlyphs(numGlyphs)
+ , m_oldFont(0)
+{
+ init();
+
+ m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
+}
- if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs))
- return false;
+TransparencyAwareGlyphPainter::~TransparencyAwareGlyphPainter()
+{
+ if (m_useGDI)
+ ::SelectObject(m_hdc, m_oldFont);
+}
+
+
+// Estimates the bounding box of the given text. This is copied from
+// FontCGWin.cpp, it is possible, but a lot more work, to get the precide
+// bounds.
+IntRect TransparencyAwareGlyphPainter::estimateTextBounds()
+{
+ int totalWidth = 0;
+ for (int i = 0; i < m_numGlyphs; i++)
+ totalWidth += lroundf(m_glyphBuffer.advanceAt(m_from + i));
+
+ return IntRect(m_point.x() - (m_font->ascent() + m_font->descent()) / 2,
+ m_point.y() - m_font->ascent() - m_font->lineGap(),
+ totalWidth + m_font->ascent() + m_font->descent(),
+ m_font->lineSpacing());
+}
+
+bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ int startAdvance) const
+{
+ if (!m_useGDI) {
+ SkPoint origin = m_point;
+ origin.fX += startAdvance;
+ return paintSkiaText(m_graphicsContext, m_font->platformData().hfont(),
+ numGlyphs, glyphs, advances, 0, &origin);
}
- return true;
+
+ // Windows' origin is the top-left of the bounding box, so we have
+ // to subtract off the font ascent to get it.
+ int x = lroundf(m_point.x() + startAdvance);
+ int y = lroundf(m_point.y() - m_font->ascent());
+ return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
+}
+
+
+class TransparencyAwareUniscribePainter : public TransparencyAwareFontPainter {
+ public:
+ TransparencyAwareUniscribePainter(GraphicsContext*,
+ const Font*,
+ const TextRun&,
+ int from, int to,
+ const FloatPoint&);
+ ~TransparencyAwareUniscribePainter();
+
+ // Uniscibe will draw directly into our buffer, so we need to expose our DC.
+ HDC hdc() const { return m_hdc; }
+
+ private:
+ virtual IntRect estimateTextBounds();
+
+ const Font* m_font;
+ const TextRun& m_run;
+ int m_from;
+ int m_to;
+};
+
+TransparencyAwareUniscribePainter::TransparencyAwareUniscribePainter(
+ GraphicsContext* context,
+ const Font* font,
+ const TextRun& run,
+ int from, int to,
+ const FloatPoint& point)
+ : TransparencyAwareFontPainter(context, point)
+ , m_font(font)
+ , m_run(run)
+ , m_from(from)
+ , m_to(to)
+{
+ init();
}
+TransparencyAwareUniscribePainter::~TransparencyAwareUniscribePainter()
+{
+}
+
+IntRect TransparencyAwareUniscribePainter::estimateTextBounds()
+{
+ // This case really really sucks. There is no convenient way to estimate
+ // the bounding box. So we run Uniscribe twice. If we find this happens a
+ // lot, the way to fix it is to make the extra layer after the
+ // UniscribeHelper has measured the text.
+ IntPoint intPoint(lroundf(m_point.x()),
+ lroundf(m_point.y()));
+
+ UniscribeHelperTextRun state(m_run, *m_font);
+ int left = lroundf(m_point.x()) + state.characterToX(m_from);
+ int right = lroundf(m_point.x()) + state.characterToX(m_to);
+
+ // This algorithm for estimating how much extra space we need (the text may
+ // go outside the selection rect) is based roughly on
+ // TransparencyAwareGlyphPainter::estimateTextBounds above.
+ return IntRect(left - (m_font->ascent() + m_font->descent()) / 2,
+ m_point.y() - m_font->ascent() - m_font->lineGap(),
+ (right - left) + m_font->ascent() + m_font->descent(),
+ m_font->lineSpacing());
+}
+
+} // namespace
+
void Font::drawGlyphs(GraphicsContext* graphicsContext,
const SimpleFontData* font,
const GlyphBuffer& glyphBuffer,
@@ -172,51 +324,27 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
int numGlyphs,
const FloatPoint& point) const
{
- PlatformGraphicsContext* context = graphicsContext->platformContext();
-
- // Max buffer length passed to the underlying windows API.
- const int kMaxBufferLength = 1024;
- // Default size for the buffer. It should be enough for most of cases.
- const int kDefaultBufferLength = 256;
-
- SkColor color = context->fillColor();
+ SkColor color = graphicsContext->platformContext()->effectiveFillColor();
unsigned char alpha = SkColorGetA(color);
// Skip 100% transparent text; no need to draw anything.
- if (!alpha && context->getStrokeStyle() == NoStroke)
+ if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
return;
- // Set up our graphics context.
- HDC hdc = context->canvas()->beginPlatformPaint();
- HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont());
-
- // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
- // Enforce non-transparent color.
- color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
- SetTextColor(hdc, skia::SkColorToCOLORREF(color));
- SetBkMode(hdc, TRANSPARENT);
-
- // Windows needs the characters and the advances in nice contiguous
- // buffers, which we build here.
- Vector<WORD, kDefaultBufferLength> glyphs;
- Vector<int, kDefaultBufferLength> advances;
-
- // Compute the coordinate. The 'origin' represents the baseline, so we need
- // to move it up to the top of the bounding square.
- int x = static_cast<int>(point.x());
- int lineTop = static_cast<int>(point.y()) - font->ascent();
-
- bool canUseGDI = windowsCanHandleTextDrawing(graphicsContext);
+ TransparencyAwareGlyphPainter painter(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
// We draw the glyphs in chunks to avoid having to do a heap allocation for
// the arrays of characters and advances. Since ExtTextOut is the
// lowest-level text output function on Windows, there should be little
// penalty for splitting up the text. On the other hand, the buffer cannot
// be bigger than 4094 or the function will fail.
- int glyphIndex = 0;
+ const int kMaxBufferLength = 256;
+ Vector<WORD, kMaxBufferLength> glyphs;
+ Vector<int, kMaxBufferLength> advances;
+ int glyphIndex = 0; // The starting glyph of the current chunk.
+ int curAdvance = 0; // How far from the left the current chunk is.
while (glyphIndex < numGlyphs) {
- // how many chars will be in this chunk?
+ // How many chars will be in this chunk?
int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
-
glyphs.resize(curLen);
advances.resize(curLen);
@@ -227,17 +355,10 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
curWidth += advances[i];
}
+ // Actually draw the glyphs (with retry on failure).
bool success = false;
for (int executions = 0; executions < 2; ++executions) {
- if (canUseGDI)
- success = !!ExtTextOut(hdc, x, lineTop, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), curLen, &advances[0]);
- else {
- // Skia's text draing origin is the baseline, like WebKit, not
- // the top, like Windows.
- SkPoint origin = { x, point.y() };
- success = paintSkiaText(context, font->platformData().hfont(), numGlyphs, reinterpret_cast<const WORD*>(&glyphs[0]), &advances[0], origin);
- }
-
+ success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], curAdvance);
if (!success && executions == 0) {
// Ask the browser to load the font for us and retry.
ChromiumBridge::ensureFontLoaded(font->platformData().hfont());
@@ -247,12 +368,8 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
}
ASSERT(success);
-
- x += curWidth;
+ curAdvance += curWidth;
}
-
- SelectObject(hdc, oldFont);
- context->canvas()->endPlatformPaint();
}
FloatRect Font::selectionRectForComplexText(const TextRun& run,
@@ -283,13 +400,15 @@ void Font::drawComplexText(GraphicsContext* graphicsContext,
PlatformGraphicsContext* context = graphicsContext->platformContext();
UniscribeHelperTextRun state(run, *this);
- SkColor color = context->fillColor();
+ SkColor color = graphicsContext->platformContext()->effectiveFillColor();
unsigned char alpha = SkColorGetA(color);
// Skip 100% transparent text; no need to draw anything.
- if (!alpha)
+ if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
return;
- HDC hdc = context->canvas()->beginPlatformPaint();
+ TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point);
+
+ HDC hdc = painter.hdc();
// TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
// Enforce non-transparent color.
@@ -299,7 +418,9 @@ void Font::drawComplexText(GraphicsContext* graphicsContext,
// Uniscribe counts the coordinates from the upper left, while WebKit uses
// the baseline, so we have to subtract off the ascent.
- state.draw(hdc, static_cast<int>(point.x()), static_cast<int>(point.y() - ascent()), from, to);
+ state.draw(graphicsContext, hdc, static_cast<int>(point.x()),
+ static_cast<int>(point.y() - ascent()), from, to);
+
context->canvas()->endPlatformPaint();
}
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
index 8f8df88..1e923ac 100644
--- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
@@ -116,7 +116,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
// Streams the concatenation of a header and font data.
class EOTStream {
public:
- EOTStream(const Vector<UInt8, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
+ EOTStream(const Vector<uint8_t, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
: m_eotHeader(eotHeader)
, m_fontData(fontData)
, m_overlayDst(overlayDst)
@@ -130,7 +130,7 @@ public:
size_t read(void* buffer, size_t count);
private:
- const Vector<UInt8, 512>& m_eotHeader;
+ const Vector<uint8_t, 512>& m_eotHeader;
const SharedBuffer* m_fontData;
size_t m_overlayDst;
size_t m_overlaySrc;
@@ -200,7 +200,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
// TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data,
// so we need to create an EOT header and prepend it to the font data.
- Vector<UInt8, 512> eotHeader;
+ Vector<uint8_t, 512> eotHeader;
size_t overlayDst;
size_t overlaySrc;
size_t overlayLength;
diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp
index 7a3e614..2b7c562 100644
--- a/WebCore/platform/graphics/chromium/FontLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -49,14 +49,6 @@ namespace WebCore {
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
const FloatPoint& point) const {
- SkCanvas* canvas = gc->platformContext()->canvas();
- SkPaint paint;
-
- gc->platformContext()->setupPaintCommon(&paint);
- font->platformData().setupPaint(&paint);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setColor(gc->fillColor().rgb());
-
SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
@@ -78,7 +70,39 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
x += SkFloatToScalar(adv[i].width());
y += SkFloatToScalar(adv[i].height());
}
- canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+
+ SkCanvas* canvas = gc->platformContext()->canvas();
+ int textMode = gc->platformContext()->getTextDrawingMode();
+
+ // We draw text up to two times (once for fill, once for stroke).
+ if (textMode & cTextFill) {
+ SkPaint paint;
+ gc->platformContext()->setupPaintForFilling(&paint);
+ font->platformData().setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setColor(gc->fillColor().rgb());
+ canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+ }
+
+ if ((textMode & cTextStroke)
+ && gc->platformContext()->getStrokeStyle() != NoStroke
+ && gc->platformContext()->getStrokeThickness() > 0) {
+
+ SkPaint paint;
+ gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
+ font->platformData().setupPaint(&paint);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setColor(gc->strokeColor().rgb());
+
+ if (textMode & cTextFill) {
+ // If we also filled, we don't want to draw shadows twice.
+ // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
+ paint.setLooper(0)->safeUnref();
+ }
+
+ canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+ }
}
void Font::drawComplexText(GraphicsContext* context, const TextRun& run,
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
index 86f96ee..7b7d197 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
@@ -86,7 +86,7 @@ void FontPlatformData::setupPaint(SkPaint* paint) const
{
const float ts = m_textSize > 0 ? m_textSize : 12;
- paint->setAntiAlias(false);
+ paint->setAntiAlias(true);
paint->setSubpixelText(false);
paint->setTextSize(SkFloatToScalar(ts));
paint->setTypeface(m_typeface);
diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
index 4c5cf7b..31c5256 100644
--- a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
@@ -147,27 +147,17 @@ static bool fillBMPGlyphs(unsigned offset,
// When this character should be a space, we ignore whatever the font
// says and use a space. Otherwise, if fonts don't map one of these
// space or zero width glyphs, we will get a box.
- if (Font::treatAsSpace(c))
+ if (Font::treatAsSpace(c)) {
// Hard code the glyph indices for characters that should be
// treated like spaces.
glyph = initSpaceGlyph(dc, &spaceGlyph);
- else if (Font::treatAsZeroWidthSpace(c) || c == 0x200B) {
- // FIXME: change Font::treatAsZeroWidthSpace to use
- // u_hasBinaryProperty, per jungshik's comment here:
- // https://bugs.webkit.org/show_bug.cgi?id=20237#c6.
- // Then the additional OR above won't be necessary.
- glyph = initSpaceGlyph(dc, &spaceGlyph);
- glyphFontData = fontData->zeroWidthFontData();
} else if (glyph == invalidGlyph) {
// WebKit expects both the glyph index and FontData
// pointer to be 0 if the glyph is not present
glyph = 0;
glyphFontData = 0;
- } else {
- if (SimpleFontData::isCJKCodePoint(c))
- glyphFontData = fontData->cjkWidthFontData();
+ } else
haveGlyphs = true;
- }
page->setGlyphDataForCharacter(offset + i, glyph, glyphFontData);
}
@@ -205,6 +195,7 @@ static bool fillNonBMPGlyphs(unsigned offset,
fontData->m_font.scriptCache(),
fontData->m_font.scriptFontProperties());
state.setInhibitLigate(true);
+ state.setDisableFontFallback(true);
state.init();
for (unsigned i = 0; i < length; i++) {
diff --git a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
index 959147a..e8ba0ad 100644
--- a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
+++ b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
@@ -33,13 +33,13 @@
#if ENABLE(VIDEO)
-#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
namespace WebCore {
-class MediaPlayerPrivate : public Noncopyable {
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
public:
- MediaPlayerPrivate(MediaPlayer*);
+ static void registerMediaEngine(MediaEngineRegistrar);
~MediaPlayerPrivate();
IntSize naturalSize() const;
@@ -74,13 +74,10 @@ public:
unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect&);
+ void setSize(const IntSize&);
void paint(GraphicsContext*, const IntRect&);
- static void getSupportedTypes(HashSet<String>&);
- static bool isAvailable();
-
// Public methods to be called by WebMediaPlayer
FrameView* frameView();
void networkStateChanged();
@@ -90,6 +87,12 @@ public:
void repaint();
private:
+ MediaPlayerPrivate(MediaPlayer*);
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
MediaPlayer* m_player;
void* m_data;
};
diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp
deleted file mode 100644
index 798ee32..0000000
--- a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 "ThemeHelperChromiumWin.h"
-
-#include "FloatRect.h"
-#include "GraphicsContext.h"
-
-namespace WebCore {
-
-ThemeHelperWin::ThemeHelperWin(GraphicsContext* context, const IntRect& rect)
- : m_orgContext(context)
- , m_orgMatrix(context->getCTM())
- , m_orgRect(rect)
-{
- if (m_orgMatrix.b() != 0 || m_orgMatrix.c() != 0) { // Check for skew.
- // Complicated effects, make a copy and draw the bitmap there.
- m_type = COPY;
- m_rect.setSize(rect.size());
-
- m_newBuffer.set(ImageBuffer::create(rect.size(), false).release());
-
- // Theme drawing messes with the transparency.
- // FIXME: Ideally, we would leave this transparent, but I was
- // having problems with button drawing, so we fill with white. Buttons
- // looked good with transparent here and no fixing up of the alpha
- // later, but text areas didn't. This makes text areas look good but
- // gives buttons a white halo. Is there a way to fix this? I think
- // buttons actually have antialised edges which is just not possible
- // to handle on a transparent background given that it messes with the
- // alpha channel.
- FloatRect newContextRect(0, 0, rect.width(), rect.height());
- GraphicsContext* newContext = m_newBuffer->context();
- newContext->setFillColor(Color::white);
- newContext->fillRect(newContextRect);
-
- return;
- }
-
- if (m_orgMatrix.a() != 1.0 || m_orgMatrix.d() != 1.0) { // Check for scale.
- // Only a scaling is applied.
- m_type = SCALE;
-
- // Save the transformed coordinates to draw.
- m_rect = m_orgMatrix.mapRect(rect);
-
- m_orgContext->save();
- m_orgContext->concatCTM(m_orgContext->getCTM().inverse());
- return;
- }
-
- // Nothing interesting.
- m_rect = rect;
- m_type = ORIGINAL;
-}
-
-ThemeHelperWin::~ThemeHelperWin()
-{
- switch (m_type) {
- case SCALE:
- m_orgContext->restore();
- break;
- case COPY: {
- // Copy the duplicate bitmap with our control to the original canvas.
- FloatRect destRect(m_orgRect);
- m_newBuffer->context()->platformContext()->canvas()->
- getTopPlatformDevice().fixupAlphaBeforeCompositing();
- m_orgContext->drawImage(m_newBuffer->image(), destRect);
- break;
- }
- case ORIGINAL:
- break;
- }
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h
deleted file mode 100644
index 1771fb4..0000000
--- a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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 ThemeHelperWin_h
-#define ThemeHelperWin_h
-
-#include "TransformationMatrix.h"
-#include "ImageBuffer.h"
-#include "IntRect.h"
-#include <wtf/OwnPtr.h>
-
-namespace WebCore {
-
-class GraphicsContext;
-class IntRect;
-
-// Helps drawing theme elements like buttons and scroll bars. This will handle
-// translations and scalings that Windows might not, by either making Windows
-// draw the appropriate sized control, or by rendering it into an off-screen
-// context and transforming it ourselves.
-class ThemeHelperWin {
- enum Type {
- // Use the original canvas with no changes. This is the normal mode.
- ORIGINAL,
-
- // Use the original canvas but scale the rectangle of the control so
- // that it will be the correct size, undoing any scale already on the
- // canvas. This will have the effect of just drawing the control bigger
- // or smaller and not actually expanding or contracting the pixels in
- // it. This usually looks better.
- SCALE,
-
- // Make a copy of the control and then transform it ourselves after
- // Windows draws it. This allows us to get complex effects.
- COPY,
- };
-
-public:
- // Prepares drawing a control with the given rect to the given context.
- ThemeHelperWin(GraphicsContext* context, const IntRect& rect);
- ~ThemeHelperWin();
-
- // Returns the context to draw the control into, which may be the original
- // or the copy, depending on the mode.
- GraphicsContext* context()
- {
- return m_newBuffer.get() ? m_newBuffer->context() : m_orgContext;
- }
-
- // Returns the rectangle in which to draw into the canvas() by Windows.
- const IntRect& rect() { return m_rect; }
-
-private:
- Type m_type;
-
- // The original canvas to wrote to. Not owned by this class.
- GraphicsContext* m_orgContext;
- TransformationMatrix m_orgMatrix;
- IntRect m_orgRect;
-
- // When m_type == COPY, this will be a new surface owned by this class that
- // represents the copy.
- OwnPtr<ImageBuffer> m_newBuffer;
-
- // The control rectangle in the coordinate space of canvas().
- IntRect m_rect;
-};
-
-} // namespace WebCore
-
-#endif // ThemeHelperWin_h
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
new file mode 100644
index 0000000..8c790af
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <windows.h>
+
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "PlatformContextSkia.h"
+#include "SimpleFontData.h"
+#include "TransformationMatrix.h"
+#include "TransparencyWin.h"
+
+#include "SkColorPriv.h"
+#include "skia/ext/platform_canvas.h"
+
+namespace WebCore {
+
+namespace {
+
+// The maximum size in pixels of the buffer we'll keep around for drawing text
+// into. Buffers larger than this will be destroyed when we're done with them.
+const int maxCachedBufferPixelSize = 65536;
+
+inline skia::PlatformCanvas* canvasForContext(const GraphicsContext& context)
+{
+ return context.platformContext()->canvas();
+}
+
+inline const SkBitmap& bitmapForContext(const GraphicsContext& context)
+{
+ return canvasForContext(context)->getTopPlatformDevice().accessBitmap(false);
+}
+
+void compositeToCopy(const GraphicsContext& sourceLayers,
+ GraphicsContext& destContext,
+ const TransformationMatrix& matrix)
+{
+ // Make a list of all devices. The iterator goes top-down, and we want
+ // bottom-up. Note that each layer can also have an offset in canvas
+ // coordinates, which is the (x, y) position.
+ struct DeviceInfo {
+ DeviceInfo(SkDevice* d, int lx, int ly)
+ : device(d)
+ , x(lx)
+ , y(ly) {}
+ SkDevice* device;
+ int x;
+ int y;
+ };
+ Vector<DeviceInfo> devices;
+ SkCanvas* sourceCanvas = canvasForContext(sourceLayers);
+ SkCanvas::LayerIter iter(sourceCanvas, false);
+ while (!iter.done()) {
+ devices.append(DeviceInfo(iter.device(), iter.x(), iter.y()));
+ iter.next();
+ }
+
+ // Create a temporary canvas for the compositing into the destination.
+ SkBitmap* destBmp = const_cast<SkBitmap*>(&bitmapForContext(destContext));
+ SkCanvas destCanvas(*destBmp);
+ destCanvas.setMatrix(matrix);
+
+ for (int i = devices.size() - 1; i >= 0; i--) {
+ const SkBitmap& srcBmp = devices[i].device->accessBitmap(false);
+
+ SkRect destRect;
+ destRect.fLeft = devices[i].x;
+ destRect.fTop = devices[i].y;
+ destRect.fRight = destRect.fLeft + srcBmp.width();
+ destRect.fBottom = destRect.fTop + srcBmp.height();
+
+ destCanvas.drawBitmapRect(srcBmp, 0, destRect);
+ }
+}
+
+} // namespace
+
+// If either of these pointers is non-null, both must be valid and point to
+// bitmaps of the same size.
+class TransparencyWin::OwnedBuffers {
+public:
+ OwnedBuffers(const IntSize& size, bool needReferenceBuffer)
+ {
+ m_destBitmap.adopt(ImageBuffer::create(size, false));
+
+ if (needReferenceBuffer) {
+ m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
+ m_referenceBitmap.allocPixels();
+ m_referenceBitmap.eraseARGB(0, 0, 0, 0);
+ }
+ }
+
+ ImageBuffer* destBitmap() { return m_destBitmap.get(); }
+
+ // This bitmap will be empty if you don't specify needReferenceBuffer to the
+ // constructor.
+ SkBitmap* referenceBitmap() { return &m_referenceBitmap; }
+
+ // Returns whether the current layer will fix a buffer of the given size.
+ bool canHandleSize(const IntSize& size) const
+ {
+ return m_destBitmap->size().width() >= size.width() && m_destBitmap->size().height() >= size.height();
+ }
+
+private:
+ // The destination bitmap we're drawing into.
+ OwnPtr<ImageBuffer> m_destBitmap;
+
+ // This could be an ImageBuffer but this is an optimization. Since this is
+ // only ever used as a reference, we don't need to make a full
+ // PlatformCanvas using Skia on Windows. Just allocating a regular SkBitmap
+ // is much faster since it's just a Malloc rather than a GDI call.
+ SkBitmap m_referenceBitmap;
+};
+
+TransparencyWin::OwnedBuffers* TransparencyWin::m_cachedBuffers = 0;
+
+TransparencyWin::TransparencyWin()
+ : m_destContext(0)
+ , m_orgTransform()
+ , m_layerMode(NoLayer)
+ , m_transformMode(KeepTransform)
+ , m_drawContext(0)
+ , m_savedOnDrawContext(false)
+ , m_layerBuffer(0)
+ , m_referenceBitmap(0)
+{
+}
+
+TransparencyWin::~TransparencyWin()
+{
+ // This should be false, since calling composite() is mandatory.
+ ASSERT(!m_savedOnDrawContext);
+}
+
+void TransparencyWin::composite()
+{
+ // Matches the save() in initializeNewTextContext (or the constructor for
+ // SCALE) to put the context back into the same state we found it.
+ if (m_savedOnDrawContext) {
+ m_drawContext->restore();
+ m_savedOnDrawContext = false;
+ }
+
+ switch (m_layerMode) {
+ case NoLayer:
+ break;
+ case OpaqueCompositeLayer:
+ case WhiteLayer:
+ compositeOpaqueComposite();
+ break;
+ case TextComposite:
+ compositeTextComposite();
+ break;
+ }
+}
+
+void TransparencyWin::init(GraphicsContext* dest,
+ LayerMode layerMode,
+ TransformMode transformMode,
+ const IntRect& region)
+{
+ m_destContext = dest;
+ m_orgTransform = dest->getCTM();
+ m_layerMode = layerMode;
+ m_transformMode = transformMode;
+ m_sourceRect = region;
+
+ computeLayerSize();
+ setupLayer();
+ setupTransform(region);
+}
+
+void TransparencyWin::computeLayerSize()
+{
+ if (m_transformMode == Untransform) {
+ // The meaning of the "transformed" source rect is a little ambigous
+ // here. The rest of the code doesn't care about it in the Untransform
+ // case since we're using our own happy coordinate system. So we set it
+ // to be the source rect since that matches how the code below actually
+ // uses the variable: to determine how to translate things to account
+ // for the offset of the layer.
+ m_transformedSourceRect = m_sourceRect;
+ m_layerSize = IntSize(m_sourceRect.width(), m_sourceRect.height());
+ } else {
+ m_transformedSourceRect = m_orgTransform.mapRect(m_sourceRect);
+ m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSourceRect.height());
+ }
+}
+
+void TransparencyWin::setupLayer()
+{
+ switch (m_layerMode) {
+ case NoLayer:
+ setupLayerForNoLayer();
+ break;
+ case OpaqueCompositeLayer:
+ setupLayerForOpaqueCompositeLayer();
+ break;
+ case TextComposite:
+ setupLayerForTextComposite();
+ break;
+ case WhiteLayer:
+ setupLayerForWhiteLayer();
+ break;
+ }
+}
+
+void TransparencyWin::setupLayerForNoLayer()
+{
+ m_drawContext = m_destContext; // Draw to the source context.
+}
+
+void TransparencyWin::setupLayerForOpaqueCompositeLayer()
+{
+ initializeNewContext();
+
+ TransformationMatrix mapping;
+ mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
+ if (m_transformMode == Untransform){
+ // Compute the inverse mapping from the canvas space to the
+ // coordinate space of our bitmap.
+ mapping = m_orgTransform.inverse() * mapping;
+ }
+ compositeToCopy(*m_destContext, *m_drawContext, mapping);
+
+ // Save the reference layer so we can tell what changed.
+ SkCanvas referenceCanvas(*m_referenceBitmap);
+ referenceCanvas.drawBitmap(bitmapForContext(*m_drawContext), 0, 0);
+ // Layer rect represents the part of the original layer.
+}
+
+void TransparencyWin::setupLayerForTextComposite()
+{
+ ASSERT(m_transformMode == KeepTransform);
+ // Fall through to filling with white.
+ setupLayerForWhiteLayer();
+}
+
+void TransparencyWin::setupLayerForWhiteLayer()
+{
+ initializeNewContext();
+ m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white);
+ // Layer rect represents the part of the original layer.
+}
+
+void TransparencyWin::setupTransform(const IntRect& region)
+{
+ switch (m_transformMode) {
+ case KeepTransform:
+ setupTransformForKeepTransform(region);
+ break;
+ case Untransform:
+ setupTransformForUntransform();
+ break;
+ case ScaleTransform:
+ setupTransformForScaleTransform();
+ break;
+ }
+}
+
+void TransparencyWin::setupTransformForKeepTransform(const IntRect& region)
+{
+ if (m_layerMode != NoLayer) {
+ // Need to save things since we're modifying the transform.
+ m_drawContext->save();
+ m_savedOnDrawContext = true;
+
+ // Account for the fact that the layer may be offset from the
+ // original. This only happens when we create a layer that has the
+ // same coordinate space as the parent.
+ TransformationMatrix xform;
+ xform.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
+
+ // We're making a layer, so apply the old transform to the new one
+ // so it's maintained. We know the new layer has the identity
+ // transform now, we we can just multiply it.
+ xform = m_orgTransform * xform;
+ m_drawContext->concatCTM(xform);
+ }
+ m_drawRect = m_sourceRect;
+}
+
+void TransparencyWin::setupTransformForUntransform()
+{
+ ASSERT(m_layerMode != NoLayer);
+ // We now have a new layer with the identity transform, which is the
+ // Untransformed space we'll use for drawing.
+ m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
+}
+
+void TransparencyWin::setupTransformForScaleTransform()
+{
+ if (m_layerMode == NoLayer) {
+ // Need to save things since we're modifying the layer.
+ m_drawContext->save();
+ m_savedOnDrawContext = true;
+
+ // Undo the transform on the current layer when we're re-using the
+ // current one.
+ m_drawContext->concatCTM(m_drawContext->getCTM().inverse());
+
+ // We're drawing to the original layer with just a different size.
+ m_drawRect = m_transformedSourceRect;
+ } else {
+ // Just go ahead and use the layer's coordinate space to draw into.
+ // It will have the scaled size, and an identity transform loaded.
+ m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
+ }
+}
+
+void TransparencyWin::setTextCompositeColor(Color color)
+{
+ m_textCompositeColor = color;
+}
+
+void TransparencyWin::initializeNewContext()
+{
+ int pixelSize = m_layerSize.width() * m_layerSize.height();
+ if (pixelSize > maxCachedBufferPixelSize) {
+ // Create a 1-off buffer for drawing into. We only need the reference
+ // buffer if we're making an OpaqueCompositeLayer.
+ bool needReferenceBitmap = m_layerMode == OpaqueCompositeLayer;
+ m_ownedBuffers.set(new OwnedBuffers(m_layerSize, needReferenceBitmap));
+
+ m_layerBuffer = m_ownedBuffers->destBitmap();
+ m_drawContext = m_layerBuffer->context();
+ if (needReferenceBitmap)
+ m_referenceBitmap = m_ownedBuffers->referenceBitmap();
+ return;
+ }
+
+ if (m_cachedBuffers && m_cachedBuffers->canHandleSize(m_layerSize)) {
+ // We can re-use the existing buffer. We don't need to clear it since
+ // all layer modes will clear it in their initialization.
+ m_layerBuffer = m_cachedBuffers->destBitmap();
+ m_drawContext = m_cachedBuffers->destBitmap()->context();
+ bitmapForContext(*m_drawContext).eraseARGB(0, 0, 0, 0);
+ m_referenceBitmap = m_cachedBuffers->referenceBitmap();
+ m_referenceBitmap->eraseARGB(0, 0, 0, 0);
+ return;
+ }
+
+ // Create a new cached buffer.
+ if (m_cachedBuffers)
+ delete m_cachedBuffers;
+ m_cachedBuffers = new OwnedBuffers(m_layerSize, true);
+
+ m_layerBuffer = m_cachedBuffers->destBitmap();
+ m_drawContext = m_cachedBuffers->destBitmap()->context();
+ m_referenceBitmap = m_cachedBuffers->referenceBitmap();
+}
+
+void TransparencyWin::compositeOpaqueComposite()
+{
+ SkCanvas* destCanvas = canvasForContext(*m_destContext);
+ destCanvas->save();
+
+ SkBitmap* bitmap = const_cast<SkBitmap*>(
+ &bitmapForContext(*m_layerBuffer->context()));
+
+ // This function will be called for WhiteLayer as well, which we don't want
+ // to change.
+ if (m_layerMode == OpaqueCompositeLayer) {
+ // Fix up our bitmap, making it contain only the pixels which changed
+ // and transparent everywhere else.
+ SkAutoLockPixels sourceLock(*m_referenceBitmap);
+ SkAutoLockPixels lock(*bitmap);
+ for (int y = 0; y < bitmap->height(); y++) {
+ uint32_t* source = m_referenceBitmap->getAddr32(0, y);
+ uint32_t* dest = bitmap->getAddr32(0, y);
+ for (int x = 0; x < bitmap->width(); x++) {
+ // Clear out any pixels that were untouched.
+ if (dest[x] == source[x])
+ dest[x] = 0;
+ else
+ dest[x] |= (0xFF << SK_A32_SHIFT);
+ }
+ }
+ } else
+ makeLayerOpaque();
+
+ SkRect destRect;
+ if (m_transformMode != Untransform) {
+ // We want to use Untransformed space.
+ //
+ // Note that we DON'T call m_layerBuffer->image() here. This actually
+ // makes a copy of the image, which is unnecessary and slow. Instead, we
+ // just draw the image from inside the destination context.
+ SkMatrix identity;
+ identity.reset();
+ destCanvas->setMatrix(identity);
+
+ destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom());
+ } else
+ destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.right(), m_sourceRect.bottom());
+
+ SkPaint paint;
+ paint.setFilterBitmap(true);
+ paint.setAntiAlias(true);
+
+ // Note that we need to specify the source layer subset, since the bitmap
+ // may have been cached and it could be larger than what we're using.
+ SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
+ destCanvas->drawBitmapRect(*bitmap, &sourceRect, destRect, &paint);
+ destCanvas->restore();
+}
+
+void TransparencyWin::compositeTextComposite()
+{
+ const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopPlatformDevice().accessBitmap(true);
+ SkColor textColor = m_textCompositeColor.rgb();
+ for (int y = 0; y < m_layerSize.height(); y++) {
+ uint32_t* row = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_layerSize.width(); x++) {
+ // The alpha is the average of the R, G, and B channels.
+ int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) + SkGetPackedB32(row[x])) / 3;
+
+ // Apply that alpha to the text color and write the result.
+ row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha));
+ }
+ }
+
+ // Now the layer has text with the proper color and opacity.
+ SkCanvas* destCanvas = canvasForContext(*m_destContext);
+
+ // We want to use Untransformed space (see above)
+ SkMatrix identity;
+ identity.reset();
+ destCanvas->setMatrix(identity);
+ SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom() };
+
+ // Note that we need to specify the source layer subset, since the bitmap
+ // may have been cached and it could be larger than what we're using.
+ SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
+ destCanvas->drawBitmapRect(bitmap, &sourceRect, destRect, 0);
+ destCanvas->restore();
+}
+
+void TransparencyWin::makeLayerOpaque()
+{
+ SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->platformContext()->
+ canvas()->getTopPlatformDevice().accessBitmap(true));
+ for (int y = 0; y < m_layerSize.height(); y++) {
+ uint32_t* row = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_layerSize.width(); x++)
+ row[x] |= 0xFF000000;
+ }
+}
+
+} // namespace WebCore
+
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.h b/WebCore/platform/graphics/chromium/TransparencyWin.h
new file mode 100644
index 0000000..e1963b3
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TransparencyWin_h
+#define TransparencyWin_h
+
+#include <windows.h>
+
+#include "ImageBuffer.h"
+#include "Noncopyable.h"
+#include "TransformationMatrix.h"
+#include "wtf/OwnPtr.h"
+
+class SkBitmap;
+class SkCanvas;
+
+namespace WebCore {
+
+class GraphicsContext;
+class TransparencyWin_NoLayer_Test;
+class TransparencyWin_WhiteLayer_Test;
+class TransparencyWin_TextComposite_Test;
+class TransparencyWin_OpaqueCompositeLayer_Test;
+
+// Helper class that abstracts away drawing ClearType text and Windows form
+// controls either to the original context directly, or to an offscreen context
+// that is composited later manually. This is to get around Windows' inability
+// to handle the alpha channel, semitransparent text, and transformed form
+// controls.
+class TransparencyWin : public Noncopyable {
+public:
+ enum LayerMode {
+ // No extra layer is created. Drawing will happen to the source.
+ // Valid only with KeepTransform and ScaleTransform. The region being
+ // drawn onto must be opaque, since the modified region will be forced
+ // to opaque when drawing is complete.
+ NoLayer,
+
+ // Makes a temporary layer consisting of the composited layers below
+ // it. This result must be opaque. When complete, the result will be
+ // compared to the original, and the difference will be added to a thee
+ // destination layer.
+ //
+ // This mode only works if the lower layers are opque (normally the
+ // case for a web page) and layers are only drawn in the stack order,
+ // meaning you can never draw underneath a layer.
+ //
+ // This doesn't technically produce the correct answer in all cases. If
+ // you have an opaque base, a transparency layer, than a semitransparent
+ // drawing on top, the result will actually be blended in twice. But
+ // this isn't a very important case. This mode is used for form
+ // controls which are always opaque except for occationally some
+ // antialiasing. It means form control antialiasing will be too light in
+ // some cases, but only if you have extra layers.
+ OpaqueCompositeLayer,
+
+ // Allows semitransparent text to be drawn on any background (even if it
+ // is itself semitransparent), but disables ClearType.
+ //
+ // It makes a trmporary layer filled with white. This is composited with
+ // the lower layer with a custom color applied to produce the result.
+ // The caller must draw the text in black, and set the desired final
+ // text color by calling setTextCompositeColor().
+ //
+ // Only valid with KeepTransform, which is the only mode where drawing
+ // text in this fashion makes sense.
+ TextComposite,
+
+ // Makes a temporary layer filled with white. When complete, the layer
+ // will be forced to be opqaue (since Windows may have messed up the
+ // alpha channel) and composited down. Any areas not drawn into will
+ // remain white.
+ //
+ // This is the mode of last resort. If the opacity of the final image
+ // is unknown and we can't do the text trick (since we know its color),
+ // then we have to live with potential white halos. This is used for
+ // form control drawing, for example.
+ WhiteLayer,
+ };
+
+ enum TransformMode {
+ // There are no changes to the transform. Use this when drawing
+ // horizontal text. The current transform must not have rotation.
+ KeepTransform,
+
+ // Drawing happens in an Untransformed space, and then that bitmap is
+ // transformed according to the current context when it is copied down.
+ // Requires that a layer be created (layer mode is not NoLayer).
+ Untransform,
+
+ // When the current transform only has a scaling factor applied and
+ // you're drawing form elements, use this parameter. This will unscale
+ // the coordinate space, so the OS will just draw the form controls
+ // larger or smaller depending on the destination size.
+ ScaleTransform,
+ };
+
+ // You MUST call init() below.
+ // |region| is expressed relative to the current transformation.
+ TransparencyWin();
+ ~TransparencyWin();
+
+ // Initializes the members if you use the 0-argument constructor. Don't call
+ // this if you use the multiple-argument constructor.
+ void init(GraphicsContext* dest,
+ LayerMode layerMode,
+ TransformMode transformMode,
+ const IntRect& region);
+
+ // Combines the source and destination bitmaps using the given mode.
+ void composite();
+
+ // Returns the context for drawing into, which may be the destination
+ // context, or a temporary one.
+ GraphicsContext* context() const { return m_drawContext; }
+
+ PlatformGraphicsContext* platformContext() const { return m_drawContext->platformContext(); }
+
+ // When the mode is TextComposite, this sets the color that the text will
+ // get. See the enum above for more.
+ void setTextCompositeColor(Color color);
+
+ // Returns the input bounds translated into the destination space. This is
+ // not necessary for KeepTransform since the rectangle will be unchanged.
+ const IntRect& drawRect() { return m_drawRect; }
+
+private:
+ friend TransparencyWin_NoLayer_Test;
+ friend TransparencyWin_WhiteLayer_Test;
+ friend TransparencyWin_TextComposite_Test;
+ friend TransparencyWin_OpaqueCompositeLayer_Test;
+
+ class OwnedBuffers;
+
+ void computeLayerSize();
+
+ // Sets up a new layer, if any. setupLayer() will call the appopriate layer-
+ // specific helper. Must be called after computeLayerSize();
+ void setupLayer();
+ void setupLayerForNoLayer();
+ void setupLayerForOpaqueCompositeLayer();
+ void setupLayerForTextComposite();
+ void setupLayerForWhiteLayer();
+
+ // Sets up the transformation on the newly created layer. setupTransform()
+ // will call the appropriate transform-specific helper. Must be called after
+ // setupLayer().
+ void setupTransform(const IntRect& region);
+ void setupTransformForKeepTransform(const IntRect& region);
+ void setupTransformForUntransform();
+ void setupTransformForScaleTransform();
+
+ void initializeNewContext();
+
+ void compositeOpaqueComposite();
+ void compositeTextComposite();
+
+ // Fixes the alpha channel to make the region inside m_transformedRect
+ // opaque.
+ void makeLayerOpaque();
+
+ // The context our drawing will eventually end up in.
+ GraphicsContext* m_destContext;
+
+ // The original transform from the destination context.
+ TransformationMatrix m_orgTransform;
+
+ LayerMode m_layerMode;
+ TransformMode m_transformMode;
+
+ // The rectangle we're drawing in the destination's coordinate space
+ IntRect m_sourceRect;
+
+ // The source rectangle transformed into pixels in the final image. For
+ // Untransform this has no meaning, since the destination might not be a
+ // rectangle.
+ IntRect m_transformedSourceRect;
+
+ // The size of the layer we created. If there's no layer, this is the size
+ // of the region we're using in the source.
+ IntSize m_layerSize;
+
+ // The rectangle we're drawing to in the draw context's coordinate space.
+ // This will be the same as the source rectangle except for ScaleTransform
+ // where we create a new virtual coordinate space for the layer.
+ IntRect m_drawRect;
+
+ // Points to the graphics context to draw text to, which will either be
+ // the original context or the copy, depending on our mode.
+ GraphicsContext* m_drawContext;
+
+ // This flag is set when we call save() on the draw context during
+ // initialization. It allows us to avoid doing an extra save()/restore()
+ // when one is unnecessary.
+ bool m_savedOnDrawContext;
+
+ // Used only when m_mode = TextComposite, this is the color that the text
+ // will end up being once we figure out the transparency.
+ Color m_textCompositeColor;
+
+ // Layer we're drawing to.
+ ImageBuffer* m_layerBuffer;
+
+ // When the layer type is OpaqueCompositeLayer, this will contain a copy
+ // of the original contents of the m_layerBuffer before Windows drew on it.
+ // It allows us to re-create what Windows did to the layer. It is an
+ // SkBitmap instead of an ImageBuffer because an SkBitmap is lighter-weight
+ // (ImageBuffers are also GDI surfaces, which we don't need here).
+ SkBitmap* m_referenceBitmap;
+
+ // If the given size of bitmap can be cached, they will be stored here. Both
+ // the bitmap and the reference are guaranteed to be allocated if this
+ // member is non-null.
+ static OwnedBuffers* m_cachedBuffers;
+
+ // If a buffer was too big to be cached, it will be created temporarily, and
+ // this member tracks its scope to make sure it gets deleted. Always use
+ // m_layerBuffer, which will either point to this object, or the statically
+ // cached one. Don't access directly.
+ OwnPtr<OwnedBuffers> m_ownedBuffers;
+};
+
+} // namespace WebCore
+
+#endif // TransaprencyWin_h
diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
index caeb959..39b0847 100644
--- a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
+++ b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
@@ -34,6 +34,9 @@
#include <windows.h>
#include "FontUtilsChromiumWin.h"
+#include "PlatformContextSkia.h"
+#include "SkiaFontWin.h"
+#include "SkPoint.h"
#include <wtf/Assertions.h>
namespace WebCore {
@@ -58,7 +61,7 @@ static bool containsMissingGlyphs(WORD *glyphs,
SCRIPT_FONTPROPERTIES* properties)
{
for (int i = 0; i < length; ++i) {
- if (glyphs[i] == properties->wgDefault
+ if (glyphs[i] == properties->wgDefault
|| (glyphs[i] == properties->wgInvalid
&& glyphs[i] != properties->wgBlank))
return true;
@@ -112,6 +115,8 @@ UniscribeHelper::UniscribeHelper(const UChar* input,
, m_spaceWidth(0)
, m_wordSpacing(0)
, m_ascent(0)
+ , m_disableFontFallback(false)
+
{
m_logfont.lfFaceName[0] = 0;
}
@@ -285,11 +290,13 @@ int UniscribeHelper::xToCharacter(int x) const
return 0;
}
-void UniscribeHelper::draw(HDC dc, int x, int y, int from, int to)
+void UniscribeHelper::draw(GraphicsContext* graphicsContext,
+ HDC dc, int x, int y, int from, int to)
{
HGDIOBJ oldFont = 0;
int curX = x;
bool firstRun = true;
+ bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext);
for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
int itemIndex = m_screenOrder[screenIndex];
@@ -360,7 +367,7 @@ void UniscribeHelper::draw(HDC dc, int x, int y, int from, int to)
// Actually draw the glyphs we found.
int glyphCount = afterGlyph - fromGlyph;
if (fromGlyph >= 0 && glyphCount > 0) {
- // Account for the preceeding space we need to add to this run. We
+ // Account for the preceding space we need to add to this run. We
// don't need to count for the following space because that will be
// counted in advanceForItem below when we move to the next run.
innerOffset += shaping.m_prePadding;
@@ -377,30 +384,44 @@ void UniscribeHelper::draw(HDC dc, int x, int y, int from, int to)
// Fonts with different ascents can be used to render different
// runs. 'Across-runs' y-coordinate correction needs to be
// adjusted for each font.
- HRESULT hr = S_FALSE;
+ bool textOutOk = false;
for (int executions = 0; executions < 2; ++executions) {
- hr = ScriptTextOut(dc, shaping.m_scriptCache,
- curX + innerOffset,
- y - shaping.m_ascentOffset,
- 0, 0, &item.a, 0, 0,
- &shaping.m_glyphs[fromGlyph],
- glyphCount,
- &shaping.m_advance[fromGlyph],
- justify,
- &shaping.m_offsets[fromGlyph]);
- if (S_OK != hr && 0 == executions) {
- // If this ScriptTextOut is called from the renderer it
- // might fail because the sandbox is preventing it from
- // opening the font files. If we are running in the
- // renderer, TryToPreloadFont is overridden to ask the
- // browser to preload the font for us so we can access it.
+ if (useWindowsDrawing) {
+ HRESULT hr = ScriptTextOut(dc, shaping.m_scriptCache,
+ curX + innerOffset,
+ y - shaping.m_ascentOffset,
+ 0, 0, &item.a, 0, 0,
+ &shaping.m_glyphs[fromGlyph],
+ glyphCount,
+ &shaping.m_advance[fromGlyph],
+ justify,
+ &shaping.m_offsets[fromGlyph]);
+ ASSERT(S_OK == hr);
+ textOutOk = (hr == S_OK);
+ } else {
+ SkPoint origin;
+ origin.fX = curX + + innerOffset;
+ origin.fY = y + m_ascent - shaping.m_ascentOffset;
+ textOutOk = paintSkiaText(graphicsContext,
+ shaping.m_hfont,
+ glyphCount,
+ &shaping.m_glyphs[fromGlyph],
+ &shaping.m_advance[fromGlyph],
+ &shaping.m_offsets[fromGlyph],
+ &origin);
+ }
+
+ if (!textOutOk && 0 == executions) {
+ // If TextOut is called from the renderer it might fail
+ // because the sandbox is preventing it from opening the
+ // font files. If we are running in the renderer,
+ // TryToPreloadFont is overridden to ask the browser to
+ // preload the font for us so we can access it.
tryToPreloadFont(shaping.m_hfont);
continue;
}
break;
}
-
- ASSERT(S_OK == hr);
}
curX += advanceForItem(itemIndex);
@@ -527,7 +548,10 @@ bool UniscribeHelper::shape(const UChar* input,
HDC tempDC = 0;
HGDIOBJ oldFont = 0;
HRESULT hr;
- bool lastFallbackTried = false;
+ // When used to fill up glyph pages for simple scripts in non-BMP,
+ // we don't want any font fallback in this class. The simple script
+ // font path can take care of font fallback.
+ bool lastFallbackTried = m_disableFontFallback;
bool result;
int generatedGlyphs = 0;
@@ -557,7 +581,7 @@ bool UniscribeHelper::shape(const UChar* input,
// PurifyMarkAsInitialized(
// &shaping.m_glyphs[0],
// sizeof(shaping.m_glyphs[0] * generatedGlyphs);
-
+
ZeroMemory(&shaping.m_glyphs[0],
sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size());
#endif
@@ -587,7 +611,8 @@ bool UniscribeHelper::shape(const UChar* input,
tempDC = 0;
}
- if (nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) {
+ if (!m_disableFontFallback &&
+ nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) {
// The primary font does not support this run. Try next font.
// In case of web page rendering, they come from fonts specified in
// CSS stylesheets.
@@ -702,6 +727,13 @@ void UniscribeHelper::fillShapes()
if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping))
continue;
+ // At the moment, the only time m_disableFontFallback is set is
+ // when we look up glyph indices for non-BMP code ranges. So,
+ // we can skip the glyph placement. When that becomes not the case
+ // any more, we have to add a new flag to control glyph placement.
+ if (m_disableFontFallback)
+ continue;
+
// Compute placements. Note that offsets is documented incorrectly
// and is actually an array.
@@ -779,9 +811,6 @@ void UniscribeHelper::adjustSpaceAdvances()
int glyphIndex = shaping.m_logs[i];
int currentAdvance = shaping.m_advance[glyphIndex];
- // Don't give zero-width spaces a width.
- if (!currentAdvance)
- continue;
// currentAdvance does not include additional letter-spacing, but
// space_width does. Here we find out how off we are from the
diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.h b/WebCore/platform/graphics/chromium/UniscribeHelper.h
index d291105..ffd57db 100644
--- a/WebCore/platform/graphics/chromium/UniscribeHelper.h
+++ b/WebCore/platform/graphics/chromium/UniscribeHelper.h
@@ -44,6 +44,8 @@ class UniscribeTest_TooBig_Test; // A gunit test for UniscribeHelper.
namespace WebCore {
+class GraphicsContext;
+
#define UNISCRIBE_HELPER_STACK_RUNS 8
#define UNISCRIBE_HELPER_STACK_CHARS 32
@@ -145,6 +147,16 @@ public:
m_ascent = ascent;
}
+ // When set to true, this class is used only to look up glyph
+ // indices for a range of Unicode characters without glyph placement.
+ // By default, it's false. This should be set to true when this
+ // class is used for glyph index look-up for non-BMP characters
+ // in GlyphPageNodeChromiumWin.cpp.
+ void setDisableFontFallback(bool disableFontFallback)
+ {
+ m_disableFontFallback = true;
+ }
+
// You must call this after setting any options but before doing any
// other calls like asking for widths or drawing.
void init()
@@ -177,7 +189,8 @@ public:
// be pre-set.
//
// The y position is the upper left corner, NOT the baseline.
- void draw(HDC, int x, int y, int from, int to);
+ void draw(GraphicsContext* graphicsContext, HDC dc, int x, int y, int from,
+ int to);
// Returns the first glyph assigned to the character at the given offset.
// This function is used to retrieve glyph information when Uniscribe is
@@ -378,6 +391,7 @@ private:
int m_letterSpacing;
int m_spaceWidth;
int m_wordSpacing;
+ bool m_disableFontFallback;
// Uniscribe breaks the text into Runs. These are one length of text that is
// in one script and one direction. This array is in reading order.
diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h
index efa5dd5..20c52e5 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformData.h
+++ b/WebCore/platform/graphics/gtk/FontPlatformData.h
@@ -74,6 +74,7 @@ public:
FontPlatformData(float size, bool bold, bool italic);
FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic);
+ FontPlatformData(const FontPlatformData&);
~FontPlatformData();
@@ -95,6 +96,7 @@ public:
}
bool operator==(const FontPlatformData&) const;
+ FontPlatformData& operator=(const FontPlatformData&);
bool isHashTableDeletedValue() const {
#if defined(USE_FREETYPE)
return m_pattern == hashTableDeletedFontValue();
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
index 17d789b..68685e9 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
@@ -3,6 +3,7 @@
* Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
* Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
* Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2009 Igalia S.L.
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -161,6 +162,45 @@ FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool b
m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
}
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ // Check for self-assignment.
+ if (this == &other)
+ return *this;
+
+ m_size = other.m_size;
+ m_syntheticBold = other.m_syntheticBold;
+ m_syntheticOblique = other.m_syntheticOblique;
+
+ if (other.m_scaledFont)
+ cairo_scaled_font_reference(other.m_scaledFont);
+ if (m_scaledFont)
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = other.m_scaledFont;
+
+ if (other.m_pattern)
+ FcPatternReference(other.m_pattern);
+ if (m_pattern)
+ FcPatternDestroy(m_pattern);
+ m_pattern = other.m_pattern;
+
+ if (m_fallbacks) {
+ FcFontSetDestroy(m_fallbacks);
+ // This will be re-created on demand.
+ m_fallbacks = 0;
+ }
+
+ return *this;
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& other)
+ : m_pattern(0)
+ , m_fallbacks(0)
+ , m_scaledFont(0)
+{
+ *this = other;
+}
+
bool FontPlatformData::init()
{
static bool initialized = false;
@@ -176,6 +216,20 @@ bool FontPlatformData::init()
FontPlatformData::~FontPlatformData()
{
+ if (m_pattern && ((FcPattern*)-1 != m_pattern)) {
+ FcPatternDestroy(m_pattern);
+ m_pattern = 0;
+ }
+
+ if (m_fallbacks) {
+ FcFontSetDestroy(m_fallbacks);
+ m_fallbacks = 0;
+ }
+
+ if (m_scaledFont) {
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = 0;
+ }
}
bool FontPlatformData::isFixedPitch()
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
index be3fd43..88bf427 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
@@ -4,6 +4,7 @@
* Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
* Copyright (C) 2007 Holger Hans Peter Freyther
* Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2009 Igalia S.L.
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -46,8 +47,8 @@
namespace WebCore {
- PangoFontMap* FontPlatformData::m_fontMap = 0;
- GHashTable* FontPlatformData::m_hashTable = 0;
+PangoFontMap* FontPlatformData::m_fontMap = 0;
+GHashTable* FontPlatformData::m_hashTable = 0;
FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
: m_context(0)
@@ -193,7 +194,20 @@ bool FontPlatformData::init()
FontPlatformData::~FontPlatformData()
{
- // Destroy takes place in FontData::platformDestroy().
+ if (m_font && m_font != reinterpret_cast<PangoFont*>(-1)) {
+ g_object_unref(m_font);
+ m_font = 0;
+ }
+
+ if (m_context) {
+ g_object_unref(m_context);
+ m_context = 0;
+ }
+
+ if (m_scaledFont) {
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = 0;
+ }
}
bool FontPlatformData::isFixedPitch()
@@ -211,6 +225,45 @@ void FontPlatformData::setFont(cairo_t* cr) const
cairo_set_scaled_font(cr, m_scaledFont);
}
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ // Check for self-assignment.
+ if (this == &other)
+ return *this;
+
+ m_size = other.m_size;
+ m_syntheticBold = other.m_syntheticBold;
+ m_syntheticOblique = other.m_syntheticOblique;
+
+ if (other.m_scaledFont)
+ cairo_scaled_font_reference(other.m_scaledFont);
+ if (m_scaledFont)
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = other.m_scaledFont;
+
+ if (other.m_font)
+ g_object_ref(other.m_font);
+ if (m_font)
+ g_object_unref(m_font);
+ m_font = other.m_font;
+
+ if (other.m_context)
+ g_object_ref(other.m_context);
+ if (m_context)
+ g_object_unref(m_context);
+ m_context = other.m_context;
+
+ return *this;
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& other)
+ : m_context(0)
+ , m_font(0)
+ , m_scaledFont(0)
+{
+ *this = other;
+}
+
bool FontPlatformData::operator==(const FontPlatformData& other) const
{
if (m_font == other.m_font)
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
index 1f0cac6..8dd1333 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2007 Collabora Ltd. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
*
@@ -101,6 +101,22 @@ gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, g
return true;
}
+static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, MediaPlayerPrivate* playerPrivate)
+{
+ playerPrivate->repaint();
+}
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_playBin(0)
@@ -111,10 +127,10 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_isEndReached(false)
, m_volume(0.5f)
, m_networkState(MediaPlayer::Empty)
- , m_readyState(MediaPlayer::DataUnavailable)
+ , m_readyState(MediaPlayer::HaveNothing)
, m_startedPlaying(false)
, m_isStreaming(false)
- , m_rect(IntRect())
+ , m_size(IntSize())
, m_visible(true)
{
@@ -140,15 +156,15 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
}
}
-void MediaPlayerPrivate::load(String url)
+void MediaPlayerPrivate::load(const String& url)
{
LOG_VERBOSE(Media, "Load %s", url.utf8().data());
if (m_networkState != MediaPlayer::Loading) {
m_networkState = MediaPlayer::Loading;
m_player->networkStateChanged();
}
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
@@ -175,24 +191,28 @@ void MediaPlayerPrivate::pause()
m_startedPlaying = false;
}
-float MediaPlayerPrivate::duration()
+float MediaPlayerPrivate::duration() const
{
if (!m_playBin)
return 0.0;
- GstFormat fmt = GST_FORMAT_TIME;
- gint64 len = 0;
-
- if (gst_element_query_duration(m_playBin, &fmt, &len))
- LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(len));
- else
- LOG_VERBOSE(Media, "Duration query failed ");
+ GstFormat timeFormat = GST_FORMAT_TIME;
+ gint64 timeLength = 0;
- if ((GstClockTime)len == GST_CLOCK_TIME_NONE) {
+ // FIXME: We try to get the duration, but we do not trust the
+ // return value of the query function only; the problem we are
+ // trying to work-around here is that pipelines in stream mode may
+ // not be able to figure out the duration, but still return true!
+ // See https://bugs.webkit.org/show_bug.cgi?id=24639.
+ if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeLength <= 0) {
+ LOG_VERBOSE(Media, "Time duration query failed.");
m_isStreaming = true;
return numeric_limits<float>::infinity();
}
- return (float) (len / 1000000000.0);
+
+ LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
+
+ return (float) (timeLength / 1000000000.0);
// FIXME: handle 3.14.9.5 properly
}
@@ -288,7 +308,7 @@ bool MediaPlayerPrivate::seeking() const
}
// Returns the size of the video
-IntSize MediaPlayerPrivate::naturalSize()
+IntSize MediaPlayerPrivate::naturalSize() const
{
if (!hasVideo())
return IntSize();
@@ -302,7 +322,7 @@ IntSize MediaPlayerPrivate::naturalSize()
return IntSize(x, y);
}
-bool MediaPlayerPrivate::hasVideo()
+bool MediaPlayerPrivate::hasVideo() const
{
gint currentVideo = -1;
if (m_playBin)
@@ -355,17 +375,17 @@ int MediaPlayerPrivate::dataRate() const
return 1;
}
-MediaPlayer::NetworkState MediaPlayerPrivate::networkState()
+MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
{
return m_networkState;
}
-MediaPlayer::ReadyState MediaPlayerPrivate::readyState()
+MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
{
return m_readyState;
}
-float MediaPlayerPrivate::maxTimeBuffered()
+float MediaPlayerPrivate::maxTimeBuffered() const
{
notImplemented();
LOG_VERBOSE(Media, "maxTimeBuffered");
@@ -373,7 +393,7 @@ float MediaPlayerPrivate::maxTimeBuffered()
return m_isStreaming ? 0 : maxTimeLoaded();
}
-float MediaPlayerPrivate::maxTimeSeekable()
+float MediaPlayerPrivate::maxTimeSeekable() const
{
// TODO
LOG_VERBOSE(Media, "maxTimeSeekable");
@@ -383,7 +403,7 @@ float MediaPlayerPrivate::maxTimeSeekable()
return maxTimeLoaded();
}
-float MediaPlayerPrivate::maxTimeLoaded()
+float MediaPlayerPrivate::maxTimeLoaded() const
{
// TODO
LOG_VERBOSE(Media, "maxTimeLoaded");
@@ -391,7 +411,7 @@ float MediaPlayerPrivate::maxTimeLoaded()
return duration();
}
-unsigned MediaPlayerPrivate::bytesLoaded()
+unsigned MediaPlayerPrivate::bytesLoaded() const
{
notImplemented();
LOG_VERBOSE(Media, "bytesLoaded");
@@ -404,14 +424,14 @@ unsigned MediaPlayerPrivate::bytesLoaded()
return 1;//totalBytes() * maxTime / dur;
}
-bool MediaPlayerPrivate::totalBytesKnown()
+bool MediaPlayerPrivate::totalBytesKnown() const
{
notImplemented();
LOG_VERBOSE(Media, "totalBytesKnown");
return totalBytes() > 0;
}
-unsigned MediaPlayerPrivate::totalBytes()
+unsigned MediaPlayerPrivate::totalBytes() const
{
notImplemented();
LOG_VERBOSE(Media, "totalBytes");
@@ -455,12 +475,11 @@ void MediaPlayerPrivate::updateStates()
gst_element_state_get_name(pending));
if (state == GST_STATE_READY) {
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (state == GST_STATE_PAUSED) {
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveEnoughData;
}
- if (m_networkState < MediaPlayer::Loaded)
- m_networkState = MediaPlayer::Loaded;
+ m_networkState = MediaPlayer::Loaded;
g_object_get(m_playBin, "source", &m_source, NULL);
if (!m_source)
@@ -478,12 +497,11 @@ void MediaPlayerPrivate::updateStates()
gst_element_state_get_name(state),
gst_element_state_get_name(pending));
if (state == GST_STATE_READY) {
- m_readyState = MediaPlayer::CanPlay;
+ m_readyState = MediaPlayer::HaveFutureData;
} else if (state == GST_STATE_PAUSED) {
- m_readyState = MediaPlayer::CanPlay;
+ m_readyState = MediaPlayer::HaveCurrentData;
}
- if (m_networkState < MediaPlayer::LoadedMetaData)
- m_networkState = MediaPlayer::LoadedMetaData;
+ m_networkState = MediaPlayer::Loading;
break;
default:
LOG_VERBOSE(Media, "Else : %d", ret);
@@ -491,7 +509,7 @@ void MediaPlayerPrivate::updateStates()
}
if (seeking())
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveNothing;
if (m_networkState != oldNetworkState) {
LOG_VERBOSE(Media, "Network State Changed from %u to %u",
@@ -540,19 +558,19 @@ void MediaPlayerPrivate::didEnd()
void MediaPlayerPrivate::loadingFailed()
{
- if (m_networkState != MediaPlayer::LoadFailed) {
- m_networkState = MediaPlayer::LoadFailed;
+ if (m_networkState != MediaPlayer::NetworkError) {
+ m_networkState = MediaPlayer::NetworkError;
m_player->networkStateChanged();
}
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
}
-void MediaPlayerPrivate::setRect(const IntRect& rect)
+void MediaPlayerPrivate::setSize(const IntSize& size)
{
- m_rect = rect;
+ m_size = size;
}
void MediaPlayerPrivate::setVisible(bool visible)
@@ -573,7 +591,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
if (!m_visible)
return;
- //TODO: m_rect vs rect?
+ //TODO: m_size vs rect?
cairo_t* cr = context->platformContext();
cairo_save(cr);
@@ -587,11 +605,18 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
{
- // FIXME: do the real thing
+ // FIXME: query the engine to see what types are supported
notImplemented();
types.add(String("video/x-theora+ogg"));
}
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // FIXME: query the engine to see what types are supported
+ notImplemented();
+ return type == "video/x-theora+ogg" ? (!codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
void MediaPlayerPrivate::createGSTPlayBin(String url)
{
ASSERT(!m_playBin);
@@ -613,6 +638,8 @@ void MediaPlayerPrivate::createGSTPlayBin(String url)
g_object_set(m_playBin, "audio-sink", audioSink, NULL);
g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
+ g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
+
setVolume(m_volume);
}
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
index 3f08bc0..628f0ac 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2007 Collabora Ltd. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
*
@@ -24,7 +24,7 @@
#if ENABLE(VIDEO)
-#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
#include "Timer.h"
#include <gtk/gtk.h>
@@ -44,20 +44,21 @@ namespace WebCore {
gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
- class MediaPlayerPrivate : Noncopyable
+ class MediaPlayerPrivate : public MediaPlayerPrivateInterface
{
friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data);
friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
public:
- MediaPlayerPrivate(MediaPlayer*);
+
+ static void registerMediaEngine(MediaEngineRegistrar);
~MediaPlayerPrivate();
- IntSize naturalSize();
- bool hasVideo();
+ IntSize naturalSize() const;
+ bool hasVideo() const;
- void load(String url);
+ void load(const String &url);
void cancelLoad();
void play();
@@ -66,7 +67,7 @@ namespace WebCore {
bool paused() const;
bool seeking() const;
- float duration();
+ float duration() const;
float currentTime() const;
void seek(float);
void setEndTime(float);
@@ -77,17 +78,17 @@ namespace WebCore {
int dataRate() const;
- MediaPlayer::NetworkState networkState();
- MediaPlayer::ReadyState readyState();
+ MediaPlayer::NetworkState networkState() const;
+ MediaPlayer::ReadyState readyState() const;
- float maxTimeBuffered();
- float maxTimeSeekable();
- unsigned bytesLoaded();
- bool totalBytesKnown();
- unsigned totalBytes();
+ float maxTimeBuffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ bool totalBytesKnown() const;
+ unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect&);
+ void setSize(const IntSize&);
void loadStateChanged();
void rateChanged();
@@ -99,15 +100,20 @@ namespace WebCore {
void repaint();
void paint(GraphicsContext*, const IntRect&);
- static void getSupportedTypes(HashSet<String>&);
- static bool isAvailable() { return true; }
private:
+ MediaPlayerPrivate(MediaPlayer*);
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable() { return true; }
+
void updateStates();
void cancelSeek();
void endPointTimerFired(Timer<MediaPlayerPrivate>*);
- float maxTimeLoaded();
+ float maxTimeLoaded() const;
void startEndPointTimerIfNeeded();
void createGSTPlayBin(String url);
@@ -124,8 +130,8 @@ namespace WebCore {
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
bool m_startedPlaying;
- bool m_isStreaming;
- IntRect m_rect;
+ mutable bool m_isStreaming;
+ IntSize m_size;
bool m_visible;
cairo_surface_t* m_surface;
};
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
index d076cb6..4203a3c 100644
--- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
@@ -53,6 +53,13 @@ void SimpleFontData::platformInit()
m_ascent = static_cast<int>(font_extents.ascent);
m_descent = static_cast<int>(font_extents.descent);
m_lineSpacing = static_cast<int>(font_extents.height);
+ // There seems to be some rounding error in cairo (or in how we
+ // use cairo) with some fonts, like DejaVu Sans Mono, which makes
+ // cairo report a height smaller than ascent + descent, which is
+ // wrong and confuses WebCore's layout system. Workaround this
+ // while we figure out what's going on.
+ if (m_lineSpacing < m_ascent + m_descent)
+ m_lineSpacing = m_ascent + m_descent;
cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents);
m_xHeight = text_extents.height;
cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents);
@@ -64,31 +71,13 @@ void SimpleFontData::platformDestroy()
{
delete m_smallCapsFontData;
m_smallCapsFontData = 0;
-
- if (isCustomFont())
- return;
-
- if (m_font.m_pattern && ((FcPattern*)-1 != m_font.m_pattern)) {
- FcPatternDestroy(m_font.m_pattern);
- m_font.m_pattern = 0;
- }
-
- if (m_font.m_fallbacks) {
- FcFontSetDestroy(m_font.m_fallbacks);
- m_font.m_fallbacks = 0;
- }
-
- if (m_font.m_scaledFont) {
- cairo_scaled_font_destroy(m_font.m_scaledFont);
- m_font.m_scaledFont = 0;
- }
}
SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
{
if (!m_smallCapsFontData) {
FontDescription desc = FontDescription(fontDescription);
- desc.setSpecifiedSize(0.70f*fontDescription.computedSize());
+ desc.setComputedSize(0.70f*fontDescription.computedSize());
const FontPlatformData* pdata = new FontPlatformData(desc, desc.family().family());
m_smallCapsFontData = new SimpleFontData(*pdata);
}
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
index db8dd3b..e345a8c 100644
--- a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
@@ -52,6 +52,13 @@ void SimpleFontData::platformInit()
m_ascent = static_cast<int>(font_extents.ascent);
m_descent = static_cast<int>(font_extents.descent);
m_lineSpacing = static_cast<int>(font_extents.height);
+ // There seems to be some rounding error in cairo (or in how we
+ // use cairo) with some fonts, like DejaVu Sans Mono, which makes
+ // cairo report a height smaller than ascent + descent, which is
+ // wrong and confuses WebCore's layout system. Workaround this
+ // while we figure out what's going on.
+ if (m_lineSpacing < m_ascent + m_descent)
+ m_lineSpacing = m_ascent + m_descent;
cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents);
m_xHeight = text_extents.height;
cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents);
@@ -61,24 +68,6 @@ void SimpleFontData::platformInit()
void SimpleFontData::platformDestroy()
{
- if (!isCustomFont()) {
-
- if (m_font.m_font && m_font.m_font != reinterpret_cast<PangoFont*>(-1)) {
- g_object_unref(m_font.m_font);
- m_font.m_font = 0;
- }
-
- if (m_font.m_context) {
- g_object_unref (m_font.m_context);
- m_font.m_context = 0;
- }
-
- if (m_font.m_scaledFont) {
- cairo_scaled_font_destroy(m_font.m_scaledFont);
- m_font.m_scaledFont = 0;
- }
- }
-
delete m_smallCapsFontData;
m_smallCapsFontData = 0;
}
diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
index 04df7ac..436841c 100644
--- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
@@ -46,10 +46,17 @@ static GstElementDetails webkit_video_sink_details =
(gchar*) "Alp Toker <alp@atoker.com>");
enum {
+ REPAINT_REQUESTED,
+ LAST_SIGNAL
+};
+
+enum {
PROP_0,
PROP_SURFACE
};
+static guint webkit_video_sink_signals[LAST_SIGNAL] = { 0, };
+
struct _WebKitVideoSinkPrivate {
cairo_surface_t* surface;
GAsyncQueue* async_queue;
@@ -95,11 +102,10 @@ webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass)
static gboolean
webkit_video_sink_idle_func(gpointer data)
{
- WebKitVideoSinkPrivate* priv;
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(data);
+ WebKitVideoSinkPrivate* priv = sink->priv;
GstBuffer* buffer;
- priv = (WebKitVideoSinkPrivate*)data;
-
if (!priv->async_queue)
return FALSE;
@@ -121,6 +127,8 @@ webkit_video_sink_idle_func(gpointer data)
gst_buffer_unref(buffer);
+ g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0);
+
return FALSE;
}
@@ -131,7 +139,7 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
WebKitVideoSinkPrivate* priv = sink->priv;
g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer));
- g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, priv, NULL);
+ g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, sink, NULL);
return GST_FLOW_OK;
}
@@ -279,6 +287,15 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
gstbase_sink_class->stop = webkit_video_sink_stop;
gstbase_sink_class->set_caps = webkit_video_sink_set_caps;
+ webkit_video_sink_signals[REPAINT_REQUESTED] = g_signal_new("repaint-requested",
+ G_TYPE_FROM_CLASS(klass),
+ (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
g_object_class_install_property(
gobject_class, PROP_SURFACE,
g_param_spec_pointer("surface", "surface", "Target cairo_surface_t*",
diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm
index 9b0f770..1c4350c 100644
--- a/WebCore/platform/graphics/mac/ColorMac.mm
+++ b/WebCore/platform/graphics/mac/ColorMac.mm
@@ -27,6 +27,7 @@
#import "Color.h"
#import "ColorMac.h"
+#import <AppKit/AppKit.h>
#import <wtf/Assertions.h>
#import <wtf/StdLibExtras.h>
#import <wtf/RetainPtr.h>
@@ -110,7 +111,7 @@ static CGColorRef CGColorFromNSColor(NSColor* color)
return cgColor;
}
-CGColorRef cgColor(const Color& c)
+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
diff --git a/WebCore/platform/graphics/mac/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm
index 26d84cc..2202459 100644
--- a/WebCore/platform/graphics/mac/FontCacheMac.mm
+++ b/WebCore/platform/graphics/mac/FontCacheMac.mm
@@ -35,7 +35,8 @@
#import "FontPlatformData.h"
#import "WebCoreSystemInterface.h"
#import "WebFontCache.h"
-#include <wtf/StdLibExtras.h>
+#import <AppKit/AppKit.h>
+#import <wtf/StdLibExtras.h>
#ifdef BUILDING_ON_TIGER
typedef int NSInteger;
@@ -191,13 +192,11 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
actualTraits = [fontManager traitsOfFont:nsFont];
NSInteger actualWeight = [fontManager weightOfFont:nsFont];
- FontPlatformData* result = new FontPlatformData;
+ NSFont *platformFont = fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont];
+ bool syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight);
+ bool syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait);
- // Use the correct font for print vs. screen.
- result->setFont(fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont]);
- result->m_syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight);
- result->m_syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait);
- return result;
+ return new FontPlatformData(platformFont, syntheticBold, syntheticOblique);
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
index 9aa4997..e40bbab 100644
--- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
@@ -29,7 +29,8 @@ namespace WebCore {
FontCustomPlatformData::~FontCustomPlatformData()
{
- ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault);
+ if (m_atsContainer)
+ ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault);
CGFontRelease(m_cgFont);
}
@@ -42,8 +43,18 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
{
ASSERT_ARG(buffer, buffer);
- // Use ATS to activate the font.
ATSFontContainerRef containerRef = 0;
+ ATSFontRef fontRef = 0;
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ RetainPtr<CFDataRef> bufferData(AdoptCF, buffer->createCFData());
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(bufferData.get()));
+
+ CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider.get());
+ if (!cgFontRef)
+ return 0;
+#else
+ // Use ATS to activate the font.
// The value "3" means that the font is private and can't be seen by anyone else.
ATSFontActivateFromMemory((void*)buffer->data(), buffer->size(), 3, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &containerRef);
@@ -58,7 +69,6 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
return 0;
}
- ATSFontRef fontRef = 0;
ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1, &fontRef, NULL);
if (!fontRef) {
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
@@ -77,6 +87,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
return 0;
}
+#endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
return new FontCustomPlatformData(containerRef, fontRef, cgFontRef);
}
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.h b/WebCore/platform/graphics/mac/FontCustomPlatformData.h
index 1e73ae0..2c1222f 100644
--- a/WebCore/platform/graphics/mac/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.h
@@ -22,6 +22,7 @@
#define FontCustomPlatformData_h
#include "FontRenderingMode.h"
+#include <CoreFoundation/CFBase.h>
#include <wtf/Noncopyable.h>
typedef struct CGFont* CGFontRef;
diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm
index bef18d0..dc86c4b 100644
--- a/WebCore/platform/graphics/mac/FontMac.mm
+++ b/WebCore/platform/graphics/mac/FontMac.mm
@@ -29,6 +29,7 @@
#import "SimpleFontData.h"
#import "WebCoreSystemInterface.h"
#import "WebCoreTextRenderer.h"
+#import <AppKit/AppKit.h>
#define SYNTHETIC_OBLIQUE_ANGLE 14
diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm
index 52493e7..3794149 100644
--- a/WebCore/platform/graphics/mac/FontMacATSUI.mm
+++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm
@@ -30,6 +30,7 @@
#import "Logging.h"
#import "ShapeArabic.h"
#import "SimpleFontData.h"
+#import <AppKit/NSGraphicsContext.h>
#import <wtf/OwnArrayPtr.h>
#define SYNTHETIC_OBLIQUE_ANGLE 14
diff --git a/WebCore/platform/graphics/mac/FontPlatformData.h b/WebCore/platform/graphics/mac/FontPlatformData.h
index 40a2dbd..e911867 100644
--- a/WebCore/platform/graphics/mac/FontPlatformData.h
+++ b/WebCore/platform/graphics/mac/FontPlatformData.h
@@ -1,8 +1,8 @@
/*
* This file is part of the internal font implementation.
- * It should not be included by source files outside it.
+ * It should not be included by source files outside of it.
*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -33,7 +33,6 @@ class NSFont;
#endif
typedef struct CGFont* CGFontRef;
-typedef UInt32 ATSUFontID;
#ifndef BUILDING_ON_TIGER
typedef const struct __CTFont* CTFontRef;
#endif
@@ -42,6 +41,8 @@ typedef const struct __CTFont* CTFontRef;
#include <objc/objc-auto.h>
#include <wtf/RetainPtr.h>
+typedef UInt32 ATSUFontID;
+
namespace WebCore {
#ifndef BUILDING_ON_TIGER
@@ -61,10 +62,15 @@ struct FontPlatformData {
{
}
- FontPlatformData(NSFont * = 0, bool syntheticBold = false, bool syntheticOblique = false);
+ FontPlatformData(NSFont *nsFont, bool syntheticBold = false, bool syntheticOblique = false);
- FontPlatformData(CGFontRef f, ATSUFontID fontID, float s, bool b , bool o)
- : m_syntheticBold(b), m_syntheticOblique(o), m_atsuFontID(fontID), m_size(s), m_font(0), m_cgFont(f)
+ FontPlatformData(CGFontRef cgFont, ATSUFontID fontID, float size, bool syntheticBold, bool syntheticOblique)
+ : m_syntheticBold(syntheticBold)
+ , m_syntheticOblique(syntheticOblique)
+ , m_atsuFontID(fontID)
+ , m_size(size)
+ , m_font(0)
+ , m_cgFont(cgFont)
{
}
diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
index 7cd9ab6..83da4a9 100644
--- a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
+++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
@@ -1,7 +1,7 @@
/*
* This file is part of the internal font implementation.
*
- * Copyright (C) 2006-7 Apple Computer, Inc.
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,21 +24,24 @@
#import "FontPlatformData.h"
#import "WebCoreSystemInterface.h"
+#import <AppKit/NSFont.h>
namespace WebCore {
-FontPlatformData::FontPlatformData(NSFont *f, bool b , bool o)
-: m_syntheticBold(b), m_syntheticOblique(o), m_font(f)
+FontPlatformData::FontPlatformData(NSFont *nsFont, bool syntheticBold, bool syntheticOblique)
+ : m_syntheticBold(syntheticBold)
+ , m_syntheticOblique(syntheticOblique)
+ , m_font(nsFont)
{
- if (f)
- CFRetain(f);
- m_size = f ? [f pointSize] : 0.0f;
+ if (nsFont)
+ CFRetain(nsFont);
+ m_size = nsFont ? [nsFont pointSize] : 0.0f;
#ifndef BUILDING_ON_TIGER
- m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(f), 0));
- m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(f), 0);
+ m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(nsFont), 0));
+ m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(nsFont), 0);
#else
- m_cgFont = wkGetCGFontFromNSFont(f);
- m_atsuFontID = wkGetNSFontATSUFontId(f);
+ m_cgFont = wkGetCGFontFromNSFont(nsFont);
+ m_atsuFontID = wkGetNSFontATSUFontId(nsFont);
#endif
}
diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
index ae829e2..4e11602 100644
--- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm
+++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
@@ -27,10 +27,13 @@
#import "GraphicsContext.h"
#import "../cg/GraphicsContextPlatformPrivateCG.h"
+#import <AppKit/AppKit.h>
#import <wtf/StdLibExtras.h>
#import "WebCoreSystemInterface.h"
+@class NSColor;
+
// FIXME: More of this should use CoreGraphics instead of AppKit.
// FIXME: More of this should move into GraphicsContextCG.cpp.
@@ -47,7 +50,7 @@ void GraphicsContext::drawFocusRing(const Color& color)
int radius = (focusRingWidth() - 1) / 2;
int offset = radius + focusRingOffset();
- CGColorRef colorRef = color.isValid() ? cgColor(color) : 0;
+ CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0;
CGMutablePathRef focusRingPath = CGPathCreateMutable();
const Vector<IntRect>& rects = focusRingRects();
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
new file mode 100644
index 0000000..3a692d3
--- /dev/null
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsLayerCA_h
+#define GraphicsLayerCA_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayer.h"
+#include <wtf/RetainPtr.h>
+
+@class WebAnimationDelegate;
+@class WebLayer;
+
+namespace WebCore {
+
+class GraphicsLayerCA : public GraphicsLayer {
+public:
+
+ GraphicsLayerCA(GraphicsLayerClient*);
+ virtual ~GraphicsLayerCA();
+
+ virtual void setName(const String&);
+
+ // for hosting this GraphicsLayer in a native layer hierarchy
+ virtual NativeLayer nativeLayer() const;
+
+ 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 setPosition(const FloatPoint&);
+ virtual void setAnchorPoint(const FloatPoint3D&);
+ virtual void setSize(const FloatSize&);
+
+ virtual void setTransform(const TransformationMatrix&);
+
+ virtual void setChildrenTransform(const TransformationMatrix&);
+
+ virtual void setPreserves3D(bool);
+ virtual void setMasksToBounds(bool);
+ virtual void setDrawsContent(bool);
+
+ virtual void setBackgroundColor(const Color&, const Animation* anim = 0, double beginTime = 0);
+ virtual void clearBackgroundColor();
+
+ virtual void setContentsOpaque(bool);
+ virtual void setBackfaceVisibility(bool);
+
+ // return true if we started an animation
+ virtual bool setOpacity(float, const Animation* anim = 0, double beginTime = 0);
+
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+
+ virtual void suspendAnimations();
+ virtual void resumeAnimations();
+
+ virtual bool animateTransform(const TransformValueList&, const IntSize&, const Animation*, double beginTime, bool isTransition);
+ virtual bool animateFloat(AnimatedPropertyID, const FloatValueList&, const Animation*, double beginTime);
+
+ virtual void setContentsToImage(Image*);
+ virtual void setContentsToVideo(PlatformLayer*);
+ virtual void clearContents();
+
+ virtual void updateContentsRect();
+
+ virtual PlatformLayer* platformLayer() const;
+
+#ifndef NDEBUG
+ virtual void setDebugBackgroundColor(const Color&);
+ virtual void setDebugBorder(const Color&, float borderWidth);
+ virtual void setZPosition(float);
+#endif
+
+private:
+ WebLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
+ WebLayer* hostLayerForSublayers() const;
+ WebLayer* layerForSuperlayer() const;
+
+ WebLayer* animatedLayer(AnimatedPropertyID property) const
+ {
+ return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
+ }
+
+ void setBasicAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation*, double time);
+ void setKeyframeAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* keys, void* values, void* timingFunctions, bool isTransition, const Animation*, double time);
+
+ virtual void removeAnimation(int index, bool reset);
+
+ bool requiresTiledLayer(const FloatSize&) const;
+ void swapFromOrToTiledLayer(bool useTiledLayer);
+
+ void setHasContentsLayer(bool);
+ void setContentsLayer(WebLayer*);
+ void setContentsLayerFlipped(bool);
+
+ RetainPtr<WebLayer> m_layer;
+ RetainPtr<WebLayer> m_transformLayer;
+ RetainPtr<WebLayer> m_contentsLayer;
+
+ RetainPtr<WebAnimationDelegate> m_animationDelegate;
+
+ bool m_contentLayerForImageOrVideo;
+};
+
+} // namespace WebCore
+
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayerCA_h
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
new file mode 100644
index 0000000..f3f2d7f
--- /dev/null
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
@@ -0,0 +1,1540 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "GraphicsLayerCA.h"
+
+#import "Animation.h"
+#import "BlockExceptions.h"
+#import "CString.h"
+#import "FloatConversion.h"
+#import "FloatRect.h"
+#import "Image.h"
+#import "PlatformString.h"
+#import <QuartzCore/QuartzCore.h>
+#import "RotateTransformOperation.h"
+#import "ScaleTransformOperation.h"
+#import "SystemTime.h"
+#import "TranslateTransformOperation.h"
+#import "WebLayer.h"
+#import "WebTiledLayer.h"
+#import <wtf/CurrentTime.h>
+#import <wtf/UnusedParam.h>
+
+using namespace std;
+
+#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
+
+namespace WebCore {
+
+// The threshold width or height above which a tiled layer will be used. This should be
+// large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL
+// texture size limit on all supported hardware.
+static const int cMaxPixelDimension = 2000;
+
+// The width and height of a single tile in a tiled layer. Should be large enough to
+// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
+// to keep the overall tile cost low.
+static const int cTiledLayerTileSize = 512;
+
+// If we send a duration of 0 to CA, then it will use the default duration
+// of 250ms. So send a very small value instead.
+static const float cAnimationAlmostZeroDuration = 1e-3f;
+
+// CACurrentMediaTime() is a time since boot. These methods convert between that and
+// WebCore time, which is system time (UTC).
+static CFTimeInterval currentTimeToMediaTime(double t)
+{
+ return CACurrentMediaTime() + t - WTF::currentTime();
+}
+
+static double mediaTimeToCurrentTime(CFTimeInterval t)
+{
+ return WTF::currentTime() + t - CACurrentMediaTime();
+}
+
+} // namespace WebCore
+
+static NSString* const WebAnimationCSSPropertyKey = @"GraphicsLayerCA_property";
+
+@interface WebAnimationDelegate : NSObject {
+ WebCore::GraphicsLayerCA* m_graphicsLayer;
+}
+
+- (void)animationDidStart:(CAAnimation *)anim;
+- (WebCore::GraphicsLayerCA*)graphicsLayer;
+- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer;
+
+@end
+
+@implementation WebAnimationDelegate
+
+- (void)animationDidStart:(CAAnimation *)animation
+{
+ if (!m_graphicsLayer)
+ return;
+
+ double startTime = WebCore::mediaTimeToCurrentTime([animation beginTime]);
+ m_graphicsLayer->client()->notifyAnimationStarted(m_graphicsLayer, startTime);
+}
+
+- (WebCore::GraphicsLayerCA*)graphicsLayer
+{
+ return m_graphicsLayer;
+}
+
+- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer
+{
+ m_graphicsLayer = graphicsLayer;
+}
+
+@end
+
+namespace WebCore {
+
+static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t)
+{
+ toT3D.m11 = narrowPrecisionToFloat(t.m11());
+ toT3D.m12 = narrowPrecisionToFloat(t.m12());
+ toT3D.m13 = narrowPrecisionToFloat(t.m13());
+ toT3D.m14 = narrowPrecisionToFloat(t.m14());
+ toT3D.m21 = narrowPrecisionToFloat(t.m21());
+ toT3D.m22 = narrowPrecisionToFloat(t.m22());
+ toT3D.m23 = narrowPrecisionToFloat(t.m23());
+ toT3D.m24 = narrowPrecisionToFloat(t.m24());
+ toT3D.m31 = narrowPrecisionToFloat(t.m31());
+ toT3D.m32 = narrowPrecisionToFloat(t.m32());
+ toT3D.m33 = narrowPrecisionToFloat(t.m33());
+ toT3D.m34 = narrowPrecisionToFloat(t.m34());
+ toT3D.m41 = narrowPrecisionToFloat(t.m41());
+ toT3D.m42 = narrowPrecisionToFloat(t.m42());
+ toT3D.m43 = narrowPrecisionToFloat(t.m43());
+ toT3D.m44 = narrowPrecisionToFloat(t.m44());
+}
+
+static NSValue* getTransformFunctionValue(const GraphicsLayer::TransformValue& transformValue, size_t index, const IntSize& size, TransformOperation::OperationType transformType)
+{
+ TransformOperation* op = (index >= transformValue.value()->operations().size()) ? 0 : transformValue.value()->operations()[index].get();
+
+ switch (transformType) {
+ case TransformOperation::ROTATE:
+ case TransformOperation::ROTATE_X:
+ case TransformOperation::ROTATE_Y:
+ return [NSNumber numberWithDouble:op ? deg2rad(static_cast<RotateTransformOperation*>(op)->angle()) : 0];
+ case TransformOperation::SCALE_X:
+ return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->x() : 0];
+ case TransformOperation::SCALE_Y:
+ return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->y() : 0];
+ case TransformOperation::SCALE_Z:
+ return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->z() : 0];
+ case TransformOperation::TRANSLATE_X:
+ return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->x(size) : 0];
+ case TransformOperation::TRANSLATE_Y:
+ return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->y(size) : 0];
+ case TransformOperation::TRANSLATE_Z:
+ return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->z(size) : 0];
+ case TransformOperation::SCALE:
+ case TransformOperation::TRANSLATE:
+ case TransformOperation::SKEW_X:
+ case TransformOperation::SKEW_Y:
+ case TransformOperation::SKEW:
+ case TransformOperation::MATRIX:
+ case TransformOperation::SCALE_3D:
+ case TransformOperation::TRANSLATE_3D:
+ case TransformOperation::ROTATE_3D:
+ case TransformOperation::MATRIX_3D:
+ case TransformOperation::PERSPECTIVE:
+ case TransformOperation::IDENTITY:
+ case TransformOperation::NONE: {
+ TransformationMatrix t;
+ if (op)
+ op->apply(t, size);
+ CATransform3D cat;
+ copyTransform(cat, t);
+ return [NSValue valueWithCATransform3D:cat];
+ }
+ }
+
+ return 0;
+}
+
+#if HAVE_MODERN_QUARTZCORE
+static NSString* getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType)
+{
+ // Use literal strings to avoid link-time dependency on those symbols.
+ switch (transformType) {
+ case TransformOperation::ROTATE_X:
+ return @"rotateX"; // kCAValueFunctionRotateX;
+ case TransformOperation::ROTATE_Y:
+ return @"rotateY"; // kCAValueFunctionRotateY;
+ case TransformOperation::ROTATE:
+ return @"rotateZ"; // kCAValueFunctionRotateZ;
+ case TransformOperation::SCALE_X:
+ return @"scaleX"; // kCAValueFunctionScaleX;
+ case TransformOperation::SCALE_Y:
+ return @"scaleY"; // kCAValueFunctionScaleY;
+ case TransformOperation::SCALE_Z:
+ return @"scaleZ"; // kCAValueFunctionScaleZ;
+ case TransformOperation::TRANSLATE_X:
+ return @"translateX"; // kCAValueFunctionTranslateX;
+ case TransformOperation::TRANSLATE_Y:
+ return @"translateY"; // kCAValueFunctionTranslateY;
+ case TransformOperation::TRANSLATE_Z:
+ return @"translateZ"; // kCAValueFunctionTranslateZ;
+ default:
+ return nil;
+ }
+}
+#endif
+
+static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& timingFunction)
+{
+ switch (timingFunction.type()) {
+ case LinearTimingFunction:
+ return [CAMediaTimingFunction functionWithName:@"linear"];
+ case CubicBezierTimingFunction:
+ return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(timingFunction.x1()) :static_cast<float>(timingFunction.y1())
+ :static_cast<float>(timingFunction.x2()) :static_cast<float>(timingFunction.y2())];
+ }
+ return 0;
+}
+
+#ifndef NDEBUG
+static void setLayerBorderColor(PlatformLayer* layer, const Color& color)
+{
+ CGColorRef borderColor = createCGColor(color);
+ [layer setBorderColor:borderColor];
+ CGColorRelease(borderColor);
+}
+
+static void clearBorderColor(PlatformLayer* layer)
+{
+ [layer setBorderColor:nil];
+}
+#endif
+
+static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color)
+{
+ CGColorRef bgColor = createCGColor(color);
+ [layer setBackgroundColor:bgColor];
+ CGColorRelease(bgColor);
+}
+
+static void clearLayerBackgroundColor(PlatformLayer* layer)
+{
+ [layer setBackgroundColor:0];
+}
+
+static CALayer* getPresentationLayer(CALayer* layer)
+{
+ CALayer* presLayer = [layer presentationLayer];
+ if (!presLayer)
+ presLayer = layer;
+
+ return presLayer;
+}
+
+static bool caValueFunctionSupported()
+{
+ static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)];
+ return sHaveValueFunction;
+}
+
+static bool forceSoftwareAnimation()
+{
+ static bool forceSoftwareAnimation = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreForceSoftwareAnimation"];
+ return forceSoftwareAnimation;
+}
+
+bool GraphicsLayer::graphicsContextsFlipped()
+{
+ return true;
+}
+
+#ifndef NDEBUG
+bool GraphicsLayer::showDebugBorders()
+{
+ static bool showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"];
+ return showDebugBorders;
+}
+
+bool GraphicsLayer::showRepaintCounter()
+{
+ static bool showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"];
+ return showRepaintCounter;
+}
+#endif
+
+static NSDictionary* nullActionsDictionary()
+{
+ NSNull* nullValue = [NSNull null];
+ NSDictionary* actions = [NSDictionary dictionaryWithObjectsAndKeys:
+ nullValue, @"anchorPoint",
+ nullValue, @"bounds",
+ nullValue, @"contents",
+ nullValue, @"contentsRect",
+ nullValue, @"opacity",
+ nullValue, @"position",
+ nullValue, @"shadowColor",
+ nullValue, @"sublayerTransform",
+ nullValue, @"sublayers",
+ nullValue, @"transform",
+#ifndef NDEBUG
+ nullValue, @"zPosition",
+#endif
+ nil];
+ return actions;
+}
+
+GraphicsLayer* GraphicsLayer::createGraphicsLayer(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerCA(client);
+}
+
+GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
+: GraphicsLayer(client)
+, m_contentLayerForImageOrVideo(false)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ m_layer.adoptNS([[WebLayer alloc] init]);
+ [m_layer.get() setLayerOwner:this];
+
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+
+ m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]);
+ [m_animationDelegate.get() setLayer:this];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+GraphicsLayerCA::~GraphicsLayerCA()
+{
+ // Remove a inner layer if there is one.
+ clearContents();
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ // Clean up the WK layer.
+ if (m_layer) {
+ WebLayer* layer = m_layer.get();
+ [layer setLayerOwner:nil];
+ [layer removeFromSuperlayer];
+ }
+
+ if (m_transformLayer)
+ [m_transformLayer.get() removeFromSuperlayer];
+
+ // animationDidStart: can fire after this, so we need to clear out the layer on the delegate.
+ [m_animationDelegate.get() setLayer:0];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setName(const String& name)
+{
+ String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
+ GraphicsLayer::setName(longName);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setName:name];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+NativeLayer GraphicsLayerCA::nativeLayer() const
+{
+ return m_layer.get();
+}
+
+void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
+{
+ GraphicsLayer::addChild(childLayer);
+
+ GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+ GraphicsLayer::addChildAtIndex(childLayer, index);
+
+ GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() atIndex:index];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ // FIXME: share code with base class
+ ASSERT(childLayer != this);
+ childLayer->removeFromParent();
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i, childLayer);
+ found = true;
+ break;
+ }
+ }
+ childLayer->setParent(this);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
+ GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
+ if (found)
+ [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() below:siblingLayerCA->layerForSuperlayer()];
+ else {
+ m_children.append(childLayer);
+ [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ // FIXME: share code with base class
+ ASSERT(childLayer != this);
+ childLayer->removeFromParent();
+
+ unsigned i;
+ bool found = false;
+ for (i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i+1, childLayer);
+ found = true;
+ break;
+ }
+ }
+ childLayer->setParent(this);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
+ GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
+ if (found) {
+ [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() above:siblingLayerCA->layerForSuperlayer()];
+ } else {
+ m_children.append(childLayer);
+ [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ // FIXME: share code with base class
+ ASSERT(!newChild->parent());
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (oldChild == m_children[i]) {
+ m_children[i] = newChild;
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ oldChild->setParent(0);
+
+ newChild->removeFromParent();
+ newChild->setParent(this);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ GraphicsLayerCA* oldChildCA = static_cast<GraphicsLayerCA*>(oldChild);
+ GraphicsLayerCA* newChildCA = static_cast<GraphicsLayerCA*>(newChild);
+ [hostLayerForSublayers() replaceSublayer:oldChildCA->layerForSuperlayer() with:newChildCA->layerForSuperlayer()];
+ END_BLOCK_OBJC_EXCEPTIONS
+ return true;
+ }
+ return false;
+}
+
+void GraphicsLayerCA::removeFromParent()
+{
+ GraphicsLayer::removeFromParent();
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [layerForSuperlayer() removeFromSuperlayer];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setPosition(const FloatPoint& point)
+{
+ // Don't short-circuit here, because position and anchor point are inter-dependent.
+ GraphicsLayer::setPosition(point);
+
+ // Position is offset on the layer by the layer anchor point.
+ CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
+ m_position.y() + m_anchorPoint.y() * m_size.height());
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [primaryLayer() setPosition:posPoint];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
+{
+ // Don't short-circuit here, because position and anchor point are inter-dependent.
+ bool zChanged = (point.z() != m_anchorPoint.z());
+ GraphicsLayer::setAnchorPoint(point);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ // set the value on the layer to the new transform.
+ [primaryLayer() setAnchorPoint:FloatPoint(point.x(), point.y())];
+
+ if (zChanged) {
+#if HAVE_MODERN_QUARTZCORE
+ [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
+#endif
+ }
+
+ // Position depends on anchor point, so update it now.
+ setPosition(m_position);
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setSize(const FloatSize& size)
+{
+ GraphicsLayer::setSize(size);
+
+ CGRect rect = CGRectMake(0.0f,
+ 0.0f,
+ m_size.width(),
+ m_size.height());
+
+ CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (m_transformLayer) {
+ [m_transformLayer.get() setBounds:rect];
+
+ // the anchor of the contents layer is always at 0.5, 0.5, so the position
+ // is center-relative
+ [m_layer.get() setPosition:centerPoint];
+ }
+
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ [m_layer.get() setBounds:rect];
+
+ // Note that we don't resize m_contentsLayer. It's up the caller to do that.
+
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ // if we've changed the bounds, we need to recalculate the position
+ // of the layer, taking anchor point into account
+ setPosition(m_position);
+}
+
+void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
+{
+ GraphicsLayer::setTransform(t);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ CATransform3D transform;
+ copyTransform(transform, t);
+ [primaryLayer() setTransform:transform];
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ // Remove any old transition entries for transform.
+ removeAllAnimationsForProperty(AnimatedPropertyWebkitTransform);
+
+ // Even if we don't have a transition in the list, the layer may still have one.
+ // This happens when we are setting the final transform value after an animation or
+ // transition has ended. In removeAnimation we toss the entry from the list but don't
+ // remove it from the list. That way we aren't in danger of displaying a stale transform
+ // in the time between removing the animation and setting the new unanimated value. We
+ // can't do this in removeAnimation because we don't know the new transform value there.
+ String keyPath = propertyIdToString(AnimatedPropertyWebkitTransform);
+ CALayer* layer = animatedLayer(AnimatedPropertyWebkitTransform);
+
+ for (int i = 0; ; ++i) {
+ String animName = keyPath + "_" + String::number(i);
+ if (![layer animationForKey: animName])
+ break;
+ [layer removeAnimationForKey:animName];
+ }
+}
+
+void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
+{
+ if (t == m_childrenTransform)
+ return;
+
+ GraphicsLayer::setChildrenTransform(t);
+
+ CATransform3D transform;
+ copyTransform(transform, t);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ // Set the value on the layer to the new transform.
+ [primaryLayer() setSublayerTransform:transform];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
+{
+ String keyPath = GraphicsLayer::propertyIdToString(property);
+ for (short index = 0; ; ++index) {
+ String animName = keyPath + "_" + String::number(index);
+ CAAnimation* anim = [fromLayer animationForKey:animName];
+ if (!anim)
+ break;
+
+ [anim retain];
+ [fromLayer removeAnimationForKey:animName];
+ [toLayer addAnimation:anim forKey:animName];
+ [anim release];
+ }
+}
+
+static void moveSublayers(CALayer* fromLayer, CALayer* toLayer)
+{
+ NSArray* sublayersCopy = [[fromLayer sublayers] copy]; // Avoid mutation while enumerating, and keep the sublayers alive.
+ NSEnumerator* childrenEnumerator = [sublayersCopy objectEnumerator];
+
+ CALayer* layer;
+ while ((layer = [childrenEnumerator nextObject]) != nil) {
+ [layer removeFromSuperlayer];
+ [toLayer addSublayer:layer];
+ }
+ [sublayersCopy release];
+}
+
+void GraphicsLayerCA::setPreserves3D(bool preserves3D)
+{
+ GraphicsLayer::setPreserves3D(preserves3D);
+
+ CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ CGPoint centerPoint = CGPointMake(0.5f, 0.5f);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ Class transformLayerClass = NSClassFromString(@"CATransformLayer");
+ if (preserves3D && !m_transformLayer && transformLayerClass) {
+ // Create the transform layer.
+ m_transformLayer.adoptNS([[transformLayerClass alloc] init]);
+
+ // Turn off default animations.
+ [m_transformLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
+
+#ifndef NDEBUG
+ [m_transformLayer.get() setName:[NSString stringWithFormat:@"Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this]];
+#endif
+ // Copy the position from this layer.
+ [m_transformLayer.get() setBounds:[m_layer.get() bounds]];
+ [m_transformLayer.get() setPosition:[m_layer.get() position]];
+ [m_transformLayer.get() setAnchorPoint:[m_layer.get() anchorPoint]];
+#if HAVE_MODERN_QUARTZCORE
+ [m_transformLayer.get() setAnchorPointZ:[m_layer.get() anchorPointZ]];
+#endif
+ [m_transformLayer.get() setContentsRect:[m_layer.get() contentsRect]];
+#ifndef NDEBUG
+ [m_transformLayer.get() setZPosition:[m_layer.get() zPosition]];
+#endif
+
+ // The contents layer is positioned at (0,0) relative to the transformLayer.
+ [m_layer.get() setPosition:point];
+ [m_layer.get() setAnchorPoint:centerPoint];
+#ifndef NDEBUG
+ [m_layer.get() setZPosition:0.0f];
+#endif
+
+ // Transfer the transform over.
+ [m_transformLayer.get() setTransform:[m_layer.get() transform]];
+ [m_layer.get() setTransform:CATransform3DIdentity];
+
+ // Transfer the opacity from the old layer to the transform layer.
+ [m_transformLayer.get() setOpacity:m_opacity];
+ [m_layer.get() setOpacity:1];
+
+ // Move this layer to be a child of the transform layer.
+ [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_transformLayer.get()];
+ [m_transformLayer.get() addSublayer:m_layer.get()];
+
+ moveAnimation(AnimatedPropertyWebkitTransform, m_layer.get(), m_transformLayer.get());
+ moveSublayers(m_layer.get(), m_transformLayer.get());
+
+ } else if (!preserves3D && m_transformLayer) {
+ // Relace the transformLayer in the parent with this layer.
+ [m_layer.get() removeFromSuperlayer];
+ [[m_transformLayer.get() superlayer] replaceSublayer:m_transformLayer.get() with:m_layer.get()];
+
+ moveAnimation(AnimatedPropertyWebkitTransform, m_transformLayer.get(), m_layer.get());
+ moveSublayers(m_transformLayer.get(), m_layer.get());
+
+ // Reset the layer position and transform.
+ [m_layer.get() setPosition:[m_transformLayer.get() position]];
+ [m_layer.get() setAnchorPoint:[m_transformLayer.get() anchorPoint]];
+#if HAVE_MODERN_QUARTZCORE
+ [m_layer.get() setAnchorPointZ:[m_transformLayer.get() anchorPointZ]];
+#endif
+ [m_layer.get() setContentsRect:[m_transformLayer.get() contentsRect]];
+ [m_layer.get() setTransform:[m_transformLayer.get() transform]];
+ [m_layer.get() setOpacity:[m_transformLayer.get() opacity]];
+#ifndef NDEBUG
+ [m_layer.get() setZPosition:[m_transformLayer.get() zPosition]];
+#endif
+
+ // Release the transform layer.
+ m_transformLayer = 0;
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
+{
+ if (masksToBounds == m_masksToBounds)
+ return;
+
+ GraphicsLayer::setMasksToBounds(masksToBounds);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setMasksToBounds:masksToBounds];
+ END_BLOCK_OBJC_EXCEPTIONS
+
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+}
+
+void GraphicsLayerCA::setDrawsContent(bool drawsContent)
+{
+ if (drawsContent != m_drawsContent) {
+ GraphicsLayer::setDrawsContent(drawsContent);
+
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ // Clobber any existing content. If necessary, CA will create backing store on the next display.
+ [m_layer.get() setContents:nil];
+
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+ END_BLOCK_OBJC_EXCEPTIONS
+ }
+}
+
+void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* transition, double beginTime)
+{
+ GraphicsLayer::setBackgroundColor(color, transition, beginTime);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ setHasContentsLayer(true);
+
+ if (transition && !transition->isEmptyOrZeroDuration()) {
+ CALayer* presLayer = [m_contentsLayer.get() presentationLayer];
+ // If we don't have a presentationLayer, just use the CALayer
+ if (!presLayer)
+ presLayer = m_contentsLayer.get();
+
+ // Get the current value of the background color from the layer
+ CGColorRef fromBackgroundColor = [presLayer backgroundColor];
+
+ CGColorRef bgColor = createCGColor(color);
+ setBasicAnimation(AnimatedPropertyBackgroundColor, TransformOperation::NONE, 0, fromBackgroundColor, bgColor, true, transition, beginTime);
+ CGColorRelease(bgColor);
+ } else {
+ removeAllAnimationsForProperty(AnimatedPropertyBackgroundColor);
+ setHasContentsLayer(true);
+ setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::clearBackgroundColor()
+{
+ if (!m_contentLayerForImageOrVideo)
+ setHasContentsLayer(false);
+ else
+ clearLayerBackgroundColor(m_contentsLayer.get());
+}
+
+void GraphicsLayerCA::setContentsOpaque(bool opaque)
+{
+ GraphicsLayer::setContentsOpaque(opaque);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setOpaque:m_contentsOpaque];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setBackfaceVisibility(bool visible)
+{
+ if (m_backfaceVisibility == visible)
+ return;
+
+ GraphicsLayer::setBackfaceVisibility(visible);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setDoubleSided:visible];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+bool GraphicsLayerCA::setOpacity(float opacity, const Animation* transition, double beginTime)
+{
+ if (forceSoftwareAnimation())
+ return false;
+
+ float clampedOpacity = max(0.0f, min(opacity, 1.0f));
+
+ bool opacitiesDiffer = (m_opacity != clampedOpacity);
+
+ GraphicsLayer::setOpacity(clampedOpacity, transition, beginTime);
+
+ int animIndex = findAnimationEntry(AnimatedPropertyOpacity, 0);
+
+ // If we don't have a transition just set the opacity
+ if (!transition || transition->isEmptyOrZeroDuration()) {
+ // Three cases:
+ // 1) no existing animation or transition: just set opacity
+ // 2) existing transition: clear it and set opacity
+ // 3) existing animation: just return
+ //
+ if (animIndex < 0 || m_animations[animIndex].isTransition()) {
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [primaryLayer() setOpacity:opacity];
+ if (animIndex >= 0) {
+ removeAllAnimationsForProperty(AnimatedPropertyOpacity);
+ animIndex = -1;
+ } else {
+ String keyPath = propertyIdToString(AnimatedPropertyOpacity);
+
+ // FIXME: using hardcoded '0' here. We should be clearing all animations. For now there is only 1.
+ String animName = keyPath + "_0";
+ [animatedLayer(AnimatedPropertyOpacity) removeAnimationForKey:animName];
+ }
+ END_BLOCK_OBJC_EXCEPTIONS
+ } else {
+ // We have an animation, so don't set the opacity directly.
+ return false;
+ }
+ } else {
+ // At this point, we know we have a transition. But if it is the same and
+ // the opacity value has not changed, don't do anything.
+ if (!opacitiesDiffer &&
+ ((animIndex == -1) ||
+ (m_animations[animIndex].isTransition() && *(m_animations[animIndex].animation()) == *transition))) {
+ return false;
+ }
+ }
+
+ // If an animation is running, ignore this transition, but still save the value.
+ if (animIndex >= 0 && !m_animations[animIndex].isTransition())
+ return false;
+
+ bool didAnimate = false;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ NSNumber* fromOpacityValue = nil;
+ NSNumber* toOpacityValue = [NSNumber numberWithFloat:opacity];
+
+ if (transition && !transition->isEmptyOrZeroDuration()) {
+ CALayer* presLayer = getPresentationLayer(primaryLayer());
+ float fromOpacity = [presLayer opacity];
+ fromOpacityValue = [NSNumber numberWithFloat:fromOpacity];
+ setBasicAnimation(AnimatedPropertyOpacity, TransformOperation::NONE, 0, fromOpacityValue, toOpacityValue, true, transition, beginTime);
+ didAnimate = true;
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ return didAnimate;
+}
+
+void GraphicsLayerCA::setNeedsDisplay()
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (drawsContent())
+ [m_layer.get() setNeedsDisplay];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (drawsContent())
+ [m_layer.get() setNeedsDisplayInRect:rect];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+
+bool GraphicsLayerCA::animateTransform(const TransformValueList& valueList, const IntSize& size, const Animation* anim, double beginTime, bool isTransition)
+{
+ if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
+ return false;
+
+ TransformValueList::FunctionList functionList;
+ bool isValid, hasBigRotation;
+ valueList.makeFunctionList(functionList, isValid, hasBigRotation);
+
+ // We need to fall back to software animation if we don't have setValueFunction:, and
+ // we would need to animate each incoming transform function separately. This is the
+ // case if we have a rotation >= 180 or we have more than one transform function.
+ if ((hasBigRotation || functionList.size() > 1) && !caValueFunctionSupported())
+ return false;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ // Rules for animation:
+ //
+ // 1) If functionList is empty or we don't have a big rotation, we do a matrix animation. We could
+ // use component animation for lists without a big rotation, but there is no need to, and this
+ // is more efficient.
+ //
+ // 2) Otherwise we do a component hardware animation.
+ bool isMatrixAnimation = !isValid || !hasBigRotation;
+
+ // Set transform to identity since we are animating components and we need the base
+ // to be the identity transform.
+ TransformationMatrix t;
+ CATransform3D toT3D;
+ copyTransform(toT3D, t);
+ [primaryLayer() setTransform:toT3D];
+
+ bool isKeyframe = valueList.size() > 2;
+
+ // Iterate through the transform functions, sending an animation for each one.
+ for (int functionIndex = 0; ; ++functionIndex) {
+ if (functionIndex >= static_cast<int>(functionList.size()) && !isMatrixAnimation)
+ break;
+
+ TransformOperation::OperationType opType = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[functionIndex];
+
+ if (isKeyframe) {
+ NSMutableArray* timesArray = [[NSMutableArray alloc] init];
+ NSMutableArray* valArray = [[NSMutableArray alloc] init];
+ NSMutableArray* tfArray = [[NSMutableArray alloc] init];
+
+ // Iterate through the keyframes, building arrays for the animation.
+ for (Vector<TransformValue>::const_iterator it = valueList.values().begin(); it != valueList.values().end(); ++it) {
+ const TransformValue& curValue = (*it);
+
+ // fill in the key time and timing function
+ [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
+
+ const TimingFunction* tf = 0;
+ if (curValue.timingFunction())
+ tf = curValue.timingFunction();
+ else if (anim->isTimingFunctionSet())
+ tf = &anim->timingFunction();
+
+ CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction(LinearTimingFunction));
+ [tfArray addObject:timingFunction];
+
+ // fill in the function
+ if (isMatrixAnimation) {
+ TransformationMatrix t;
+ curValue.value()->apply(size, t);
+ CATransform3D cat;
+ copyTransform(cat, t);
+ [valArray addObject:[NSValue valueWithCATransform3D:cat]];
+ } else
+ [valArray addObject:getTransformFunctionValue(curValue, functionIndex, size, opType)];
+ }
+
+ // We toss the last tfArray value because it has to one shorter than the others.
+ [tfArray removeLastObject];
+
+ setKeyframeAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, timesArray, valArray, tfArray, isTransition, anim, beginTime);
+
+ [timesArray release];
+ [valArray release];
+ [tfArray release];
+ } else {
+ // Is a transition
+ id fromValue, toValue;
+
+ if (isMatrixAnimation) {
+ TransformationMatrix fromt, tot;
+ valueList.at(0).value()->apply(size, fromt);
+ valueList.at(1).value()->apply(size, tot);
+
+ CATransform3D cat;
+ copyTransform(cat, fromt);
+ fromValue = [NSValue valueWithCATransform3D:cat];
+ copyTransform(cat, tot);
+ toValue = [NSValue valueWithCATransform3D:cat];
+ } else {
+ fromValue = getTransformFunctionValue(valueList.at(0), functionIndex, size, opType);
+ toValue = getTransformFunctionValue(valueList.at(1), functionIndex, size, opType);
+ }
+
+ setBasicAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, fromValue, toValue, isTransition, anim, beginTime);
+ }
+
+ if (isMatrixAnimation)
+ break;
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+ return true;
+}
+
+bool GraphicsLayerCA::animateFloat(AnimatedPropertyID property, const FloatValueList& valueList, const Animation* animation, double beginTime)
+{
+ if (forceSoftwareAnimation() || valueList.size() < 2)
+ return false;
+
+ // if there is already is an animation for this property and it hasn't changed, ignore it.
+ int i = findAnimationEntry(property, 0);
+ if (i >= 0 && *m_animations[i].animation() == *animation) {
+ m_animations[i].setIsCurrent();
+ return false;
+ }
+
+ if (valueList.size() == 2) {
+ float fromVal = valueList.at(0).value();
+ float toVal = valueList.at(1).value();
+ if (isnan(toVal) && isnan(fromVal))
+ return false;
+
+ // initialize the property to 0
+ [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
+ setBasicAnimation(property, TransformOperation::NONE, 0, isnan(fromVal) ? nil : [NSNumber numberWithFloat:fromVal], isnan(toVal) ? nil : [NSNumber numberWithFloat:toVal], false, animation, beginTime);
+ return true;
+ }
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ NSMutableArray* timesArray = [[NSMutableArray alloc] init];
+ NSMutableArray* valArray = [[NSMutableArray alloc] init];
+ NSMutableArray* tfArray = [[NSMutableArray alloc] init];
+
+ for (unsigned i = 0; i < valueList.values().size(); ++i) {
+ const FloatValue& curValue = valueList.values()[i];
+ [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
+ [valArray addObject:[NSNumber numberWithFloat:curValue.value()]];
+
+ const TimingFunction* tf = 0;
+ if (curValue.timingFunction())
+ tf = curValue.timingFunction();
+ else if (animation->isTimingFunctionSet())
+ tf = &animation->timingFunction();
+
+ CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
+ [tfArray addObject:timingFunction];
+ }
+
+ // We toss the last tfArray value because it has to one shorter than the others.
+ [tfArray removeLastObject];
+
+ // Initialize the property to 0.
+ [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
+ // Then set the animation.
+ setKeyframeAnimation(property, TransformOperation::NONE, 0, timesArray, valArray, tfArray, false, animation, beginTime);
+
+ [timesArray release];
+ [valArray release];
+ [tfArray release];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+ return true;
+}
+
+void GraphicsLayerCA::setContentsToImage(Image* image)
+{
+ if (image) {
+ setHasContentsLayer(true);
+
+ // FIXME: is image flipping really a property of the graphics context?
+ bool needToFlip = GraphicsLayer::graphicsContextsFlipped();
+ CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ {
+ CGImageRef theImage = image->nativeImageForCurrentFrame();
+ // FIXME: maybe only do trilinear if the image is being scaled down,
+ // but then what if the layer size changes?
+#if HAVE_MODERN_QUARTZCORE
+ [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear];
+#endif
+ if (needToFlip) {
+ CATransform3D flipper = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f};
+ [m_contentsLayer.get() setTransform:flipper];
+ }
+
+ [m_contentsLayer.get() setAnchorPoint:anchorPoint];
+ [m_contentsLayer.get() setContents:(id)theImage];
+ }
+ END_BLOCK_OBJC_EXCEPTIONS
+ } else
+ setHasContentsLayer(false);
+
+ m_contentLayerForImageOrVideo = (image != 0);
+}
+
+void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer)
+{
+ setContentsLayer(videoLayer);
+ m_contentLayerForImageOrVideo = (videoLayer != 0);
+}
+
+void GraphicsLayerCA::clearContents()
+{
+ if (m_contentLayerForImageOrVideo) {
+ setHasContentsLayer(false);
+ m_contentLayerForImageOrVideo = false;
+ }
+}
+
+void GraphicsLayerCA::updateContentsRect()
+{
+ if (m_client && m_contentsLayer) {
+ IntRect contentRect = m_client->contentsBox(this);
+
+ CGPoint point = CGPointMake(contentRect.x(),
+ contentRect.y());
+ CGRect rect = CGRectMake(0.0f,
+ 0.0f,
+ contentRect.width(),
+ contentRect.height());
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_contentsLayer.get() setPosition:point];
+ [m_contentsLayer.get() setBounds:rect];
+ END_BLOCK_OBJC_EXCEPTIONS
+ }
+}
+
+void GraphicsLayerCA::setBasicAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation* transition, double beginTime)
+{
+ ASSERT(fromVal || toVal);
+
+ WebLayer* layer = animatedLayer(property);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ // add an entry for this animation
+ addAnimationEntry(property, index, isTransition, transition);
+
+ String keyPath = propertyIdToString(property);
+ String animName = keyPath + "_" + String::number(index);
+
+ CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:keyPath];
+
+ double duration = transition->duration();
+ if (duration <= 0)
+ duration = cAnimationAlmostZeroDuration;
+
+ float repeatCount = transition->iterationCount();
+ if (repeatCount == Animation::IterationCountInfinite)
+ repeatCount = FLT_MAX;
+ else if (transition->direction() == Animation::AnimationDirectionAlternate)
+ repeatCount /= 2;
+
+ [basicAnim setDuration:duration];
+ [basicAnim setRepeatCount:repeatCount];
+ [basicAnim setAutoreverses:transition->direction()];
+ [basicAnim setRemovedOnCompletion:NO];
+
+ // Note that currently transform is the only property which has animations
+ // with an index > 0.
+ [basicAnim setAdditive:property == AnimatedPropertyWebkitTransform];
+ [basicAnim setFillMode:@"extended"];
+#if HAVE_MODERN_QUARTZCORE
+ if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType))
+ [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
+#else
+ UNUSED_PARAM(operationType);
+#endif
+
+ // Set the delegate (and property value).
+ int prop = isTransition ? property : AnimatedPropertyInvalid;
+ [basicAnim setValue:[NSNumber numberWithInt:prop] forKey:WebAnimationCSSPropertyKey];
+ [basicAnim setDelegate:m_animationDelegate.get()];
+
+ NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
+ [basicAnim setBeginTime:bt];
+
+ if (fromVal)
+ [basicAnim setFromValue:reinterpret_cast<id>(fromVal)];
+ if (toVal)
+ [basicAnim setToValue:reinterpret_cast<id>(toVal)];
+
+ const TimingFunction* tf = 0;
+ if (transition->isTimingFunctionSet())
+ tf = &transition->timingFunction();
+
+ CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
+ [basicAnim setTimingFunction:timingFunction];
+
+ // Send over the animation.
+ [layer removeAnimationForKey:animName];
+ [layer addAnimation:basicAnim forKey:animName];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setKeyframeAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* keys, void* values, void* timingFunctions,
+ bool isTransition, const Animation* anim, double beginTime)
+{
+ PlatformLayer* layer = animatedLayer(property);
+
+ // Add an entry for this animation (which may change beginTime).
+ addAnimationEntry(property, index, isTransition, anim);
+
+ String keyPath = propertyIdToString(property);
+ String animName = keyPath + "_" + String::number(index);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:keyPath];
+
+ double duration = anim->duration();
+ if (duration <= 0)
+ duration = cAnimationAlmostZeroDuration;
+
+ float repeatCount = anim->iterationCount();
+ if (repeatCount == Animation::IterationCountInfinite)
+ repeatCount = FLT_MAX;
+ else if (anim->direction() == Animation::AnimationDirectionAlternate)
+ repeatCount /= 2;
+
+ [keyframeAnim setDuration:duration];
+ [keyframeAnim setRepeatCount:repeatCount];
+ [keyframeAnim setAutoreverses:anim->direction()];
+ [keyframeAnim setRemovedOnCompletion:NO];
+
+ // The first animation is non-additive, all the rest are additive.
+ // Note that currently transform is the only property which has animations
+ // with an index > 0.
+ [keyframeAnim setAdditive:(property == AnimatedPropertyWebkitTransform) ? YES : NO];
+ [keyframeAnim setFillMode:@"extended"];
+#if HAVE_MODERN_QUARTZCORE
+ if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType))
+ [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
+#else
+ UNUSED_PARAM(operationType);
+#endif
+
+ [keyframeAnim setKeyTimes:reinterpret_cast<id>(keys)];
+ [keyframeAnim setValues:reinterpret_cast<id>(values)];
+
+ // Set the delegate (and property value).
+ int prop = isTransition ? property : AnimatedPropertyInvalid;
+ [keyframeAnim setValue:[NSNumber numberWithInt: prop] forKey:WebAnimationCSSPropertyKey];
+ [keyframeAnim setDelegate:m_animationDelegate.get()];
+
+ NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
+ [keyframeAnim setBeginTime:bt];
+
+ // Set the timing functions, if any.
+ if (timingFunctions != nil)
+ [keyframeAnim setTimingFunctions:(id)timingFunctions];
+
+ // Send over the animation.
+ [layer removeAnimationForKey:animName];
+ [layer addAnimation:keyframeAnim forKey:animName];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::suspendAnimations()
+{
+ double t = currentTimeToMediaTime(currentTime());
+ [primaryLayer() setSpeed:0];
+ [primaryLayer() setTimeOffset:t];
+}
+
+void GraphicsLayerCA::resumeAnimations()
+{
+ [primaryLayer() setSpeed:1];
+ [primaryLayer() setTimeOffset:0];
+}
+
+void GraphicsLayerCA::removeAnimation(int index, bool reset)
+{
+ ASSERT(index >= 0);
+
+ AnimatedPropertyID property = m_animations[index].property();
+
+ // Set the value of the property and remove the animation.
+ String keyPath = propertyIdToString(property);
+ String animName = keyPath + "_" + String::number(m_animations[index].index());
+ CALayer* layer = animatedLayer(property);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ // If we are not resetting, it means we are pausing. So we need to get the current presentation
+ // value into the property before we remove the animation.
+ if (!reset) {
+ // Put the current value into the property.
+ CALayer* presLayer = [layer presentationLayer];
+ if (presLayer)
+ [layer setValue:[presLayer valueForKeyPath:keyPath] forKeyPath:keyPath];
+
+ // Make sure the saved values accurately reflect the value in the layer.
+ id val = [layer valueForKeyPath:keyPath];
+ switch (property) {
+ case AnimatedPropertyWebkitTransform:
+ // FIXME: needs comment explaining why the m_transform is not obtained from the layer
+ break;
+ case AnimatedPropertyBackgroundColor:
+ m_backgroundColor = Color(reinterpret_cast<CGColorRef>(val));
+ break;
+ case AnimatedPropertyOpacity:
+ m_opacity = [val floatValue];
+ break;
+ case AnimatedPropertyInvalid:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ // If we have reached the end of an animation, we don't want to actually remove the
+ // animation from the CALayer. At some point we will be setting the property to its
+ // unanimated value and at that point we will remove the animation. That will avoid
+ // any flashing between the time the animation is removed and the property is set.
+ if (!reset || m_animations[index].isTransition())
+ [layer removeAnimationForKey:animName];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ // Remove the animation entry.
+ m_animations.remove(index);
+}
+
+PlatformLayer* GraphicsLayerCA::hostLayerForSublayers() const
+{
+ return m_transformLayer ? m_transformLayer.get() : m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerCA::layerForSuperlayer() const
+{
+ if (m_transformLayer)
+ return m_transformLayer.get();
+
+ return m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerCA::platformLayer() const
+{
+ return primaryLayer();
+}
+
+#ifndef NDEBUG
+void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (color.isValid())
+ setLayerBackgroundColor(m_layer.get(), color);
+ else
+ clearLayerBackgroundColor(m_layer.get());
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (color.isValid()) {
+ setLayerBorderColor(m_layer.get(), color);
+ [m_layer.get() setBorderWidth:borderWidth];
+ } else {
+ clearBorderColor(m_layer.get());
+ [m_layer.get() setBorderWidth:0];
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setZPosition(float position)
+{
+ GraphicsLayer::setZPosition(position);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [primaryLayer() setZPosition:position];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+#endif
+
+bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
+{
+ if (!m_drawsContent)
+ return false;
+
+ // FIXME: catch zero-size height or width here (or earlier)?
+ return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension;
+}
+
+void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer)
+{
+ if (userTiledLayer == m_usingTiledLayer)
+ return;
+
+ CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ RetainPtr<CALayer> oldLayer = m_layer.get();
+
+ Class layerClass = userTiledLayer ? [WebTiledLayer self] : [WebLayer self];
+ m_layer.adoptNS([[layerClass alloc] init]);
+
+ if (userTiledLayer) {
+ WebTiledLayer* tiledLayer = (WebTiledLayer*)m_layer.get();
+ [tiledLayer setTileSize:tileSize];
+ [tiledLayer setLevelsOfDetail:1];
+ [tiledLayer setLevelsOfDetailBias:0];
+
+ if (GraphicsLayer::graphicsContextsFlipped())
+ [tiledLayer setContentsGravity:@"bottomLeft"];
+ else
+ [tiledLayer setContentsGravity:@"topLeft"];
+ }
+
+ [m_layer.get() setLayerOwner:this];
+ [m_layer.get() setSublayers:[oldLayer.get() sublayers]];
+
+ [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()];
+
+ [m_layer.get() setBounds:[oldLayer.get() bounds]];
+ [m_layer.get() setPosition:[oldLayer.get() position]];
+ [m_layer.get() setAnchorPoint:[oldLayer.get() anchorPoint]];
+ [m_layer.get() setOpaque:[oldLayer.get() isOpaque]];
+ [m_layer.get() setOpacity:[oldLayer.get() opacity]];
+ [m_layer.get() setTransform:[oldLayer.get() transform]];
+ [m_layer.get() setSublayerTransform:[oldLayer.get() sublayerTransform]];
+ [m_layer.get() setDoubleSided:[oldLayer.get() isDoubleSided]];
+#ifndef NDEBUG
+ [m_layer.get() setZPosition:[oldLayer.get() zPosition]];
+#endif
+
+#ifndef NDEBUG
+ String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name;
+ [m_layer.get() setName:name];
+#endif
+
+ // move over animations
+ moveAnimation(AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get());
+ moveAnimation(AnimatedPropertyOpacity, oldLayer.get(), m_layer.get());
+ moveAnimation(AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get());
+
+ // need to tell new layer to draw itself
+ setNeedsDisplay();
+
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ m_usingTiledLayer = userTiledLayer;
+
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+}
+
+void GraphicsLayerCA::setHasContentsLayer(bool hasLayer)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (hasLayer && !m_contentsLayer) {
+ // create the inner layer
+ WebLayer* contentsLayer = [WebLayer layer];
+#ifndef NDEBUG
+ [contentsLayer setName:@"Contents Layer"];
+#endif
+ setContentsLayer(contentsLayer);
+
+ } else if (!hasLayer && m_contentsLayer)
+ setContentsLayer(0);
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer)
+{
+ if (contentsLayer == m_contentsLayer)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (m_contentsLayer) {
+ [m_contentsLayer.get() removeFromSuperlayer];
+ m_contentsLayer = 0;
+ }
+
+ if (contentsLayer) {
+ // Turn off implicit animations on the inner layer.
+ [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
+
+ m_contentsLayer.adoptNS([contentsLayer retain]);
+ [m_contentsLayer.get() setAnchorPoint:CGPointZero];
+ [m_layer.get() addSublayer:m_contentsLayer.get()];
+
+ updateContentsRect();
+
+ // Set contents to nil if the layer does not draw its own content.
+ if (m_client && !drawsContent())
+ [m_layer.get() setContents:nil];
+
+#ifndef NDEBUG
+ if (showDebugBorders()) {
+ setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180));
+ [m_contentsLayer.get() setBorderWidth:1.0f];
+ }
+#endif
+ }
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+} // namespace WebCore
+
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
index 3f18ab4..677c31a 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,7 +28,7 @@
#if ENABLE(VIDEO)
-#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
#include "Timer.h"
#include <wtf/RetainPtr.h>
@@ -52,11 +52,28 @@ class WebCoreMovieObserver;
namespace WebCore {
-class MediaPlayerPrivate : Noncopyable {
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
public:
- MediaPlayerPrivate(MediaPlayer*);
+ static void registerMediaEngine(MediaEngineRegistrar);
+
~MediaPlayerPrivate();
-
+
+ void repaint();
+ void loadStateChanged();
+ void rateChanged();
+ void sizeChanged();
+ void timeChanged();
+ void didEnd();
+
+private:
+ MediaPlayerPrivate(MediaPlayer*);
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
IntSize naturalSize() const;
bool hasVideo() const;
@@ -72,11 +89,12 @@ public:
float duration() const;
float currentTime() const;
void seek(float time);
- void setEndTime(float time);
void setRate(float);
void setVolume(float);
-
+
+ void setEndTime(float time);
+
int dataRate() const;
MediaPlayer::NetworkState networkState() const { return m_networkState; }
@@ -89,21 +107,10 @@ public:
unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect& r);
-
- void loadStateChanged();
- void rateChanged();
- void sizeChanged();
- void timeChanged();
- void didEnd();
+ void setSize(const IntSize&);
- void repaint();
void paint(GraphicsContext*, const IntRect&);
-
- static void getSupportedTypes(HashSet<String>& types);
- static bool isAvailable();
-
-private:
+
void createQTMovie(const String& url);
void setUpVideoRendering();
void tearDownVideoRendering();
@@ -117,10 +124,10 @@ private:
void doSeek();
void cancelSeek();
void seekTimerFired(Timer<MediaPlayerPrivate>*);
- void endPointTimerFired(Timer<MediaPlayerPrivate>*);
float maxTimeLoaded() const;
- void startEndPointTimerIfNeeded();
- void disableUnsupportedTracks(unsigned& enabledTrackCount);
+ void disableUnsupportedTracks();
+
+ bool metaDataAvailable() const { return m_qtMovie && m_readyState >= MediaPlayer::HaveMetadata; }
MediaPlayer* m_player;
RetainPtr<QTMovie> m_qtMovie;
@@ -128,14 +135,15 @@ private:
RetainPtr<QTVideoRendererWebKitOnly> m_qtVideoRenderer;
RetainPtr<WebCoreMovieObserver> m_objcObserver;
float m_seekTo;
- float m_endTime;
Timer<MediaPlayerPrivate> m_seekTimer;
- Timer<MediaPlayerPrivate> m_endPointTimer;
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
bool m_startedPlaying;
bool m_isStreaming;
bool m_visible;
+ IntRect m_rect;
+ unsigned m_enabledTrackCount;
+ float m_duration;
#if DRAW_FRAME_RATE
int m_frameCountWhilePlaying;
double m_timeStartedPlaying;
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
index a33c8d2..74a9ff9 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -69,6 +69,7 @@ SOFT_LINK_CLASS(QTKit, QTMovieView)
SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *)
SOFT_LINK_POINTER(QTKit, QTMediaTypeBase, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeMPEG, NSString *)
SOFT_LINK_POINTER(QTKit, QTMediaTypeSound, NSString *)
SOFT_LINK_POINTER(QTKit, QTMediaTypeText, NSString *)
SOFT_LINK_POINTER(QTKit, QTMediaTypeVideo, NSString *)
@@ -95,6 +96,7 @@ SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification,
#define QTMediaTypeAttribute getQTMediaTypeAttribute()
#define QTMediaTypeBase getQTMediaTypeBase()
+#define QTMediaTypeMPEG getQTMediaTypeMPEG()
#define QTMediaTypeSound getQTMediaTypeSound()
#define QTMediaTypeText getQTMediaTypeText()
#define QTMediaTypeVideo getQTMediaTypeVideo()
@@ -155,24 +157,35 @@ using namespace std;
namespace WebCore {
-static const float endPointTimerInterval = 0.020f;
-
#ifdef BUILDING_ON_TIGER
static const long minimumQuickTimeVersion = 0x07300000; // 7.3
#endif
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_objcObserver(AdoptNS, [[WebCoreMovieObserver alloc] initWithCallback:this])
, m_seekTo(-1)
- , m_endTime(numeric_limits<float>::infinity())
, m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
- , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired)
, m_networkState(MediaPlayer::Empty)
- , m_readyState(MediaPlayer::DataUnavailable)
+ , m_readyState(MediaPlayer::HaveNothing)
, m_startedPlaying(false)
, m_isStreaming(false)
, m_visible(false)
+ , m_rect()
+ , m_enabledTrackCount(0)
+ , m_duration(-1.0f)
#if DRAW_FRAME_RATE
, m_frameCountWhilePlaying(0)
, m_timeStartedPlaying(0)
@@ -270,7 +283,7 @@ void MediaPlayerPrivate::createQTMovieView()
detachQTMovieView();
static bool addedCustomMethods = false;
- if (!addedCustomMethods) {
+ if (!m_player->inMediaDocument() && !addedCustomMethods) {
Class QTMovieContentViewClass = NSClassFromString(@"QTMovieContentView");
ASSERT(QTMovieContentViewClass);
@@ -281,9 +294,12 @@ void MediaPlayerPrivate::createQTMovieView()
addedCustomMethods = true;
}
+ // delay callbacks as we *will* get notifications during setup
+ [m_objcObserver.get() setDelayCallbacks:YES];
+
m_qtMovieView.adoptNS([[QTMovieView alloc] init]);
- setRect(m_player->rect());
- NSView* parentView = m_player->m_frameView->documentView();
+ setSize(m_player->size());
+ NSView* parentView = m_player->frameView()->documentView();
[parentView addSubview:m_qtMovieView.get()];
#ifdef BUILDING_ON_TIGER
// setDelegate: isn't a public call in Tiger, so use performSelector to keep the compiler happy
@@ -303,6 +319,8 @@ void MediaPlayerPrivate::createQTMovieView()
// Note that we expect mainThreadSetNeedsDisplay to be invoked only when synchronous drawing is requested.
if (!m_player->inMediaDocument())
wkQTMovieViewSetDrawSynchronously(m_qtMovieView.get(), YES);
+
+ [m_objcObserver.get() setDelayCallbacks:NO];
}
void MediaPlayerPrivate::detachQTMovieView()
@@ -356,7 +374,7 @@ void MediaPlayerPrivate::destroyQTVideoRenderer()
void MediaPlayerPrivate::setUpVideoRendering()
{
- if (!m_player->m_frameView || !m_qtMovie)
+ if (!m_player->frameView() || !m_qtMovie)
return;
if (m_player->inMediaDocument() || !QTVideoRendererClass() )
@@ -375,7 +393,7 @@ void MediaPlayerPrivate::tearDownVideoRendering()
QTTime MediaPlayerPrivate::createQTTime(float time) const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return QTMakeTime(0, 600);
long timeScale = [[m_qtMovie.get() attributeForKey:QTMovieTimeScaleAttribute] longValue];
return QTMakeTime(time * timeScale, timeScale);
@@ -387,12 +405,11 @@ void MediaPlayerPrivate::load(const String& url)
m_networkState = MediaPlayer::Loading;
m_player->networkStateChanged();
}
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
cancelSeek();
- m_endPointTimer.stop();
[m_objcObserver.get() setDelayCallbacks:YES];
@@ -404,7 +421,7 @@ void MediaPlayerPrivate::load(const String& url)
void MediaPlayerPrivate::play()
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
m_startedPlaying = true;
#if DRAW_FRAME_RATE
@@ -413,12 +430,11 @@ void MediaPlayerPrivate::play()
[m_objcObserver.get() setDelayCallbacks:YES];
[m_qtMovie.get() setRate:m_player->rate()];
[m_objcObserver.get() setDelayCallbacks:NO];
- startEndPointTimerIfNeeded();
}
void MediaPlayerPrivate::pause()
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
m_startedPlaying = false;
#if DRAW_FRAME_RATE
@@ -427,12 +443,11 @@ void MediaPlayerPrivate::pause()
[m_objcObserver.get() setDelayCallbacks:YES];
[m_qtMovie.get() stop];
[m_objcObserver.get() setDelayCallbacks:NO];
- m_endPointTimer.stop();
}
float MediaPlayerPrivate::duration() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
QTTime time = [m_qtMovie.get() duration];
if (time.flags == kQTTimeIsIndefinite)
@@ -442,22 +457,22 @@ float MediaPlayerPrivate::duration() const
float MediaPlayerPrivate::currentTime() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
QTTime time = [m_qtMovie.get() currentTime];
- return min(static_cast<float>(time.timeValue) / time.timeScale, m_endTime);
+ return static_cast<float>(time.timeValue) / time.timeScale;
}
void MediaPlayerPrivate::seek(float time)
{
cancelSeek();
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
if (time > duration())
time = duration();
-
+
m_seekTo = time;
if (maxTimeLoaded() >= m_seekTo)
doSeek();
@@ -475,7 +490,7 @@ void MediaPlayerPrivate::doSeek()
[m_qtMovie.get() setCurrentTime:qttime];
float timeAfterSeek = currentTime();
// restore playback only if not at end, othewise QTMovie will loop
- if (timeAfterSeek < duration() && timeAfterSeek < m_endTime)
+ if (oldRate && timeAfterSeek < duration())
[m_qtMovie.get() setRate:oldRate];
cancelSeek();
[m_objcObserver.get() setDelayCallbacks:NO];
@@ -489,7 +504,7 @@ void MediaPlayerPrivate::cancelSeek()
void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
{
- if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) {
+ if (!metaDataAvailable()|| !seeking() || currentTime() == m_seekTo) {
cancelSeek();
updateStates();
m_player->timeChanged();
@@ -508,67 +523,48 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
}
}
-void MediaPlayerPrivate::setEndTime(float time)
+void MediaPlayerPrivate::setEndTime(float)
{
- m_endTime = time;
- startEndPointTimerIfNeeded();
-}
-
-void MediaPlayerPrivate::startEndPointTimerIfNeeded()
-{
- if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive())
- m_endPointTimer.startRepeating(endPointTimerInterval);
-}
-
-void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
-{
- float time = currentTime();
-
- // just do end for now
- if (time >= m_endTime) {
- pause();
- didEnd();
- }
}
bool MediaPlayerPrivate::paused() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return true;
return [m_qtMovie.get() rate] == 0;
}
bool MediaPlayerPrivate::seeking() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return false;
return m_seekTo >= 0;
}
IntSize MediaPlayerPrivate::naturalSize() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return IntSize();
return IntSize([[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]);
}
bool MediaPlayerPrivate::hasVideo() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return false;
return [[m_qtMovie.get() attributeForKey:QTMovieHasVideoAttribute] boolValue];
}
void MediaPlayerPrivate::setVolume(float volume)
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
[m_qtMovie.get() setVolume:volume];
}
void MediaPlayerPrivate::setRate(float rate)
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
if (!paused())
[m_qtMovie.get() setRate:rate];
@@ -576,7 +572,7 @@ void MediaPlayerPrivate::setRate(float rate)
int MediaPlayerPrivate::dataRate() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
return wkQTMovieDataRate(m_qtMovie.get());
}
@@ -596,7 +592,7 @@ float MediaPlayerPrivate::maxTimeSeekable() const
float MediaPlayerPrivate::maxTimeLoaded() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
return wkQTMovieMaxTimeLoaded(m_qtMovie.get());
}
@@ -616,7 +612,7 @@ bool MediaPlayerPrivate::totalBytesKnown() const
unsigned MediaPlayerPrivate::totalBytes() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
return [[m_qtMovie.get() attributeForKey:QTMovieDataSizeAttribute] intValue];
}
@@ -639,52 +635,66 @@ void MediaPlayerPrivate::updateStates()
MediaPlayer::ReadyState oldReadyState = m_readyState;
long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError);
-
- if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData && !m_player->inMediaDocument()) {
- unsigned enabledTrackCount;
- disableUnsupportedTracks(enabledTrackCount);
- // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692>
- if (!enabledTrackCount)
+
+ if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata && !m_player->inMediaDocument()) {
+ disableUnsupportedTracks();
+ if (!m_enabledTrackCount)
loadState = QTMovieLoadStateError;
}
- // "Loaded" is reserved for fully buffered movies, never the case when streaming
if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
- if (m_networkState < MediaPlayer::Loaded)
- m_networkState = MediaPlayer::Loaded;
- m_readyState = MediaPlayer::CanPlayThrough;
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (loadState >= QTMovieLoadStatePlaythroughOK) {
- if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
- m_networkState = MediaPlayer::LoadedFirstFrame;
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveFutureData;
+ m_networkState = MediaPlayer::Loading;
} else if (loadState >= QTMovieLoadStatePlayable) {
- if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
- m_networkState = MediaPlayer::LoadedFirstFrame;
// FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
- m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable;
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+ m_networkState = MediaPlayer::Loading;
} else if (loadState >= QTMovieLoadStateLoaded) {
- if (m_networkState < MediaPlayer::LoadedMetaData)
- m_networkState = MediaPlayer::LoadedMetaData;
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveMetadata;
+ m_networkState = MediaPlayer::Loading;
} else if (loadState > QTMovieLoadStateError) {
- if (m_networkState < MediaPlayer::Loading)
- m_networkState = MediaPlayer::Loading;
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveNothing;
+ m_networkState = MediaPlayer::Loading;
} else {
- m_networkState = MediaPlayer::LoadFailed;
- m_readyState = MediaPlayer::DataUnavailable;
+ float loaded = maxTimeLoaded();
+
+ if (!loaded)
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (!m_enabledTrackCount)
+ m_networkState = MediaPlayer::FormatError;
+ else {
+ // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
+ if (loaded > 0)
+ m_networkState = MediaPlayer::DecodeError;
+ else
+ m_readyState = MediaPlayer::HaveNothing;
+ }
}
if (seeking())
- m_readyState = MediaPlayer::DataUnavailable;
-
+ m_readyState = MediaPlayer::HaveNothing;
+
if (m_networkState != oldNetworkState)
m_player->networkStateChanged();
if (m_readyState != oldReadyState)
m_player->readyStateChanged();
- if (loadState >= QTMovieLoadStateLoaded && oldNetworkState < MediaPlayer::LoadedMetaData && m_player->visible())
+ if (loadState >= QTMovieLoadStateLoaded && oldReadyState < MediaPlayer::HaveMetadata && m_player->visible())
setUpVideoRendering();
+
+ if (loadState >= QTMovieLoadStateLoaded) {
+ float dur = duration();
+ if (dur != m_duration) {
+ if (m_duration != -1.0f)
+ m_player->durationChanged();
+ m_duration = dur;
+ }
+ }
}
void MediaPlayerPrivate::loadStateChanged()
@@ -695,10 +705,12 @@ void MediaPlayerPrivate::loadStateChanged()
void MediaPlayerPrivate::rateChanged()
{
updateStates();
+ m_player->rateChanged();
}
void MediaPlayerPrivate::sizeChanged()
{
+ m_player->sizeChanged();
}
void MediaPlayerPrivate::timeChanged()
@@ -709,7 +721,6 @@ void MediaPlayerPrivate::timeChanged()
void MediaPlayerPrivate::didEnd()
{
- m_endPointTimer.stop();
m_startedPlaying = false;
#if DRAW_FRAME_RATE
m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate];
@@ -718,18 +729,19 @@ void MediaPlayerPrivate::didEnd()
m_player->timeChanged();
}
-void MediaPlayerPrivate::setRect(const IntRect& r)
+void MediaPlayerPrivate::setSize(const IntSize& size)
{
if (!m_qtMovieView)
return;
+ m_rect.setSize(size);
if (m_player->inMediaDocument())
// We need the QTMovieView to be placed in the proper location for document mode.
- [m_qtMovieView.get() setFrame:r];
+ [m_qtMovieView.get() setFrame:m_rect];
else {
// We don't really need the QTMovieView in any specific location so let's just get it out of the way
// where it won't intercept events or try to bring up the context menu.
- IntRect farAwayButCorrectSize(r);
+ IntRect farAwayButCorrectSize(m_rect);
farAwayButCorrectSize.move(-1000000, -1000000);
[m_qtMovieView.get() setFrame:farAwayButCorrectSize];
}
@@ -740,7 +752,7 @@ void MediaPlayerPrivate::setVisible(bool b)
if (m_visible != b) {
m_visible = b;
if (b) {
- if (m_networkState >= MediaPlayer::LoadedMetaData)
+ if (m_readyState >= MediaPlayer::HaveMetadata)
setUpVideoRendering();
} else
tearDownVideoRendering();
@@ -789,13 +801,19 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
[NSGraphicsContext setCurrentContext:newContext];
[(id<WebKitVideoRenderingDetails>)qtVideoRenderer drawInRect:paintRect];
[NSGraphicsContext restoreGraphicsState];
- } else
+ } else {
+ if (m_player->inMediaDocument() && r != m_rect) {
+ // the QTMovieView needs to be placed in the proper location for document mode
+ m_rect = r;
+ [view setFrame:m_rect];
+ }
[view displayRectIgnoringOpacity:paintRect inContext:newContext];
+ }
#if DRAW_FRAME_RATE
// Draw the frame rate only after having played more than 10 frames.
if (m_frameCountWhilePlaying > 10) {
- Frame* frame = m_player->m_frameView ? m_player->m_frameView->frame() : NULL;
+ Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : NULL;
Document* document = frame ? frame->document() : NULL;
RenderObject* renderer = document ? document->renderer() : NULL;
RenderStyle* styleToUse = renderer ? renderer->style() : NULL;
@@ -821,22 +839,42 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
[m_objcObserver.get() setDelayCallbacks:NO];
}
-void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+static HashSet<String> mimeTypeCache()
{
- NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes];
- int count = [fileTypes count];
- for (int n = 0; n < count; n++) {
- CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]);
- RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL));
- if (!uti)
- continue;
- RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType));
- if (!mime)
- continue;
- types.add(mime.get());
+ DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes];
+ int count = [fileTypes count];
+ for (int n = 0; n < count; n++) {
+ CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]);
+ RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL));
+ if (!uti)
+ continue;
+ RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType));
+ if (!mime)
+ continue;
+ cache.add(mime.get());
+ }
+ typeListInitialized = true;
}
-}
+ return cache;
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+{
+ types = mimeTypeCache();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
+ // extended MIME type yet
+ return mimeTypeCache().contains(type) ? (codecs && !codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
bool MediaPlayerPrivate::isAvailable()
{
#ifdef BUILDING_ON_TIGER
@@ -858,10 +896,10 @@ bool MediaPlayerPrivate::isAvailable()
#endif
}
-void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
+void MediaPlayerPrivate::disableUnsupportedTracks()
{
if (!m_qtMovie) {
- enabledTrackCount = 0;
+ m_enabledTrackCount = 0;
return;
}
@@ -872,6 +910,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
allowedTrackTypes->add(QTMediaTypeSound);
allowedTrackTypes->add(QTMediaTypeText);
allowedTrackTypes->add(QTMediaTypeBase);
+ allowedTrackTypes->add(QTMediaTypeMPEG);
allowedTrackTypes->add("clcp");
allowedTrackTypes->add("sbtl");
}
@@ -879,7 +918,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
NSArray *tracks = [m_qtMovie.get() tracks];
unsigned trackCount = [tracks count];
- enabledTrackCount = trackCount;
+ m_enabledTrackCount = trackCount;
for (unsigned trackIndex = 0; trackIndex < trackCount; trackIndex++) {
// Grab the track at the current index. If there isn't one there, then
// we can move onto the next one.
@@ -907,7 +946,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
if (!allowedTrackTypes->contains(mediaType)) {
// If this track type is not allowed, then we need to disable it.
[track setEnabled:NO];
- --enabledTrackCount;
+ --m_enabledTrackCount;
}
// Disable chapter tracks. These are most likely to lead to trouble, as
@@ -939,7 +978,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
// Disable the evil, evil track.
[chapterTrack setEnabled:NO];
- --enabledTrackCount;
+ --m_enabledTrackCount;
}
}
@@ -947,7 +986,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
@implementation WebCoreMovieObserver
-- (id)initWithCallback:(MediaPlayerPrivate *)callback
+- (id)initWithCallback:(MediaPlayerPrivate*)callback
{
m_callback = callback;
return [super init];
diff --git a/WebCore/platform/graphics/mac/MediaPlayerProxy.h b/WebCore/platform/graphics/mac/MediaPlayerProxy.h
new file mode 100644
index 0000000..6060484
--- /dev/null
+++ b/WebCore/platform/graphics/mac/MediaPlayerProxy.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaPlayerProxy_h
+#define MediaPlayerProxy_h
+
+#ifdef __OBJC__
+@class WebMediaPlayerProxy;
+#else
+class WebMediaPlayerProxy;
+#endif
+
+enum MediaPlayerProxyNotificationType {
+
+ MediaPlayerNotificationMediaValidated = 1,
+ MediaPlayerNotificationMediaFailedToValidate,
+
+ MediaPlayerNotificationStartUsingNetwork,
+ MediaPlayerNotificationStopUsingNetwork,
+
+ MediaPlayerNotificationEnteredFullScreen,
+ MediaPlayerNotificationExitedFullScreen,
+
+ MediaPlayerNotificationReadyForInspection,
+ MediaPlayerNotificationReadyForPlayback,
+ MediaPlayerNotificationDidPlayToTheEnd,
+
+ MediaPlayerNotificationPlaybackFailed,
+
+ MediaPlayerNotificationStreamLikelyToKeepUp,
+ MediaPlayerNotificationStreamUnlikelyToKeepUp,
+ MediaPlayerNotificationStreamBufferFull,
+ MediaPlayerNotificationStreamRanDry,
+ MediaPlayerNotificationFileLoaded,
+
+ MediaPlayerNotificationSizeDidChange,
+ MediaPlayerNotificationVolumeDidChange,
+ MediaPlayerNotificationMutedDidChange,
+ MediaPlayerNotificationTimeJumped,
+
+ MediaPlayerNotificationPlayPauseButtonPressed,
+};
+
+#ifdef __OBJC__
+@interface NSObject (WebMediaPlayerProxy)
+
+- (int)_interfaceVersion;
+
+- (void)_disconnect;
+
+- (void)_load:(NSURL *)url;
+- (void)_cancelLoad;
+
+- (void)_setPoster:(NSURL *)url;
+
+- (void)_play;
+- (void)_pause;
+
+- (NSSize)_naturalSize;
+
+- (BOOL)_hasVideo;
+- (BOOL)_hasAudio;
+
+- (NSTimeInterval)_duration;
+
+- (double)_currentTime;
+- (void)_setCurrentTime:(double)time;
+- (BOOL)_seeking;
+
+- (void)_setEndTime:(double)time;
+
+- (float)_rate;
+- (void)_setRate:(float)rate;
+
+- (float)_volume;
+- (void)_setVolume:(float)newVolume;
+
+- (BOOL)_muted;
+- (void)_setMuted:(BOOL)muted;
+
+- (float)_maxTimeBuffered;
+- (float)_maxTimeSeekable;
+- (NSArray *)_bufferedTimeRanges;
+
+- (int)_dataRate;
+
+- (BOOL)_totalBytesKnown;
+- (unsigned)_totalBytes;
+- (unsigned)_bytesLoaded;
+
+- (NSArray *)_mimeTypes;
+
+@end
+#endif
+
+#endif
diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
index 30dbf97..a3c10fa 100644
--- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
+++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -38,6 +38,7 @@
#import "FontDescription.h"
#import "SharedBuffer.h"
#import "WebCoreSystemInterface.h"
+#import <AppKit/AppKit.h>
#import <ApplicationServices/ApplicationServices.h>
#import <float.h>
#import <unicode/uchar.h>
diff --git a/WebCore/platform/graphics/mac/WebLayer.h b/WebCore/platform/graphics/mac/WebLayer.h
new file mode 100644
index 0000000..b8b46ed
--- /dev/null
+++ b/WebCore/platform/graphics/mac/WebLayer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebLayer_h
+#define WebLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import <QuartzCore/QuartzCore.h>
+
+namespace WebCore {
+ class GraphicsLayer;
+}
+
+// Category implemented by WebLayer and WebTiledLayer.
+@interface CALayer(WebLayerAdditions)
+
+- (void)setLayerOwner:(WebCore::GraphicsLayer*)layer;
+- (WebCore::GraphicsLayer*)layerOwner;
+
+@end
+
+@interface WebLayer : CALayer
+{
+ WebCore::GraphicsLayer* m_layerOwner;
+}
+
+// Class method allows us to share implementation across TiledLayerMac and WebLayer
++ (void)drawContents:(WebCore::GraphicsLayer*)layerContents ofLayer:(CALayer*)layer intoContext:(CGContextRef)context;
+
+@end
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebLayer_h
diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm
new file mode 100644
index 0000000..267b5bc
--- /dev/null
+++ b/WebCore/platform/graphics/mac/WebLayer.mm
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "WebLayer.h"
+
+#import "GraphicsContext.h"
+#import "GraphicsLayer.h"
+#import <QuartzCore/QuartzCore.h>
+#import "WebCoreTextRenderer.h"
+#import <wtf/UnusedParam.h>
+
+using namespace WebCore;
+
+@implementation WebLayer
+
++ (void)drawContents:(WebCore::GraphicsLayer*)layerContents ofLayer:(CALayer*)layer intoContext:(CGContextRef)context
+{
+ UNUSED_PARAM(layer);
+ CGContextSaveGState(context);
+
+ if (layerContents && layerContents->client()) {
+ [NSGraphicsContext saveGraphicsState];
+
+ // Set up an NSGraphicsContext for the context, so that parts of AppKit that rely on
+ // the current NSGraphicsContext (e.g. NSCell drawing) get the right one.
+ NSGraphicsContext* layerContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:YES];
+ [NSGraphicsContext setCurrentContext:layerContext];
+
+ GraphicsContext graphicsContext(context);
+
+ // It's important to get the clip from the context, because it may be significantly
+ // smaller than the layer bounds (e.g. tiled layers)
+ CGRect clipBounds = CGContextGetClipBoundingBox(context);
+ IntRect clip(enclosingIntRect(clipBounds));
+ layerContents->paintGraphicsLayerContents(graphicsContext, clip);
+
+ [NSGraphicsContext restoreGraphicsState];
+ }
+#ifndef NDEBUG
+ else {
+ ASSERT_NOT_REACHED();
+
+ // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
+ // so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
+ CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
+ CGRect aBounds = [layer bounds];
+ CGContextFillRect(context, aBounds);
+ }
+#endif
+
+ CGContextRestoreGState(context);
+
+#ifndef NDEBUG
+ if (layerContents && layerContents->showRepaintCounter()) {
+ bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]];
+
+ char text[16]; // that's a lot of repaints
+ snprintf(text, sizeof(text), "%d", layerContents->incrementRepaintCount());
+
+ CGAffineTransform a = CGContextGetCTM(context);
+
+ CGContextSaveGState(context);
+ if (isTiledLayer)
+ CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 0.8f);
+ else
+ CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
+
+ CGRect aBounds = [layer bounds];
+
+ aBounds.size.width = 10 + 12 * strlen(text);
+ aBounds.size.height = 25;
+ CGContextFillRect(context, aBounds);
+
+ CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f);
+
+ CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));
+ CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman);
+ CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text));
+
+ CGContextRestoreGState(context);
+ }
+#endif
+}
+
+// Disable default animations
+- (id<CAAction>)actionForKey:(NSString *)key
+{
+ UNUSED_PARAM(key);
+ return nil;
+}
+
+// Implement this so presentationLayer can get our custom attributes
+- (id)initWithLayer:(id)layer
+{
+ if ((self = [super initWithLayer:layer]))
+ m_layerOwner = [(WebLayer*)layer layerOwner];
+
+ return self;
+}
+
+- (void)setNeedsDisplay
+{
+ if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent())
+ [super setNeedsDisplay];
+}
+
+- (void)setNeedsDisplayInRect:(CGRect)dirtyRect
+{
+ if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) {
+ [super setNeedsDisplayInRect:dirtyRect];
+
+#ifndef NDEBUG
+ if (m_layerOwner->showRepaintCounter()) {
+ CGRect bounds = [self bounds];
+ [super setNeedsDisplayInRect:CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25)];
+ }
+#endif
+ }
+}
+
+- (void)drawInContext:(CGContextRef)context
+{
+ [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:context];
+}
+
+@end // implementation WebLayer
+
+#pragma mark -
+
+@implementation WebLayer(WebLayerAdditions)
+
+- (void)setLayerOwner:(GraphicsLayer*)aLayer
+{
+ m_layerOwner = aLayer;
+}
+
+- (GraphicsLayer*)layerOwner
+{
+ return m_layerOwner;
+}
+
+@end
+
+#pragma mark -
+
+#ifndef NDEBUG
+
+@implementation CALayer(ExtendedDescription)
+
+- (NSString*)_descriptionWithPrefix:(NSString*)inPrefix
+{
+ CGRect aBounds = [self bounds];
+ CGPoint aPos = [self position];
+ CATransform3D t = [self transform];
+
+ NSString* selfString = [NSString stringWithFormat:@"%@<%@ 0x%08x> \"%@\" bounds(%.1f, %.1f, %.1f, %.1f) pos(%.1f, %.1f), sublayers=%d masking=%d",
+ inPrefix,
+ [self class],
+ self,
+ [self name],
+ aBounds.origin.x, aBounds.origin.y, aBounds.size.width, aBounds.size.height,
+ aPos.x, aPos.y,
+ [[self sublayers] count],
+ [self masksToBounds]];
+
+ NSMutableString* curDesc = [NSMutableString stringWithString:selfString];
+
+ if ([[self sublayers] count] > 0)
+ [curDesc appendString:@"\n"];
+
+ NSString* sublayerPrefix = [inPrefix stringByAppendingString:@"\t"];
+
+ NSEnumerator* sublayersEnum = [[self sublayers] objectEnumerator];
+ CALayer* curLayer;
+ while ((curLayer = [sublayersEnum nextObject]))
+ [curDesc appendString:[curLayer _descriptionWithPrefix:sublayerPrefix]];
+
+ if ([[self sublayers] count] == 0)
+ [curDesc appendString:@"\n"];
+
+ return curDesc;
+}
+
+- (NSString*)extendedDescription
+{
+ return [self _descriptionWithPrefix:@""];
+}
+
+@end // implementation WebLayer(ExtendedDescription)
+
+#endif // NDEBUG
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.h b/WebCore/platform/graphics/mac/WebTiledLayer.h
new file mode 100644
index 0000000..1c9144d
--- /dev/null
+++ b/WebCore/platform/graphics/mac/WebTiledLayer.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebTiledLayer_h
+#define WebTiledLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "WebLayer.h"
+
+@interface WebTiledLayer : CATiledLayer
+{
+ WebCore::GraphicsLayer* m_layerOwner;
+}
+
+// implements WebLayerAdditions
+
+@end
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebTiledLayer_h
+
diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.mm b/WebCore/platform/graphics/mac/WebTiledLayer.mm
new file mode 100644
index 0000000..1dd00ba
--- /dev/null
+++ b/WebCore/platform/graphics/mac/WebTiledLayer.mm
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "WebTiledLayer.h"
+
+#import "GraphicsContext.h"
+#import "GraphicsLayer.h"
+#import <wtf/UnusedParam.h>
+
+using namespace WebCore;
+
+@implementation WebTiledLayer
+
+// Set a zero duration for the fade in of tiles
++ (CFTimeInterval)fadeDuration
+{
+ return 0;
+}
+
+// Make sure that tiles are drawn on the main thread
++ (BOOL)shouldDrawOnMainThread
+{
+ return YES;
+}
+
+// Disable default animations
+- (id<CAAction>)actionForKey:(NSString *)key
+{
+ UNUSED_PARAM(key);
+ return nil;
+}
+
+// Implement this so presentationLayer can get our custom attributes
+- (id)initWithLayer:(id)layer
+{
+ if ((self = [super initWithLayer:layer]))
+ m_layerOwner = [(WebLayer*)layer layerOwner];
+
+ return self;
+}
+
+- (void)setNeedsDisplay
+{
+ if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent())
+ [super setNeedsDisplay];
+}
+
+- (void)setNeedsDisplayInRect:(CGRect)dirtyRect
+{
+ if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) {
+ [super setNeedsDisplayInRect:dirtyRect];
+
+#ifndef NDEBUG
+ if (m_layerOwner->showRepaintCounter()) {
+ CGRect bounds = [self bounds];
+ [super setNeedsDisplayInRect:CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25)];
+ }
+#endif
+ }
+}
+
+- (void)drawInContext:(CGContextRef)ctx
+{
+ [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:ctx];
+}
+
+@end // implementation WebTiledLayer
+
+#pragma mark -
+
+@implementation WebTiledLayer(LayerMacAdditions)
+
+- (void)setLayerOwner:(GraphicsLayer*)aLayer
+{
+ m_layerOwner = aLayer;
+}
+
+- (GraphicsLayer*)layerOwner
+{
+ return m_layerOwner;
+}
+
+@end
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/win/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp
index 1951320..16c3c00 100644
--- a/WebCore/platform/graphics/win/OpenTypeUtilities.cpp
+++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp
@@ -49,9 +49,9 @@ struct EOTPrefix {
unsigned fontDataSize;
unsigned version;
unsigned flags;
- UInt8 fontPANOSE[10];
- UInt8 charset;
- UInt8 italic;
+ uint8_t fontPANOSE[10];
+ uint8_t charset;
+ uint8_t italic;
unsigned weight;
unsigned short fsType;
unsigned short magicNumber;
@@ -69,6 +69,15 @@ struct TableDirectoryEntry {
BigEndianULong length;
};
+#if !PLATFORM(CG)
+// Fixed type is not defined on non-CG platforms. |version| in sfntHeader
+// and headTable and |fontRevision| in headTable are of Fixed, but they're
+// not actually refered to anywhere. Therefore, we just have to match
+// the size (4 bytes). For the definition of Fixed type, see
+// http://developer.apple.com/documentation/mac/Legacy/GXEnvironment/GXEnvironment-356.html#HEADING356-6.
+typedef int32_t Fixed;
+#endif
+
struct sfntHeader {
Fixed version;
BigEndianUShort numTables;
@@ -95,9 +104,9 @@ struct OS2Table {
BigEndianUShort strikeoutSize;
BigEndianUShort strikeoutPosition;
BigEndianUShort familyClass;
- UInt8 panose[10];
+ uint8_t panose[10];
BigEndianULong unicodeRange[4];
- UInt8 vendID[4];
+ uint8_t vendID[4];
BigEndianUShort fsSelection;
BigEndianUShort firstCharIndex;
BigEndianUShort lastCharIndex;
@@ -152,7 +161,7 @@ struct nameTable {
#pragma pack()
-static void appendBigEndianStringToEOTHeader(Vector<UInt8, 512>& eotHeader, const BigEndianUShort* string, unsigned short length)
+static void appendBigEndianStringToEOTHeader(Vector<uint8_t, 512>& eotHeader, const BigEndianUShort* string, unsigned short length)
{
size_t size = eotHeader.size();
eotHeader.resize(size + length + 2 * sizeof(unsigned short));
@@ -165,7 +174,7 @@ static void appendBigEndianStringToEOTHeader(Vector<UInt8, 512>& eotHeader, cons
dst[i] = 0;
}
-bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
+bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
{
overlayDst = 0;
overlaySrc = 0;
@@ -311,7 +320,7 @@ bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t&
appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength);
unsigned short padding = 0;
- eotHeader.append(reinterpret_cast<UInt8*>(&padding), sizeof(padding));
+ eotHeader.append(reinterpret_cast<uint8_t*>(&padding), sizeof(padding));
prefix->eotSize = eotHeader.size() + fontData->size();
diff --git a/WebCore/platform/graphics/win/OpenTypeUtilities.h b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h
index ab35551..a67ffc7 100644
--- a/WebCore/platform/graphics/win/OpenTypeUtilities.h
+++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h
@@ -33,7 +33,7 @@ namespace WebCore {
class SharedBuffer;
-bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength);
+bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength);
HANDLE renameAndActivateFont(SharedBuffer*, const String&);
} // namespace WebCore
diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
index ea51fe8..f0dd3ea 100644
--- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
+++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
@@ -61,12 +61,14 @@ FontPlatformData::FontPlatformData(const QFont& font, bool bold)
{
}
+#if ENABLE(SVG_FONTS)
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
: m_size(size)
, m_bold(bold)
, m_oblique(oblique)
{
}
+#endif
FontPlatformData::FontPlatformData()
: m_size(0.0f)
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index deeea99..9ed5915 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -1,6 +1,7 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -24,11 +25,18 @@
#include "FontFallbackList.h"
#include "FontSelector.h"
+#include "Gradient.h"
#include "GraphicsContext.h"
-#include <QTextLayout>
-#include <QPainter>
-#include <QFontMetrics>
+#include "Pattern.h"
+#include "TransformationMatrix.h"
+
+#include <QBrush>
#include <QFontInfo>
+#include <QFontMetrics>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPen>
+#include <QTextLayout>
#include <qalgorithms.h>
#include <qdebug.h>
@@ -37,20 +45,27 @@
#if QT_VERSION >= 0x040400
namespace WebCore {
-static QString qstring(const TextRun& run)
+static const QString qstring(const TextRun& run)
+{
+ //We don't detach
+ return QString::fromRawData((const QChar *)run.characters(), run.length());
+}
+
+static const QString fixSpacing(const QString &string)
{
- QString string((QChar *)run.characters(), run.length());
- QChar *uc = string.data();
+ //Only detach if we're actually changing something
+ QString possiblyDetached = string;
for (int i = 0; i < string.length(); ++i) {
- if (Font::treatAsSpace(uc[i].unicode()))
- uc[i] = 0x20;
- else if (Font::treatAsZeroWidthSpace(uc[i].unicode()))
- uc[i] = 0x200c;
+ const QChar c = string.at(i);
+ if (c.unicode() != 0x20 && Font::treatAsSpace(c.unicode())) {
+ possiblyDetached[i] = 0x20; //detach
+ } else if (c.unicode() != 0x200c && Font::treatAsZeroWidthSpace(c.unicode())) {
+ possiblyDetached[i] = 0x200c; //detach
+ }
}
- return string;
+ return possiblyDetached;
}
-
static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
{
int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
@@ -72,10 +87,32 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float
to = run.length();
QPainter *p = ctx->platformContext();
- Color color = ctx->fillColor();
- p->setPen(QColor(color));
- QString string = qstring(run);
+ if (ctx->textDrawingMode() & cTextFill) {
+ if (ctx->fillGradient()) {
+ QBrush brush(*ctx->fillGradient()->platformGradient());
+ brush.setTransform(ctx->fillGradient()->gradientSpaceTransform());
+ p->setPen(QPen(brush, 0));
+ } else if (ctx->fillPattern()) {
+ TransformationMatrix affine;
+ p->setPen(QPen(QBrush(ctx->fillPattern()->createPlatformPattern(affine)), 0));
+ } else
+ p->setPen(QColor(ctx->fillColor()));
+ }
+
+ if (ctx->textDrawingMode() & cTextStroke) {
+ if (ctx->strokeGradient()) {
+ QBrush brush(*ctx->strokeGradient()->platformGradient());
+ brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform());
+ p->setPen(QPen(brush, ctx->strokeThickness()));
+ } else if (ctx->strokePattern()) {
+ TransformationMatrix affine;
+ p->setPen(QPen(QBrush(ctx->strokePattern()->createPlatformPattern(affine)), ctx->strokeThickness()));
+ } else
+ p->setPen(QPen(QColor(ctx->strokeColor()), ctx->strokeThickness()));
+ }
+
+ const QString string = fixSpacing(qstring(run));
// text shadow
IntSize shadowSize;
@@ -137,14 +174,20 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float
p->drawText(pt, string, flags, run.padding());
p->restore();
}
- p->drawText(pt, string, flags, run.padding());
+ if (ctx->textDrawingMode() & cTextStroke) {
+ QPainterPath path;
+ path.addText(pt, font(), string);
+ p->strokePath(path, p->pen());
+ }
+ if (ctx->textDrawingMode() & cTextFill)
+ p->drawText(pt, string, flags, run.padding());
}
float Font::floatWidthForComplexText(const TextRun& run) const
{
if (!run.length())
return 0;
- QString string = qstring(run);
+ const QString string = fixSpacing(qstring(run));
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
int w = int(line.naturalTextWidth());
@@ -157,7 +200,7 @@ float Font::floatWidthForComplexText(const TextRun& run) const
int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const
{
- QString string = qstring(run);
+ const QString string = fixSpacing(qstring(run));
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
return line.xToCursor(position);
@@ -165,7 +208,7 @@ int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, int h, int from, int to) const
{
- QString string = qstring(run);
+ const QString string = fixSpacing(qstring(run));
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp
index a0edf8d..1e71f58 100644
--- a/WebCore/platform/graphics/qt/GradientQt.cpp
+++ b/WebCore/platform/graphics/qt/GradientQt.cpp
@@ -28,9 +28,10 @@
#include "Gradient.h"
#include "CSSParser.h"
-#include "NotImplemented.h"
+#include "GraphicsContext.h"
#include <QGradient>
+#include <QPainter>
namespace WebCore {
@@ -66,12 +67,24 @@ QGradient* Gradient::platformGradient()
++stopIterator;
}
+ switch(m_spreadMethod) {
+ case SpreadMethodPad:
+ m_gradient->setSpread(QGradient::PadSpread);
+ break;
+ case SpreadMethodReflect:
+ m_gradient->setSpread(QGradient::ReflectSpread);
+ break;
+ case SpreadMethodRepeat:
+ m_gradient->setSpread(QGradient::RepeatSpread);
+ break;
+ }
+
return m_gradient;
}
void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
{
- notImplemented();
+ context->platformContext()->fillRect(rect, *platformGradient());
}
} //namespace
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 2e7cdcb..ccf4b06 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -51,6 +51,7 @@
#include "Pen.h"
#include "NotImplemented.h"
+#include <QBrush>
#include <QDebug>
#include <QGradient>
#include <QPainter>
@@ -152,22 +153,6 @@ static Qt::PenStyle toQPenStyle(StrokeStyle style)
return Qt::NoPen;
}
-static inline QGradient applySpreadMethod(QGradient gradient, GradientSpreadMethod spreadMethod)
-{
- switch (spreadMethod) {
- case SpreadMethodPad:
- gradient.setSpread(QGradient::PadSpread);
- break;
- case SpreadMethodReflect:
- gradient.setSpread(QGradient::ReflectSpread);
- break;
- case SpreadMethodRepeat:
- gradient.setSpread(QGradient::RepeatSpread);
- break;
- }
- return gradient;
-}
-
struct TransparencyLayer
{
TransparencyLayer(const QPainter* p, const QRect &rect)
@@ -282,7 +267,11 @@ PlatformGraphicsContext* GraphicsContext::platformContext() const
TransformationMatrix GraphicsContext::getCTM() const
{
- return platformContext()->combinedMatrix();
+ QTransform matrix(platformContext()->combinedTransform());
+ return TransformationMatrix(matrix.m11(), matrix.m12(), 0, matrix.m13(),
+ matrix.m21(), matrix.m22(), 0, matrix.m23(),
+ 0, 0, 1, 0,
+ matrix.m31(), matrix.m32(), 0, matrix.m33());
}
void GraphicsContext::savePlatformState()
@@ -295,7 +284,7 @@ void GraphicsContext::restorePlatformState()
m_data->p()->restore();
if (!m_data->currentPath.isEmpty() && m_common->state.pathTransform.isInvertible()) {
- QMatrix matrix = m_common->state.pathTransform;
+ QTransform matrix = m_common->state.pathTransform;
m_data->currentPath = m_data->currentPath * matrix;
}
}
@@ -458,13 +447,21 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
if (paintingDisabled())
return;
+ StrokeStyle style = strokeStyle();
+ Color color = strokeColor();
+ if (style == NoStroke || !color.alpha())
+ return;
+
+ float width = strokeThickness();
+
FloatPoint p1 = point1;
FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
QPainter *p = m_data->p();
const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
- adjustLineToPixelBoundaries(p1, p2, strokeThickness(), strokeStyle());
+ adjustLineToPixelBoundaries(p1, p2, width, style);
IntSize shadowSize;
int shadowBlur;
@@ -477,8 +474,76 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
p->restore();
}
+ int patWidth = 0;
+ switch (style) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DottedStroke:
+ patWidth = (int)width;
+ break;
+ case DashedStroke:
+ patWidth = 3 * (int)width;
+ break;
+ }
+
+ if (patWidth) {
+ p->save();
+
+ // Do a rect fill of our endpoints. This ensures we always have the
+ // appearance of being a border. We then draw the actual dotted/dashed line.
+ if (isVerticalLine) {
+ p->fillRect(FloatRect(p1.x() - width / 2, p1.y() - width, width, width), QColor(color));
+ p->fillRect(FloatRect(p2.x() - width / 2, p2.y(), width, width), QColor(color));
+ } else {
+ p->fillRect(FloatRect(p1.x() - width, p1.y() - width / 2, width, width), QColor(color));
+ p->fillRect(FloatRect(p2.x(), p2.y() - width / 2, width, width), QColor(color));
+ }
+
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width;
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0f;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0f;
+ else {
+ bool evenNumberOfSegments = numSegments % 2 == 0;
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2;
+ } else
+ patternOffset = patWidth / 2;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder)/2;
+ }
+ }
+
+ QVector<qreal> dashes;
+ dashes << qreal(patWidth) / width << qreal(patWidth) / width;
+
+ QPen pen = p->pen();
+ pen.setWidthF(width);
+ pen.setCapStyle(Qt::FlatCap);
+ pen.setDashPattern(dashes);
+ pen.setDashOffset(patternOffset / width);
+ p->setPen(pen);
+ }
+
p->drawLine(p1, p2);
+ if (patWidth)
+ p->restore();
+
p->setRenderHint(QPainter::Antialiasing, antiAlias);
}
@@ -553,9 +618,9 @@ void GraphicsContext::fillPath()
break;
}
case GradientColorSpace:
- QGradient* gradient = m_common->state.fillGradient->platformGradient();
- *gradient = applySpreadMethod(*gradient, spreadMethod());
- p->fillPath(path, QBrush(*gradient));
+ QBrush brush(*m_common->state.fillGradient->platformGradient());
+ brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform());
+ p->fillPath(path, brush);
break;
}
m_data->currentPath = QPainterPath();
@@ -583,9 +648,9 @@ void GraphicsContext::strokePath()
break;
}
case GradientColorSpace: {
- QGradient* gradient = m_common->state.strokeGradient->platformGradient();
- *gradient = applySpreadMethod(*gradient, spreadMethod());
- pen.setBrush(QBrush(*gradient));
+ QBrush brush(*m_common->state.strokeGradient->platformGradient());
+ brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform());
+ pen.setBrush(brush);
p->setPen(pen);
p->strokePath(path, pen);
break;
@@ -612,7 +677,9 @@ void GraphicsContext::fillRect(const FloatRect& rect)
break;
}
case GradientColorSpace:
- p->fillRect(rect, QBrush(*(m_common->state.fillGradient.get()->platformGradient())));
+ QBrush brush(*m_common->state.fillGradient->platformGradient());
+ brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform());
+ p->fillRect(rect, brush);
break;
}
m_data->currentPath = QPainterPath();
@@ -663,10 +730,7 @@ void GraphicsContext::clip(const FloatRect& rect)
if (paintingDisabled())
return;
- QPainter *p = m_data->p();
- if (p->clipRegion().isEmpty())
- p->setClipRect(rect);
- else p->setClipRect(rect, Qt::IntersectClip);
+ m_data->p()->setClipRect(rect, Qt::IntersectClip);
}
void GraphicsContext::clipPath(WindRule clipRule)
@@ -818,7 +882,7 @@ void GraphicsContext::clearRect(const FloatRect& rect)
QPainter::CompositionMode currentCompositionMode = p->compositionMode();
if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
p->setCompositionMode(QPainter::CompositionMode_Source);
- p->eraseRect(rect);
+ p->fillRect(rect, Qt::transparent);
if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
p->setCompositionMode(currentCompositionMode);
}
@@ -939,7 +1003,7 @@ void GraphicsContext::translate(float x, float y)
m_data->p()->translate(x, y);
if (!m_data->currentPath.isEmpty()) {
- QMatrix matrix;
+ QTransform matrix;
m_data->currentPath = m_data->currentPath * matrix.translate(-x, -y);
m_common->state.pathTransform.translate(x, y);
}
@@ -961,7 +1025,7 @@ void GraphicsContext::rotate(float radians)
m_data->p()->rotate(180/M_PI*radians);
if (!m_data->currentPath.isEmpty()) {
- QMatrix matrix;
+ QTransform matrix;
m_data->currentPath = m_data->currentPath * matrix.rotate(-180/M_PI*radians);
m_common->state.pathTransform.rotate(radians);
}
@@ -975,9 +1039,9 @@ void GraphicsContext::scale(const FloatSize& s)
m_data->p()->scale(s.width(), s.height());
if (!m_data->currentPath.isEmpty()) {
- QMatrix matrix;
+ QTransform matrix;
m_data->currentPath = m_data->currentPath * matrix.scale(1 / s.width(), 1 / s.height());
- m_common->state.pathTransform.scale(s.width(), s.height());
+ m_common->state.pathTransform.scaleNonUniform(s.width(), s.height());
}
}
@@ -1041,12 +1105,12 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform)
if (paintingDisabled())
return;
- m_data->p()->setMatrix(transform, true);
+ m_data->p()->setWorldTransform(transform, true);
// Transformations to the context shouldn't transform the currentPath.
// We have to undo every change made to the context from the currentPath to avoid wrong drawings.
if (!m_data->currentPath.isEmpty() && transform.isInvertible()) {
- QMatrix matrix = transform.inverse();
+ QTransform matrix = transform.inverse();
m_data->currentPath = m_data->currentPath * matrix;
m_common->state.pathTransform.multiply(transform);
}
diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
index d4ab59f..d748305 100644
--- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2008 Holger Hans Peter Freyther
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,10 +32,11 @@
#include "GraphicsContext.h"
#include "ImageData.h"
#include "MIMETypeRegistry.h"
-#include "NotImplemented.h"
#include "StillImageQt.h"
#include <QBuffer>
+#include <QColor>
+#include <QImage>
#include <QImageWriter>
#include <QPainter>
#include <QPixmap>
@@ -79,15 +81,108 @@ Image* ImageBuffer::image() const
return m_image.get();
}
-PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const
+PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
{
- notImplemented();
- return 0;
+ PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
+ unsigned char* data = result->data()->data()->data();
+
+ if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height())
+ memset(data, 0, result->data()->length());
+
+ int originx = rect.x();
+ int destx = 0;
+ if (originx < 0) {
+ destx = -originx;
+ originx = 0;
+ }
+ int endx = rect.x() + rect.width();
+ if (endx > m_size.width())
+ endx = m_size.width();
+ int numColumns = endx - originx;
+
+ int originy = rect.y();
+ int desty = 0;
+ if (originy < 0) {
+ desty = -originy;
+ originy = 0;
+ }
+ int endy = rect.y() + rect.height();
+ if (endy > m_size.height())
+ endy = m_size.height();
+ int numRows = endy - originy;
+
+ QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ ASSERT(!image.isNull());
+
+ unsigned destBytesPerRow = 4 * rect.width();
+ unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ QRgb value = image.pixel(x + originx, y + originy);
+ int basex = x * 4;
+
+ destRows[basex] = qRed(value);
+ destRows[basex + 1] = qGreen(value);
+ destRows[basex + 2] = qBlue(value);
+ destRows[basex + 3] = qAlpha(value);
+ }
+ destRows += destBytesPerRow;
+ }
+
+ return result;
}
-void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&)
+void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
{
- notImplemented();
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originx = sourceRect.x();
+ int destx = destPoint.x() + sourceRect.x();
+ ASSERT(destx >= 0);
+ ASSERT(destx < m_size.width());
+ ASSERT(originx >= 0);
+ ASSERT(originx <= sourceRect.right());
+
+ int endx = destPoint.x() + sourceRect.right();
+ ASSERT(endx <= m_size.width());
+
+ int numColumns = endx - destx;
+
+ int originy = sourceRect.y();
+ int desty = destPoint.y() + sourceRect.y();
+ ASSERT(desty >= 0);
+ ASSERT(desty < m_size.height());
+ ASSERT(originy >= 0);
+ ASSERT(originy <= sourceRect.bottom());
+
+ int endy = destPoint.y() + sourceRect.bottom();
+ ASSERT(endy <= m_size.height());
+ int numRows = endy - desty;
+
+ unsigned srcBytesPerRow = 4 * source->width();
+
+ bool isPainting = m_data.m_painter->isActive();
+ if (isPainting)
+ m_data.m_painter->end();
+
+ QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+
+ unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ quint32* scanLine = reinterpret_cast<quint32*>(image.scanLine(y + desty));
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ scanLine[x + destx] = reinterpret_cast<quint32*>(srcRows + basex)[0];
+ }
+
+ srcRows += srcBytesPerRow;
+ }
+
+ m_data.m_pixmap = QPixmap::fromImage(image);
+
+ if (isPainting)
+ m_data.m_painter->begin(&m_data.m_pixmap);
}
// We get a mimeType here but QImageWriter does not support mimetypes but
diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp
index 99062f9..3bc67ae 100644
--- a/WebCore/platform/graphics/qt/ImageQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageQt.cpp
@@ -2,6 +2,7 @@
* Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
* Copyright (C) 2006 Zack Rusin <zack@kde.org>
* Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
*
* All rights reserved.
*
@@ -96,7 +97,26 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name)
void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
{
- notImplemented();
+ QPixmap* framePixmap = nativeImageForCurrentFrame();
+ if (!framePixmap) // If it's too early we won't have an image yet.
+ return;
+
+ QPixmap pixmap = *framePixmap;
+ QRect tr = QRectF(tileRect).toRect();
+ if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) {
+ pixmap = pixmap.copy(tr);
+ }
+
+ QBrush b(pixmap);
+ b.setTransform(patternTransform);
+ ctxt->save();
+ ctxt->setCompositeOperation(op);
+ QPainter* p = ctxt->platformContext();
+ if (!pixmap.hasAlpha() && p->compositionMode() == QPainter::CompositionMode_SourceOver)
+ p->setCompositionMode(QPainter::CompositionMode_Source);
+ p->setBrushOrigin(phase);
+ p->fillRect(destRect, b);
+ ctxt->restore();
}
void BitmapImage::initPlatformData()
@@ -131,6 +151,9 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
QPainter* painter(ctxt->platformContext());
+ if (!image->hasAlpha() && painter->compositionMode() == QPainter::CompositionMode_SourceOver)
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+
// Test using example site at
// http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
painter->drawPixmap(dst, *image, src);
@@ -138,33 +161,20 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
ctxt->restore();
}
-void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform,
- const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
+void BitmapImage::checkForSolidColor()
{
- QPixmap* framePixmap = nativeImageForCurrentFrame();
- if (!framePixmap) // If it's too early we won't have an image yet.
- return;
+ m_isSolidColor = false;
+ m_checkedForSolidColor = true;
- QPixmap pixmap = *framePixmap;
- QRect tr = QRectF(tileRect).toRect();
- if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) {
- pixmap = pixmap.copy(tr);
- }
+ if (frameCount() > 1)
+ return;
- QBrush b(pixmap);
- b.setMatrix(patternTransform);
- ctxt->save();
- ctxt->setCompositeOperation(op);
- QPainter* p = ctxt->platformContext();
- p->setBrushOrigin(phase);
- p->fillRect(destRect, b);
- ctxt->restore();
-}
+ QPixmap* framePixmap = frameAtIndex(0);
+ if (!framePixmap || framePixmap->width() != 1 || framePixmap->height() != 1)
+ return;
-void BitmapImage::checkForSolidColor()
-{
- // FIXME: It's easy to implement this optimization. Just need to check the RGBA32 buffer to see if it is 1x1.
- m_isSolidColor = false;
+ m_isSolidColor = true;
+ m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0));
}
}
diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
index d62acc3..84de443 100644
--- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
@@ -163,7 +163,7 @@ void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer*
delete m_decoder;
m_decoder = 0;
if (data)
- setData(data, allDataReceived);
+ setData(data, allDataReceived);
}
}
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
index b1a48fb..c80d73b 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -76,7 +77,7 @@ namespace WebCore {
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_networkState(MediaPlayer::Empty)
- , m_readyState(MediaPlayer::DataUnavailable)
+ , m_readyState(MediaPlayer::HaveNothing)
, m_mediaObject(new MediaObject())
, m_videoWidget(new VideoWidget(0))
, m_audioOutput(new AudioOutput())
@@ -110,6 +111,18 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
}
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+
MediaPlayerPrivate::~MediaPlayerPrivate()
{
LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting videowidget");
@@ -131,6 +144,13 @@ void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&)
notImplemented();
}
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // FIXME: do the real thing
+ notImplemented();
+ return MediaPlayer::IsNotSupported;
+}
+
bool MediaPlayerPrivate::hasVideo() const
{
bool hasVideo = m_mediaObject->hasVideo();
@@ -138,7 +158,7 @@ bool MediaPlayerPrivate::hasVideo() const
return hasVideo;
}
-void MediaPlayerPrivate::load(String url)
+void MediaPlayerPrivate::load(const String& url)
{
LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data());
@@ -149,8 +169,8 @@ void MediaPlayerPrivate::load(String url)
}
// And we don't have any data yet
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
@@ -205,7 +225,7 @@ bool MediaPlayerPrivate::seeking() const
float MediaPlayerPrivate::duration() const
{
- if (m_networkState < MediaPlayer::LoadedMetaData)
+ if (m_readyState < MediaPlayer::HaveMetadata)
return 0.0f;
float duration = m_mediaObject->totalTime() / 1000.0f;
@@ -309,18 +329,19 @@ void MediaPlayerPrivate::updateStates()
Phonon::State phononState = m_mediaObject->state();
if (phononState == Phonon::StoppedState) {
- if (oldNetworkState < MediaPlayer::LoadedMetaData) {
- m_networkState = MediaPlayer::LoadedMetaData;
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState < MediaPlayer::HaveMetadata) {
+ m_networkState = MediaPlayer::Loading; // FIXME: should this be MediaPlayer::Idle?
+ m_readyState = MediaPlayer::HaveMetadata;
m_mediaObject->pause();
}
} else if (phononState == Phonon::PausedState) {
m_networkState = MediaPlayer::Loaded;
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (phononState == Phonon::ErrorState) {
if (!m_mediaObject || m_mediaObject->errorType() == Phonon::FatalError) {
- m_networkState = MediaPlayer::LoadFailed;
- m_readyState = MediaPlayer::DataUnavailable;
+ // FIXME: is it possile to differentiate between different types of errors
+ m_networkState = MediaPlayer::NetworkError;
+ m_readyState = MediaPlayer::HaveNothing;
cancelLoad();
} else {
m_mediaObject->pause();
@@ -328,7 +349,7 @@ void MediaPlayerPrivate::updateStates()
}
if (seeking())
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveNothing;
if (m_networkState != oldNetworkState) {
const QMetaObject* metaObj = this->metaObject();
@@ -357,19 +378,18 @@ void MediaPlayerPrivate::setVisible(bool visible)
m_videoWidget->setVisible(m_isVisible);
}
-void MediaPlayerPrivate::setRect(const IntRect& newRect)
+void MediaPlayerPrivate::setSize(const IntSize& newSize)
{
if (!m_videoWidget)
return;
- LOG(Media, "MediaPlayerPrivatePhonon::setRect(%d,%d %dx%d)",
- newRect.x(), newRect.y(),
- newRect.width(), newRect.height());
+ LOG(Media, "MediaPlayerPrivatePhonon::setSize(%d,%d)",
+ newSize.width(), newSize.height());
QRect currentRect = m_videoWidget->rect();
- if (newRect.width() != currentRect.width() || newRect.height() != currentRect.height())
- m_videoWidget->resize(newRect.width(), newRect.height());
+ if (newSize.width() != currentRect.width() || newSize.height() != currentRect.height())
+ m_videoWidget->resize(newSize.width(), newSize.height());
}
IntSize MediaPlayerPrivate::naturalSize() const
@@ -380,7 +400,7 @@ IntSize MediaPlayerPrivate::naturalSize() const
return IntSize();
}
- if (m_networkState < MediaPlayer::LoadedMetaData) {
+ if (m_readyState < MediaPlayer::HaveMetadata) {
LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
0, 0);
return IntSize();
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
index 1b20a84..9572d61 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -20,8 +21,7 @@
#ifndef MediaPlayerPrivatePhonon_h
#define MediaPlayerPrivatePhonon_h
-#include "MediaPlayer.h"
-#include <wtf/Noncopyable.h>
+#include "MediaPlayerPrivate.h"
#include <QObject>
#include <phononnamespace.h>
@@ -40,31 +40,33 @@ QT_END_NAMESPACE
namespace WebCore {
- class MediaPlayerPrivate : public QObject, Noncopyable {
+ class MediaPlayerPrivate : public QObject, public MediaPlayerPrivateInterface {
Q_OBJECT
public:
- MediaPlayerPrivate(MediaPlayer*);
+ static void registerMediaEngine(MediaEngineRegistrar);
~MediaPlayerPrivate();
// These enums are used for debugging
Q_ENUMS(ReadyState NetworkState PhononState)
enum ReadyState {
- DataUnavailable,
- CanShowCurrentFrame,
- CanPlay,
- CanPlayThrough
+ HaveNothing,
+ HaveMetadata,
+ HaveCurrentData,
+ HaveFutureData,
+ HaveEnoughData
};
enum NetworkState {
- Empty,
- LoadFailed,
- Loading,
- LoadedMetaData,
- LoadedFirstFrame,
- Loaded
+ Empty,
+ Idle,
+ Loading,
+ Loaded,
+ FormatError,
+ NetworkError,
+ DecodeError
};
enum PhononState {
@@ -79,7 +81,7 @@ namespace WebCore {
IntSize naturalSize() const;
bool hasVideo() const;
- void load(String url);
+ void load(const String &url);
void cancelLoad();
void play();
@@ -109,11 +111,9 @@ namespace WebCore {
unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect&);
+ void setSize(const IntSize&);
void paint(GraphicsContext*, const IntRect&);
- static void getSupportedTypes(HashSet<String>&);
- static bool isAvailable() { return true; }
protected:
bool eventFilter(QObject*, QEvent*);
@@ -130,6 +130,13 @@ namespace WebCore {
void totalTimeChanged(qint64);
private:
+ MediaPlayerPrivate(MediaPlayer*);
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable() { return true; }
+
void updateStates();
MediaPlayer* m_player;
diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp
index bd0192c..a8a3ea2 100644
--- a/WebCore/platform/graphics/qt/PathQt.cpp
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -1,6 +1,7 @@
/*
- * Copyright (C) 2006 Zack Rusin <zack@kde.org>
- * 2006 Rob Buis <buis@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * 2006 Rob Buis <buis@kde.org>
+ * 2009 Dirk Schulze <krit@webkit.org>
*
* All rights reserved.
*
@@ -36,7 +37,7 @@
#include "PlatformString.h"
#include "StrokeStyleApplier.h"
#include <QPainterPath>
-#include <QMatrix>
+#include <QTransform>
#include <QString>
#define _USE_MATH_DEFINES
@@ -108,7 +109,7 @@ bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point)
void Path::translate(const FloatSize& size)
{
- QMatrix matrix;
+ QTransform matrix;
matrix.translate(size.width(), size.height());
*m_path = (*m_path) * matrix;
}
@@ -161,9 +162,72 @@ void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const
void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
{
- //FIXME: busted
- qWarning("arcTo is busted");
- m_path->arcTo(p1.x(), p1.y(), p2.x(), p2.y(), radius, 90);
+ FloatPoint p0(m_path->currentPosition());
+
+ if ((p1.x() == p0.x() && p1.y() == p0.y()) || (p1.x() == p2.x() && p1.y() == p2.y()) || radius == 0.f) {
+ m_path->lineTo(p1);
+ return;
+ }
+
+ FloatPoint p1p0((p0.x() - p1.x()),(p0.y() - p1.y()));
+ FloatPoint p1p2((p2.x() - p1.x()),(p2.y() - p1.y()));
+ float p1p0_length = sqrtf(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
+ float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+
+ double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+ // all points on a line logic
+ if (cos_phi == -1) {
+ m_path->lineTo(p1);
+ return;
+ }
+ if (cos_phi == 1) {
+ // add infinite far away point
+ unsigned int max_length = 65535;
+ double factor_max = max_length / p1p0_length;
+ FloatPoint ep((p0.x() + factor_max * p1p0.x()), (p0.y() + factor_max * p1p0.y()));
+ m_path->lineTo(ep);
+ return;
+ }
+
+ float tangent = radius / tan(acos(cos_phi) / 2);
+ float factor_p1p0 = tangent / p1p0_length;
+ FloatPoint t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
+
+ FloatPoint orth_p1p0(p1p0.y(), -p1p0.x());
+ float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
+ float factor_ra = radius / orth_p1p0_length;
+
+ // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
+ double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ if (cos_alpha < 0.f)
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+
+ FloatPoint p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
+
+ // calculate angles for addArc
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+ float sa = acos(orth_p1p0.x() / orth_p1p0_length);
+ if (orth_p1p0.y() < 0.f)
+ sa = 2 * piDouble - sa;
+
+ // anticlockwise logic
+ bool anticlockwise = false;
+
+ float factor_p1p2 = tangent / p1p2_length;
+ FloatPoint t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
+ FloatPoint orth_p1p2((t_p1p2.x() - p.x()),(t_p1p2.y() - p.y()));
+ float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
+ float ea = acos(orth_p1p2.x() / orth_p1p2_length);
+ if (orth_p1p2.y() < 0)
+ ea = 2 * piDouble - ea;
+ if ((sa > ea) && ((sa - ea) < piDouble))
+ anticlockwise = true;
+ if ((sa < ea) && ((ea - sa) > piDouble))
+ anticlockwise = true;
+
+ m_path->lineTo(t_p1p0);
+
+ addArc(p, radius, sa, ea, anticlockwise);
}
void Path::closeSubpath()
@@ -316,7 +380,7 @@ void Path::apply(void* info, PathApplierFunction function) const
void Path::transform(const TransformationMatrix& transform)
{
if (m_path) {
- QMatrix mat = transform;
+ QTransform mat = transform;
QPainterPath temp = mat.map(*m_path);
delete m_path;
m_path = new QPainterPath(temp);
diff --git a/WebCore/platform/graphics/qt/PatternQt.cpp b/WebCore/platform/graphics/qt/PatternQt.cpp
index 5b76841..b261613 100644
--- a/WebCore/platform/graphics/qt/PatternQt.cpp
+++ b/WebCore/platform/graphics/qt/PatternQt.cpp
@@ -31,14 +31,15 @@
namespace WebCore {
-QBrush Pattern::createPlatformPattern(const TransformationMatrix& transform) const
+QBrush Pattern::createPlatformPattern(const TransformationMatrix&) const
{
QPixmap* pixmap = tileImage()->nativeImageForCurrentFrame();
if (!pixmap)
return QBrush();
+ // Qt merges patter space and user space itself
QBrush brush(*pixmap);
- brush.setMatrix(transform);
+ brush.setTransform(m_patternSpaceTransformation);
return brush;
}
diff --git a/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
index 47abd17..15f0cc5 100644
--- a/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
+++ b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
@@ -31,170 +31,9 @@
namespace WebCore {
-TransformationMatrix::TransformationMatrix()
- : m_transform()
-{
-}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
- : m_transform(a, b, c, d, tx, ty)
-{
-}
-
-TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix)
- : m_transform(matrix)
-{
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform.setMatrix(a, b, c, d, tx, ty);
-}
-
-void TransformationMatrix::map(double x, double y, double* x2, double* y2) const
-{
- qreal tx2, ty2;
- m_transform.map(qreal(x), qreal(y), &tx2, &ty2);
- *x2 = tx2;
- *y2 = ty2;
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect& rect) const
-{
- return m_transform.mapRect(rect);
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect& rect) const
-{
- return m_transform.mapRect(rect);
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return m_transform.isIdentity();
-}
-
-double TransformationMatrix::a() const
-{
- return m_transform.m11();
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.setMatrix(a, b(), c(), d(), e(), f());
-}
-
-double TransformationMatrix::b() const
-{
- return m_transform.m12();
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.setMatrix(a(), b, c(), d(), e(), f());
-}
-
-double TransformationMatrix::c() const
-{
- return m_transform.m21();
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.setMatrix(a(), b(), c, d(), e(), f());
-}
-
-double TransformationMatrix::d() const
-{
- return m_transform.m22();
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.setMatrix(a(), b(), c(), d, e(), f());
-}
-
-double TransformationMatrix::e() const
-{
- return m_transform.dx();
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.setMatrix(a(), b(), c(), d(), e, f());
-}
-
-double TransformationMatrix::f() const
-{
- return m_transform.dy();
-}
-
-void TransformationMatrix::setF(double f)
-{
- m_transform.setMatrix(a(), b(), c(), d(), e(), f);
-}
-
-void TransformationMatrix::reset()
-{
- m_transform.reset();
-}
-
-TransformationMatrix& TransformationMatrix::scale(double sx, double sy)
-{
- m_transform.scale(sx, sy);
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::rotate(double d)
-{
- m_transform.rotate(d);
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
-{
- m_transform.translate(tx, ty);
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::shear(double sx, double sy)
-{
- m_transform.shear(sx, sy);
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return m_transform.det();
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- if(!isInvertible())
- return TransformationMatrix();
-
- return m_transform.inverted();
-}
-
-TransformationMatrix::operator QMatrix() const
-{
- return m_transform;
-}
-
-bool TransformationMatrix::operator==(const TransformationMatrix& other) const
-{
- return m_transform == other.m_transform;
-}
-
-TransformationMatrix& TransformationMatrix::operator*=(const TransformationMatrix& other)
-{
- m_transform *= other.m_transform;
- return *this;
-}
-
-TransformationMatrix TransformationMatrix::operator*(const TransformationMatrix& other)
-{
- return m_transform * other.m_transform;
+TransformationMatrix::operator QTransform() const
+{
+ return QTransform(m11(), m12(), m14(), m21(), m22(), m24(), m41(), m42(), m44());
}
}
diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp
index eff7c66..2d2000c 100644
--- a/WebCore/platform/graphics/skia/GradientSkia.cpp
+++ b/WebCore/platform/graphics/skia/GradientSkia.cpp
@@ -136,6 +136,19 @@ SkShader* Gradient::platformGradient()
fillStops(m_stops.data(), m_stops.size(), pos, colors);
+ SkShader::TileMode tile = SkShader::kClamp_TileMode;
+ switch (m_spreadMethod) {
+ case SpreadMethodReflect:
+ tile = SkShader::kMirror_TileMode;
+ break;
+ case SpreadMethodRepeat:
+ tile = SkShader::kRepeat_TileMode;
+ break;
+ case SpreadMethodPad:
+ tile = SkShader::kClamp_TileMode;
+ break;
+ }
+
if (m_radial) {
// FIXME: CSS radial Gradients allow an offset focal point (the
// "start circle"), but skia doesn't seem to support that, so this just
@@ -145,13 +158,16 @@ SkShader* Gradient::platformGradient()
// description of the expected behavior.
m_gradient = SkGradientShader::CreateRadial(m_p1,
WebCoreFloatToSkScalar(m_r1), colors, pos,
- static_cast<int>(countUsed), SkShader::kClamp_TileMode);
+ static_cast<int>(countUsed), tile);
} else {
SkPoint pts[2] = { m_p0, m_p1 };
m_gradient = SkGradientShader::CreateLinear(pts, colors, pos,
- static_cast<int>(countUsed), SkShader::kClamp_TileMode);
+ static_cast<int>(countUsed), tile);
}
+ SkMatrix matrix = m_gradientSpaceTransformation;
+ m_gradient->setLocalMatrix(matrix);
+
return m_gradient;
}
diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
index e6c7783..376fa4b 100644
--- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
@@ -36,6 +36,7 @@
#include "Color.h"
#include "FloatRect.h"
#include "Gradient.h"
+#include "ImageBuffer.h"
#include "IntRect.h"
#include "NativeImageSkia.h"
#include "NotImplemented.h"
@@ -274,11 +275,6 @@ void GraphicsContext::endTransparencyLayer()
{
if (paintingDisabled())
return;
-
-#if PLATFORM(WIN_OS)
- platformContext()->canvas()->getTopPlatformDevice().
- fixupAlphaBeforeCompositing();
-#endif
platformContext()->canvas()->restore();
}
@@ -406,8 +402,7 @@ void GraphicsContext::clipPath(WindRule clipRule)
if (paintingDisabled())
return;
- const SkPath* oldPath = platformContext()->currentPath();
- SkPath path(*oldPath);
+ SkPath path = platformContext()->currentPathInLocalCoordinates();
path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
platformContext()->canvas()->clipPath(path);
}
@@ -418,8 +413,9 @@ void GraphicsContext::clipToImageBuffer(const FloatRect& rect,
if (paintingDisabled())
return;
- // FIXME: This is needed for image masking and complex text fills.
- notImplemented();
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ platformContext()->beginLayerClippedToImage(rect, imageBuffer);
+#endif
}
void GraphicsContext::concatCTM(const TransformationMatrix& xform)
@@ -645,6 +641,9 @@ void GraphicsContext::drawLineForText(const IntPoint& pt,
if (paintingDisabled())
return;
+ if (width <= 0)
+ return;
+
int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
SkRect r;
r.fLeft = SkIntToScalar(pt.x());
@@ -653,7 +652,9 @@ void GraphicsContext::drawLineForText(const IntPoint& pt,
r.fBottom = r.fTop + SkIntToScalar(thickness);
SkPaint paint;
- paint.setColor(strokeColor().rgb());
+ platformContext()->setupPaintForFilling(&paint);
+ // Text lines are drawn using the stroke color.
+ paint.setColor(platformContext()->effectiveStrokeColor());
platformContext()->canvas()->drawRect(r, paint);
}
@@ -664,9 +665,10 @@ void GraphicsContext::drawRect(const IntRect& rect)
return;
SkRect r = rect;
- if (!isRectSkiaSafe(getCTM(), r))
+ if (!isRectSkiaSafe(getCTM(), r)) {
// See the fillRect below.
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ }
platformContext()->drawRect(r);
}
@@ -676,7 +678,7 @@ void GraphicsContext::fillPath()
if (paintingDisabled())
return;
- const SkPath& path = *platformContext()->currentPath();
+ SkPath path = platformContext()->currentPathInLocalCoordinates();
if (!isPathSkiaSafe(getCTM(), path))
return;
@@ -686,7 +688,7 @@ void GraphicsContext::fillPath()
if (colorSpace == SolidColorSpace && !fillColor().alpha())
return;
- platformContext()->setFillRule(state.fillRule == RULE_EVENODD ?
+ path.setFillType(state.fillRule == RULE_EVENODD ?
SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
SkPaint paint;
@@ -708,9 +710,10 @@ void GraphicsContext::fillRect(const FloatRect& rect)
return;
SkRect r = rect;
- if (!isRectSkiaSafe(getCTM(), r))
+ if (!isRectSkiaSafe(getCTM(), r)) {
// See the other version of fillRect below.
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ }
const GraphicsContextState& state = m_common->state;
ColorSpace colorSpace = state.fillColorSpace;
@@ -775,6 +778,17 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect,
// See fillRect().
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ if (topLeft.width() + topRight.width() > rect.width()
+ || bottomLeft.width() + bottomRight.width() > rect.width()
+ || topLeft.height() + bottomLeft.height() > rect.height()
+ || topRight.height() + bottomRight.height() > rect.height()) {
+ // Not all the radii fit, return a rect. This matches the behavior of
+ // Path::createRoundedRectangle. Without this we attempt to draw a round
+ // shadow for a square box.
+ fillRect(rect, color);
+ return;
+ }
+
SkPath path;
addCornerArc(&path, r, topRight, 270);
addCornerArc(&path, r, bottomRight, 0);
@@ -784,12 +798,17 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect,
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
platformContext()->canvas()->drawPath(path, paint);
- return fillRect(rect, color);
}
TransformationMatrix GraphicsContext::getCTM() const
{
- return platformContext()->canvas()->getTotalMatrix();
+ const SkMatrix& m = platformContext()->canvas()->getTotalMatrix();
+ return TransformationMatrix(SkScalarToDouble(m.getScaleX()), // a
+ SkScalarToDouble(m.getSkewY()), // b
+ SkScalarToDouble(m.getSkewX()), // c
+ SkScalarToDouble(m.getScaleY()), // d
+ SkScalarToDouble(m.getTranslateX()), // e
+ SkScalarToDouble(m.getTranslateY())); // f
}
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
@@ -1050,7 +1069,7 @@ void GraphicsContext::strokePath()
if (paintingDisabled())
return;
- const SkPath& path = *platformContext()->currentPath();
+ SkPath path = platformContext()->currentPathInLocalCoordinates();
if (!isPathSkiaSafe(getCTM(), path))
return;
diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
index fdfcb85..5e90491 100644
--- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
@@ -31,12 +31,14 @@
#include "config.h"
#include "ImageBuffer.h"
+#include "Base64.h"
#include "BitmapImage.h"
#include "BitmapImageSingleFrameSkia.h"
#include "GraphicsContext.h"
#include "ImageData.h"
#include "NotImplemented.h"
#include "PlatformContextSkia.h"
+#include "PNGImageEncoder.h"
#include "SkiaUtils.h"
using namespace std;
@@ -63,6 +65,9 @@ ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
m_data.m_platformContext.setCanvas(&m_data.m_canvas);
m_context.set(new GraphicsContext(&m_data.m_platformContext));
+#if PLATFORM(WIN_OS)
+ m_context->platformContext()->setDrawingToImageBuffer(true);
+#endif
// Make the background transparent. It would be nice if this wasn't
// required, but the canvas is currently filled with the magic transparency
@@ -101,7 +106,7 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
ASSERT(context());
RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
- unsigned char* data = result->data()->data();
+ unsigned char* data = result->data()->data()->data();
if (rect.x() < 0 || rect.y() < 0 ||
(rect.x() + rect.width()) > m_size.width() ||
@@ -188,7 +193,7 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect,
unsigned srcBytesPerRow = 4 * source->width();
- const unsigned char* srcRow = source->data()->data() + originY * srcBytesPerRow + originX * 4;
+ const unsigned char* srcRow = source->data()->data()->data() + originY * srcBytesPerRow + originX * 4;
for (int y = 0; y < numRows; ++y) {
uint32_t* destRow = bitmap.getAddr32(destX, destY + y);
@@ -203,8 +208,18 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect,
String ImageBuffer::toDataURL(const String&) const
{
- notImplemented();
- return String();
+ // Encode the image into a vector.
+ Vector<unsigned char> pngEncodedData;
+ PNGImageEncoder::encode(*context()->platformContext()->bitmap(), &pngEncodedData);
+
+ // Convert it into base64.
+ Vector<char> base64EncodedData;
+ base64Encode(*reinterpret_cast<Vector<char>*>(&pngEncodedData), base64EncodedData);
+ // Append with a \0 so that it's a valid string.
+ base64EncodedData.append('\0');
+
+ // And the resulting string.
+ return String::format("data:image/png;base64,%s", base64EncodedData.data());
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp
index 1123fe9..d7f2830 100644
--- a/WebCore/platform/graphics/skia/ImageSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageSkia.cpp
@@ -225,6 +225,7 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag
{
SkPaint paint;
paint.setPorterDuffXfermode(compOp);
+ paint.setFilterBitmap(true);
skia::PlatformCanvas* canvas = platformContext->canvas();
@@ -233,7 +234,6 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag
SkScalarToFloat(destRect.width()),
SkScalarToFloat(destRect.height()));
if (resampling == RESAMPLE_AWESOME) {
- paint.setFilterBitmap(false);
drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect);
} else {
// No resampling necessary, we can just draw the bitmap. We want to
@@ -241,7 +241,6 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag
// is something interesting going on with the matrix (like a rotation).
// Note: for serialization, we will want to subset the bitmap first so
// we don't send extra pixels.
- paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint);
}
}
@@ -401,6 +400,7 @@ void BitmapImage::invalidatePlatformData()
void BitmapImage::checkForSolidColor()
{
+ m_checkedForSolidColor = true;
}
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
@@ -427,7 +427,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
paintSkBitmap(ctxt->platformContext(),
*bm,
enclosingIntRect(normSrcRect),
- enclosingIntRect(normDstRect),
+ normDstRect,
WebCoreCompositeToSkiaComposite(compositeOp));
}
@@ -447,7 +447,7 @@ void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
paintSkBitmap(ctxt->platformContext(),
m_nativeImage,
enclosingIntRect(normSrcRect),
- enclosingIntRect(normDstRect),
+ normDstRect,
WebCoreCompositeToSkiaComposite(compositeOp));
}
diff --git a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
index f77620b..b5f7e1d 100644
--- a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
@@ -100,16 +100,16 @@ ImageSource::~ImageSource()
void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
{
- // TODO(darin): Figure out what to do with the |data| and |allDataReceived| params.
-
- if (destroyAll) {
- delete m_decoder;
- m_decoder = 0;
+ if (!destroyAll) {
+ if (m_decoder)
+ m_decoder->clearFrameBufferCache(clearBeforeFrame);
return;
}
- if (m_decoder)
- m_decoder->clearFrameBufferCache(clearBeforeFrame);
+ delete m_decoder;
+ m_decoder = 0;
+ if (data)
+ setData(data, allDataReceived);
}
bool ImageSource::initialized() const
diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp
index ca99322..2700da8 100644
--- a/WebCore/platform/graphics/skia/PathSkia.cpp
+++ b/WebCore/platform/graphics/skia/PathSkia.cpp
@@ -274,7 +274,7 @@ static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context)
SkPaint paint;
context->platformContext()->setupPaintForStroking(&paint, 0, 0);
SkPath boundingPath;
- paint.getFillPath(context->platformContext()->currentPath(), &boundingPath);
+ paint.getFillPath(context->platformContext()->currentPathInLocalCoordinates(), &boundingPath);
SkRect r;
boundingPath.computeBounds(&r, SkPath::kExact_BoundsType);
return r;
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
index 60dbbe0..6c633f2 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -31,6 +31,7 @@
#include "config.h"
#include "GraphicsContext.h"
+#include "ImageBuffer.h"
#include "NativeImageSkia.h"
#include "PlatformContextSkia.h"
#include "SkiaUtils.h"
@@ -45,10 +46,6 @@
#include <wtf/MathExtras.h>
-#if defined(__linux__)
-#include "GdkSkia.h"
-#endif
-
// State -----------------------------------------------------------------------
// Encapsulates the additional painting state information we store for each
@@ -86,6 +83,13 @@ struct PlatformContextSkia::State {
// color to produce a new output color.
SkColor applyAlpha(SkColor) const;
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ // If non-empty, the current State is clipped to this image.
+ SkBitmap m_imageBufferClip;
+ // If m_imageBufferClip is non-empty, this is the region the image is clipped to.
+ WebCore::FloatRect m_clip;
+#endif
+
private:
// Not supported.
void operator=(const State&);
@@ -113,9 +117,28 @@ PlatformContextSkia::State::State()
}
PlatformContextSkia::State::State(const State& other)
+ : m_alpha(other.m_alpha)
+ , m_porterDuffMode(other.m_porterDuffMode)
+ , m_gradient(other.m_gradient)
+ , m_pattern(other.m_pattern)
+ , m_useAntialiasing(other.m_useAntialiasing)
+ , m_looper(other.m_looper)
+ , m_fillColor(other.m_fillColor)
+ , m_strokeStyle(other.m_strokeStyle)
+ , m_strokeColor(other.m_strokeColor)
+ , m_strokeThickness(other.m_strokeThickness)
+ , m_dashRatio(other.m_dashRatio)
+ , m_miterLimit(other.m_miterLimit)
+ , m_lineCap(other.m_lineCap)
+ , m_lineJoin(other.m_lineJoin)
+ , m_dash(other.m_dash)
+ , m_textDrawingMode(other.m_textDrawingMode)
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ , m_imageBufferClip(other.m_imageBufferClip)
+ , m_clip(other.m_clip)
+#endif
{
- memcpy(this, &other, sizeof(State));
-
+ // Up the ref count of these. saveRef does nothing if 'this' is NULL.
m_looper->safeRef();
m_dash->safeRef();
m_gradient->safeRef();
@@ -148,22 +171,16 @@ SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
: m_canvas(canvas)
, m_stateStack(sizeof(State))
+#if PLATFORM(WIN_OS)
+ , m_drawingToImageBuffer(false)
+#endif
{
m_stateStack.append(State());
m_state = &m_stateStack.last();
-#if defined(OS_LINUX)
- m_gdkskia = m_canvas ? gdk_skia_new(m_canvas) : 0;
-#endif
}
PlatformContextSkia::~PlatformContextSkia()
{
-#if defined(OS_LINUX)
- if (m_gdkskia) {
- g_object_unref(m_gdkskia);
- m_gdkskia = 0;
- }
-#endif
}
void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
@@ -171,17 +188,72 @@ void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
m_canvas = canvas;
}
+#if PLATFORM(WIN_OS)
+void PlatformContextSkia::setDrawingToImageBuffer(bool value)
+{
+ m_drawingToImageBuffer = value;
+}
+
+bool PlatformContextSkia::isDrawingToImageBuffer() const
+{
+ return m_drawingToImageBuffer;
+}
+#endif
+
void PlatformContextSkia::save()
{
m_stateStack.append(*m_state);
m_state = &m_stateStack.last();
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ // The clip image only needs to be applied once. Reset the image so that we
+ // don't attempt to clip multiple times.
+ m_state->m_imageBufferClip.reset();
+#endif
+
// Save our native canvas.
canvas()->save();
}
+#if defined(__linux__) || PLATFORM(WIN_OS)
+void PlatformContextSkia::beginLayerClippedToImage(const WebCore::FloatRect& rect,
+ const WebCore::ImageBuffer* imageBuffer)
+{
+ // Skia doesn't support clipping to an image, so we create a layer. The next
+ // time restore is invoked the layer and |imageBuffer| are combined to
+ // create the resulting image.
+ m_state->m_clip = rect;
+ SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
+ SkFloatToScalar(rect.right()), SkFloatToScalar(rect.bottom()) };
+
+ canvas()->saveLayerAlpha(&bounds, 255,
+ static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+ // Copy off the image as |imageBuffer| may be deleted before restore is invoked.
+ const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap();
+ if (!bitmap->pixelRef()) {
+ // The bitmap owns it's pixels. This happens when we've allocated the
+ // pixels in some way and assigned them directly to the bitmap (as
+ // happens when we allocate a DIB). In this case the assignment operator
+ // does not copy the pixels, rather the copied bitmap ends up
+ // referencing the same pixels. As the pixels may not live as long as we
+ // need it to, we copy the image.
+ bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config);
+ } else {
+ // If there is a pixel ref, we can safely use the assignment operator.
+ m_state->m_imageBufferClip = *bitmap;
+ }
+}
+#endif
+
void PlatformContextSkia::restore()
{
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ if (!m_state->m_imageBufferClip.empty()) {
+ applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip);
+ canvas()->restore();
+ }
+#endif
+
m_stateStack.removeLast();
m_state = &m_stateStack.last();
@@ -200,12 +272,21 @@ void PlatformContextSkia::drawRect(SkRect rect)
if (m_state->m_strokeStyle != WebCore::NoStroke &&
(m_state->m_strokeColor & 0xFF000000)) {
- if (fillcolorNotTransparent) {
- // This call is expensive so don't call it unnecessarily.
- paint.reset();
- }
- setupPaintForStroking(&paint, &rect, 0);
- canvas()->drawRect(rect, paint);
+ // We do a fill of four rects to simulate the stroke of a border.
+ SkColor oldFillColor = m_state->m_fillColor;
+ if (oldFillColor != m_state->m_strokeColor)
+ setFillColor(m_state->m_strokeColor);
+ setupPaintForFilling(&paint);
+ SkRect topBorder = { rect.fLeft, rect.fTop, rect.width(), 1 };
+ canvas()->drawRect(topBorder, paint);
+ SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.width(), 1 };
+ canvas()->drawRect(bottomBorder, paint);
+ SkRect leftBorder = { rect.fLeft, rect.fTop + 1, 1, rect.height() - 2 };
+ canvas()->drawRect(leftBorder, paint);
+ SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, 1, rect.height() - 2 };
+ canvas()->drawRect(rightBorder, paint);
+ if (oldFillColor != m_state->m_strokeColor)
+ setFillColor(oldFillColor);
}
}
@@ -239,10 +320,6 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
setupPaintCommon(paint);
float width = m_state->m_strokeThickness;
- // This allows dashing and dotting to work properly for hairline strokes.
- if (width == 0)
- width = 1;
-
paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
paint->setStyle(SkPaint::kStroke_Style);
paint->setStrokeWidth(SkFloatToScalar(width));
@@ -250,9 +327,6 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
paint->setStrokeJoin(m_state->m_lineJoin);
paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
- if (rect != 0 && (static_cast<int>(roundf(width)) & 1))
- rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
-
if (m_state->m_dash)
paint->setPathEffect(m_state->m_dash);
else {
@@ -267,7 +341,8 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
SkScalar dashLength;
if (length) {
// Determine about how many dashes or dots we should have.
- int numDashes = length / roundf(width);
+ float roundedWidth = roundf(width);
+ int numDashes = roundedWidth ? (length / roundedWidth) : length;
if (!(numDashes & 1))
numDashes++; // Make it odd so we end on a dash/dot.
// Use the number of dashes to determine the length of a
@@ -366,9 +441,14 @@ void PlatformContextSkia::setUseAntialiasing(bool enable)
m_state->m_useAntialiasing = enable;
}
-SkColor PlatformContextSkia::fillColor() const
+SkColor PlatformContextSkia::effectiveFillColor() const
{
- return m_state->m_fillColor;
+ return m_state->applyAlpha(m_state->m_fillColor);
+}
+
+SkColor PlatformContextSkia::effectiveStrokeColor() const
+{
+ return m_state->applyAlpha(m_state->m_strokeColor);
}
void PlatformContextSkia::beginPath()
@@ -378,7 +458,17 @@ void PlatformContextSkia::beginPath()
void PlatformContextSkia::addPath(const SkPath& path)
{
- m_path.addPath(path);
+ m_path.addPath(path, m_canvas->getTotalMatrix());
+}
+
+SkPath PlatformContextSkia::currentPathInLocalCoordinates() const
+{
+ SkPath localPath = m_path;
+ const SkMatrix& matrix = m_canvas->getTotalMatrix();
+ SkMatrix inverseMatrix;
+ matrix.invert(&inverseMatrix);
+ localPath.transform(inverseMatrix);
+ return localPath;
}
void PlatformContextSkia::setFillRule(SkPath::FillType fr)
@@ -425,3 +515,14 @@ bool PlatformContextSkia::isPrinting()
{
return m_canvas->getTopPlatformDevice().IsVectorial();
}
+
+#if defined(__linux__) || PLATFORM(WIN_OS)
+void PlatformContextSkia::applyClipFromImage(const WebCore::FloatRect& rect, const SkBitmap& imageBuffer)
+{
+ // NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we
+ // only look at the alpha when compositing. I'm not 100% sure this is what WebKit expects for image clipping.
+ SkPaint paint;
+ paint.setPorterDuffXfermode(SkPorterDuff::kDstIn_Mode);
+ m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint);
+}
+#endif
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h
index 78e9a19..8850a6a 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.h
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h
@@ -43,8 +43,6 @@
#include <wtf/Vector.h>
-typedef struct _GdkDrawable GdkSkia;
-
// This class holds the platform-specific state for GraphicsContext. We put
// most of our Skia wrappers on this class. In theory, a lot of this stuff could
// be moved to GraphicsContext directly, except that some code external to this
@@ -73,9 +71,28 @@ public:
// to the constructor.
void setCanvas(skia::PlatformCanvas*);
+#if PLATFORM(WIN_OS)
+ // If false we're rendering to a GraphicsContext for a web page, if false
+ // we're not (as is the case when rendering to a canvas object).
+ // If this is true the contents have not been marked up with the magic
+ // color and all text drawing needs to go to a layer so that the alpha is
+ // correctly updated.
+ void setDrawingToImageBuffer(bool);
+ bool isDrawingToImageBuffer() const;
+#endif
+
void save();
void restore();
+ // Begins a layer that is clipped to the image |imageBuffer| at the location
+ // |rect|. This layer is implicitly restored when the next restore is
+ // invoked.
+ // NOTE: |imageBuffer| may be deleted before the |restore| is invoked.
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ void beginLayerClippedToImage(const WebCore::FloatRect&,
+ const WebCore::ImageBuffer*);
+#endif
+
// Sets up the common flags on a paint for antialiasing, effects, etc.
// This is implicitly called by setupPaintFill and setupPaintStroke, but
// you may wish to call it directly sometimes if you don't want that other
@@ -116,9 +133,15 @@ public:
void beginPath();
void addPath(const SkPath&);
- const SkPath* currentPath() const { return &m_path; }
+ SkPath currentPathInLocalCoordinates() const;
+
+ // Returns the fill color. The returned color has it's alpha adjusted
+ // by the current alpha.
+ SkColor effectiveFillColor() const;
- SkColor fillColor() const;
+ // Returns the stroke color. The returned color has it's alpha adjusted
+ // by the current alpha.
+ SkColor effectiveStrokeColor() const;
skia::PlatformCanvas* canvas() { return m_canvas; }
@@ -142,12 +165,13 @@ public:
// possible quality.
bool isPrinting();
-#if defined(__linux__)
- // FIXME: should be camelCase.
- GdkSkia* gdk_skia() const { return m_gdkskia; }
+private:
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ // Used when restoring and the state has an image clip. Only shows the pixels in
+ // m_canvas that are also in imageBuffer.
+ void applyClipFromImage(const WebCore::FloatRect&, const SkBitmap&);
#endif
-private:
// Defines drawing style.
struct State;
@@ -161,12 +185,11 @@ private:
// mStateStack.back().
State* m_state;
- // Current path.
+ // Current path in global coordinates.
SkPath m_path;
-#if defined(__linux__)
- // A pointer to a GDK Drawable wrapping of this Skia canvas
- GdkSkia* m_gdkskia;
+#if PLATFORM(WIN_OS)
+ bool m_drawingToImageBuffer;
#endif
};
diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/WebCore/platform/graphics/skia/SkiaFontWin.cpp
index 6e79a7e..d0cd4c5 100644
--- a/WebCore/platform/graphics/skia/SkiaFontWin.cpp
+++ b/WebCore/platform/graphics/skia/SkiaFontWin.cpp
@@ -31,8 +31,13 @@
#include "config.h"
#include "SkiaFontWin.h"
+#include "PlatformContextSkia.h"
+#include "Gradient.h"
+#include "Pattern.h"
#include "SkCanvas.h"
#include "SkPaint.h"
+#include "SkShader.h"
+#include "TransformationMatrix.h"
#include <wtf/ListHashSet.h>
#include <wtf/Vector.h>
@@ -162,10 +167,10 @@ static bool getPathForGlyph(HDC dc, WORD glyph, SkPath* path)
addPolyCurveToPath(polyCurve, path);
curPoly += sizeof(WORD) * 2 + sizeof(POINTFX) * polyCurve->cpfx;
}
+ path->close();
curGlyph += polyHeader->cb;
}
- path->close();
return true;
}
@@ -215,4 +220,152 @@ void SkiaWinOutlineCache::removePathsForFont(HFONT hfont)
deleteOutline(outlineCache.find(*i));
}
+bool windowsCanHandleTextDrawing(GraphicsContext* context)
+{
+ // Check for non-translation transforms. Sometimes zooms will look better in
+ // Skia, and sometimes better in Windows. The main problem is that zooming
+ // in using Skia will show you the hinted outlines for the smaller size,
+ // which look weird. All else being equal, it's better to use Windows' text
+ // drawing, so we don't check for zooms.
+ const TransformationMatrix& matrix = context->getCTM();
+ if (matrix.b() != 0 || matrix.c() != 0) // Check for skew.
+ return false;
+
+ // Check for stroke effects.
+ if (context->platformContext()->getTextDrawingMode() != cTextFill)
+ return false;
+
+ // Check for gradients.
+ if (context->fillGradient() || context->strokeGradient())
+ return false;
+
+ // Check for patterns.
+ if (context->fillPattern() || context->strokePattern())
+ return false;
+
+ // Check for shadow effects.
+ if (context->platformContext()->getDrawLooper())
+ return false;
+
+ return true;
+}
+
+// Draws the given text string using skia. Note that gradient or
+// pattern may be NULL, in which case a solid colour is used.
+static bool skiaDrawText(HFONT hfont,
+ HDC dc,
+ SkCanvas* canvas,
+ const SkPoint& point,
+ SkPaint* paint,
+ const TransformationMatrix& transformationMatrix,
+ Gradient* gradient,
+ Pattern* pattern,
+ const WORD* glyphs,
+ const int* advances,
+ const GOFFSET* offsets,
+ int numGlyphs)
+{
+ SkShader* shader = NULL;
+ if (gradient)
+ shader = gradient->platformGradient();
+ else if (pattern)
+ shader = pattern->createPlatformPattern(transformationMatrix);
+
+ paint->setShader(shader);
+ float x = point.fX, y = point.fY;
+
+ for (int i = 0; i < numGlyphs; i++) {
+ const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]);
+ if (!path)
+ return false;
+
+ float offsetX = 0.0f, offsetY = 0.0f;
+ if (offsets && (offsets[i].du != 0 || offsets[i].dv != 0)) {
+ offsetX = offsets[i].du;
+ offsetY = offsets[i].dv;
+ }
+
+ SkPath newPath;
+ newPath.addPath(*path, x + offsetX, y + offsetY);
+ canvas->drawPath(newPath, *paint);
+
+ x += advances[i];
+ }
+
+ return true;
+}
+
+bool paintSkiaText(GraphicsContext* context,
+ HFONT hfont,
+ int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ const GOFFSET* offsets,
+ const SkPoint* origin)
+{
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, hfont);
+
+ PlatformContextSkia* platformContext = context->platformContext();
+ int textMode = platformContext->getTextDrawingMode();
+
+ // Filling (if necessary). This is the common case.
+ SkPaint paint;
+ platformContext->setupPaintForFilling(&paint);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ bool didFill = false;
+
+ if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) {
+ Gradient* fillGradient = 0;
+ Pattern* fillPattern = 0;
+ if (context->fillColorSpace() == GradientColorSpace)
+ fillGradient = context->fillGradient();
+ else if (context->fillColorSpace() == PatternColorSpace)
+ fillPattern = context->fillPattern();
+ if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,
+ context->getCTM(), fillGradient, fillPattern,
+ &glyphs[0], &advances[0], &offsets[0], numGlyphs))
+ return false;
+ didFill = true;
+ }
+
+ // Stroking on top (if necessary).
+ if ((textMode & WebCore::cTextStroke)
+ && platformContext->getStrokeStyle() != NoStroke
+ && platformContext->getStrokeThickness() > 0) {
+
+ paint.reset();
+ platformContext->setupPaintForStroking(&paint, 0, 0);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ if (didFill) {
+ // If there is a shadow and we filled above, there will already be
+ // a shadow. We don't want to draw it again or it will be too dark
+ // and it will go on top of the fill.
+ //
+ // Note that this isn't strictly correct, since the stroke could be
+ // very thick and the shadow wouldn't account for this. The "right"
+ // thing would be to draw to a new layer and then draw that layer
+ // with a shadow. But this is a lot of extra work for something
+ // that isn't normally an issue.
+ paint.setLooper(0)->safeUnref();
+ }
+
+ Gradient* strokeGradient = 0;
+ Pattern* strokePattern = 0;
+ if (context->strokeColorSpace() == GradientColorSpace)
+ strokeGradient = context->strokeGradient();
+ else if (context->strokeColorSpace() == PatternColorSpace)
+ strokePattern = context->strokePattern();
+ if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,
+ context->getCTM(), strokeGradient, strokePattern,
+ &glyphs[0], &advances[0], &offsets[0], numGlyphs))
+ return false;
+ }
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ return true;
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.h b/WebCore/platform/graphics/skia/SkiaFontWin.h
index 2adab39..0e0c953 100644
--- a/WebCore/platform/graphics/skia/SkiaFontWin.h
+++ b/WebCore/platform/graphics/skia/SkiaFontWin.h
@@ -32,8 +32,12 @@
#define SkiaWinOutlineCache_h
#include <windows.h>
+#include <usp10.h>
+class GraphicsContext;
class SkPath;
+class SkPoint;
+class PlatformContextSkia;
namespace WebCore {
@@ -49,6 +53,37 @@ private:
SkiaWinOutlineCache();
};
+// The functions below are used for more complex font drawing (effects such as
+// stroking and more complex transforms) than Windows supports directly. Since
+// Windows drawing is faster you should use windowsCanHandleTextDrawing first to
+// check if using Skia is required at all.
+// Note that the text will look different (no ClearType) so this should only be
+// used when necessary.
+//
+// When you call a Skia* text drawing function, various glyph outlines will be
+// cached. As a result, you should call SkiaWinOutlineCache::removePathsForFont
+// when the font is destroyed so that the cache does not outlive the font (since
+// the HFONTs are recycled).
+//
+// Remember that Skia's text drawing origin is the baseline, like WebKit, not
+// the top, like Windows.
+
+// Returns true if advanced font rendering is recommended.
+bool windowsCanHandleTextDrawing(GraphicsContext* context);
+
+// Note that the offsets parameter is optional. If not NULL it represents a
+// per glyph offset (such as returned by ScriptPlace Windows API function).
+//
+// Returns true of the text was drawn successfully. False indicates an error
+// from Windows.
+bool paintSkiaText(GraphicsContext* graphicsContext,
+ HFONT hfont,
+ int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ const GOFFSET* offsets,
+ const SkPoint* origin);
+
} // namespace WebCore
#endif // SkiaWinOutlineCache_h
diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp
index 6d9ffe2..55cba37 100644
--- a/WebCore/platform/graphics/skia/SkiaUtils.cpp
+++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp
@@ -38,6 +38,7 @@
#include "SkColorPriv.h"
#include "SkMatrix.h"
#include "SkRegion.h"
+#include "SkUnPreMultiply.h"
namespace WebCore {
@@ -74,29 +75,12 @@ SkPorterDuff::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op)
return SkPorterDuff::kSrcOver_Mode; // fall-back
}
-static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
-{
- SkASSERT(component == (uint8_t)component);
- return (component * scale + 0x8000) >> 16;
-}
-
-SkColor SkPMColorToColor(SkPMColor pm)
-{
- if (0 == pm)
- return 0;
-
- unsigned a = SkGetPackedA32(pm);
- uint32_t scale = (255 << 16) / a;
-
- return SkColorSetARGB(a,
- InvScaleByte(SkGetPackedR32(pm), scale),
- InvScaleByte(SkGetPackedG32(pm), scale),
- InvScaleByte(SkGetPackedB32(pm), scale));
-}
-
Color SkPMColorToWebCoreColor(SkPMColor pm)
{
- return SkPMColorToColor(pm);
+ SkColor c = SkUnPreMultiply::PMColorToColor(pm);
+ // need the cast to find the right constructor
+ return WebCore::Color((int)SkColorGetR(c), (int)SkColorGetG(c),
+ (int)SkColorGetB(c), (int)SkColorGetA(c));
}
void IntersectRectAndRegion(const SkRegion& region, const SkRect& srcRect, SkRect* destRect) {
@@ -151,7 +135,12 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::
int scale = 1;
SkRect bounds;
+#if PLATFORM(SGL)
+ // this is the API from skia/trunk
+ bounds = originalPath->getBounds();
+#else
originalPath->computeBounds(&bounds, SkPath::kFast_BoundsType);
+#endif
// We can immediately return false if the point is outside the bounding rect
if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y())))
diff --git a/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp b/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
index 1e2a194..2d0f9f8 100644
--- a/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
+++ b/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
@@ -30,193 +30,28 @@
#include "config.h"
#include "TransformationMatrix.h"
-#include "FloatRect.h"
-#include "IntRect.h"
-
#include "SkiaUtils.h"
namespace WebCore {
-TransformationMatrix::TransformationMatrix()
-{
- m_transform.reset();
-}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double e, double f)
-{
- setMatrix(a, b, c, d, e, f);
-}
-
-TransformationMatrix::TransformationMatrix(const SkMatrix& matrix)
- : m_transform(matrix)
-{
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double e, double f)
-{
- m_transform.reset();
-
- m_transform.setScaleX(WebCoreDoubleToSkScalar(a));
- m_transform.setSkewX(WebCoreDoubleToSkScalar(c));
- m_transform.setTranslateX(WebCoreDoubleToSkScalar(e));
-
- m_transform.setScaleY(WebCoreDoubleToSkScalar(d));
- m_transform.setSkewY(WebCoreDoubleToSkScalar(b));
- m_transform.setTranslateY(WebCoreDoubleToSkScalar(f));
-}
-
-void TransformationMatrix::map(double x, double y, double* x2, double* y2) const
-{
- SkPoint src, dst;
- src.set(WebCoreDoubleToSkScalar(x), WebCoreDoubleToSkScalar(y));
- m_transform.mapPoints(&dst, &src, 1);
-
- *x2 = SkScalarToDouble(dst.fX);
- *y2 = SkScalarToDouble(dst.fY);
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect& src) const
-{
- SkRect dst;
- m_transform.mapRect(&dst, src);
- return enclosingIntRect(dst);
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect& src) const
-{
- SkRect dst;
- m_transform.mapRect(&dst, src);
- return dst;
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return m_transform.isIdentity();
-}
-
-void TransformationMatrix::reset()
-{
- m_transform.reset();
-}
-
-TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
-{
- m_transform.preScale(WebCoreDoubleToSkScalar(sx), WebCoreDoubleToSkScalar(sy), 0, 0);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::rotate(double d)
-{
- m_transform.preRotate(WebCoreDoubleToSkScalar(d), 0, 0);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
-{
- m_transform.preTranslate(WebCoreDoubleToSkScalar(tx), WebCoreDoubleToSkScalar(ty));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
-{
- m_transform.preSkew(WebCoreDoubleToSkScalar(sx), WebCoreDoubleToSkScalar(sy), 0, 0);
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return SkScalarToDouble(m_transform.getScaleX()) * SkScalarToDouble(m_transform.getScaleY()) -
- SkScalarToDouble(m_transform.getSkewY()) * SkScalarToDouble(m_transform.getSkewX());
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- TransformationMatrix inverse;
- m_transform.invert(&inverse.m_transform);
- return inverse;
-}
-
TransformationMatrix::operator SkMatrix() const
{
- return m_transform;
-}
-
-bool TransformationMatrix::operator==(const TransformationMatrix& m2) const
-{
- return m_transform == m2.m_transform;
-}
+ SkMatrix result;
-TransformationMatrix &TransformationMatrix::operator*=(const TransformationMatrix& m2)
-{
- m_transform.setConcat(m2.m_transform, m_transform);
- return *this;
-}
+ result.setScaleX(WebCoreDoubleToSkScalar(a()));
+ result.setSkewX(WebCoreDoubleToSkScalar(c()));
+ result.setTranslateX(WebCoreDoubleToSkScalar(e()));
-TransformationMatrix TransformationMatrix::operator*(const TransformationMatrix& m2)
-{
- TransformationMatrix cat;
- cat.m_transform.setConcat(m2.m_transform, m_transform);
- return cat;
-}
+ result.setScaleY(WebCoreDoubleToSkScalar(d()));
+ result.setSkewY(WebCoreDoubleToSkScalar(b()));
+ result.setTranslateY(WebCoreDoubleToSkScalar(f()));
-double TransformationMatrix::a() const
-{
- return SkScalarToDouble(m_transform.getScaleX());
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.setScaleX(WebCoreDoubleToSkScalar(a));
-}
-
-double TransformationMatrix::b() const
-{
- return SkScalarToDouble(m_transform.getSkewY());
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.setSkewY(WebCoreDoubleToSkScalar(b));
-}
+ // FIXME: Set perspective properly.
+ result.setPerspX(0);
+ result.setPerspY(0);
+ result.set(SkMatrix::kMPersp2, SK_Scalar1);
-double TransformationMatrix::c() const
-{
- return SkScalarToDouble(m_transform.getSkewX());
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.setSkewX(WebCoreDoubleToSkScalar(c));
-}
-
-double TransformationMatrix::d() const
-{
- return SkScalarToDouble(m_transform.getScaleY());
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.setScaleY(WebCoreDoubleToSkScalar(d));
-}
-
-double TransformationMatrix::e() const
-{
- return SkScalarToDouble(m_transform.getTranslateX());
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.setTranslateX(WebCoreDoubleToSkScalar(e));
-}
-
-double TransformationMatrix::f() const
-{
- return SkScalarToDouble(m_transform.getTranslateY());
-}
-
-void TransformationMatrix::setF(double f)
-{
- m_transform.setTranslateY(WebCoreDoubleToSkScalar(f));
+ return result;
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp
new file mode 100644
index 0000000..ab3413b
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Matrix3DTransformOperation.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> Matrix3DTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ // Convert the TransformOperations into matrices
+ IntSize size;
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ if (from)
+ from->apply(fromT, size);
+
+ apply(toT, size);
+
+ if (blendToIdentity)
+ swap(fromT, toT);
+
+ toT.blend(fromT, progress);
+ return Matrix3DTransformOperation::create(toT);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h
new file mode 100644
index 0000000..7430dbc
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Matrix3DTransformOperation_h
+#define Matrix3DTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class Matrix3DTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<Matrix3DTransformOperation> create(const TransformationMatrix& matrix)
+ {
+ return adoptRef(new Matrix3DTransformOperation(matrix));
+ }
+
+private:
+ virtual bool isIdentity() const { return m_matrix.isIdentity(); }
+
+ virtual OperationType getOperationType() const { return MATRIX_3D; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX_3D; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const Matrix3DTransformOperation* m = static_cast<const Matrix3DTransformOperation*>(&o);
+ return m_matrix == m->m_matrix;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.multLeft(TransformationMatrix(m_matrix));
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ Matrix3DTransformOperation(const TransformationMatrix& mat)
+ {
+ m_matrix = mat;
+ }
+
+ TransformationMatrix m_matrix;
+};
+
+} // namespace WebCore
+
+#endif // Matrix3DTransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
index 153d96d..4934fa6 100644
--- a/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
@@ -24,6 +24,8 @@
#include <algorithm>
+using namespace std;
+
namespace WebCore {
PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
@@ -41,7 +43,7 @@ PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOp
}
if (blendToIdentity)
- std::swap(fromT, toT);
+ swap(fromT, toT);
toT.blend(fromT, progress);
return MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f());
diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
index d272229..ee47a11 100644
--- a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
@@ -26,6 +26,7 @@
#define MatrixTransformOperation_h
#include "TransformOperation.h"
+#include "TransformationMatrix.h"
namespace WebCore {
@@ -36,8 +37,14 @@ public:
return adoptRef(new MatrixTransformOperation(a, b, c, d, e, f));
}
+ static PassRefPtr<MatrixTransformOperation> create(const TransformationMatrix& t)
+ {
+ return adoptRef(new MatrixTransformOperation(t));
+ }
+
private:
virtual bool isIdentity() const { return m_a == 1 && m_b == 0 && m_c == 0 && m_d == 1 && m_e == 0 && m_f == 0; }
+
virtual OperationType getOperationType() const { return MATRIX; }
virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX; }
@@ -53,7 +60,7 @@ private:
virtual bool apply(TransformationMatrix& transform, const IntSize&) const
{
TransformationMatrix matrix(m_a, m_b, m_c, m_d, m_e, m_f);
- transform = matrix * transform;
+ transform.multLeft(TransformationMatrix(matrix));
return false;
}
@@ -68,6 +75,16 @@ private:
, m_f(f)
{
}
+
+ MatrixTransformOperation(const TransformationMatrix& t)
+ : m_a(t.a())
+ , m_b(t.b())
+ , m_c(t.c())
+ , m_d(t.d())
+ , m_e(t.e())
+ , m_f(t.f())
+ {
+ }
double m_a;
double m_b;
diff --git a/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp
new file mode 100644
index 0000000..9fd03a1
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PerspectiveTransformOperation.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> PerspectiveTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return PerspectiveTransformOperation::create(m_p + (1. - m_p) * progress);
+
+ const PerspectiveTransformOperation* fromOp = static_cast<const PerspectiveTransformOperation*>(from);
+ double fromP = fromOp ? fromOp->m_p : 0;
+ double toP = m_p;
+
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ fromT.applyPerspective(fromP);
+ toT.applyPerspective(toP);
+ toT.blend(fromT, progress);
+ TransformationMatrix::DecomposedType decomp;
+ toT.decompose(decomp);
+
+ return PerspectiveTransformOperation::create(decomp.perspectiveZ ? -1.0 / decomp.perspectiveZ : 0.0);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h
new file mode 100644
index 0000000..a665f3e
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PerspectiveTransformOperation_h
+#define PerspectiveTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class PerspectiveTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<PerspectiveTransformOperation> create(double p)
+ {
+ return adoptRef(new PerspectiveTransformOperation(p));
+ }
+
+private:
+ virtual bool isIdentity() const { return m_p == 0; }
+ virtual OperationType getOperationType() const { return PERSPECTIVE; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == PERSPECTIVE; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const PerspectiveTransformOperation* p = static_cast<const PerspectiveTransformOperation*>(&o);
+ return m_p == p->m_p;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.applyPerspective(m_p);
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ PerspectiveTransformOperation(double p)
+ : m_p(p)
+ {
+ }
+
+ double m_p;
+};
+
+} // namespace WebCore
+
+#endif // PerspectiveTransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp b/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
index 4887cee..919d174 100644
--- a/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
@@ -22,6 +22,11 @@
#include "config.h"
#include "RotateTransformOperation.h"
+#include <algorithm>
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
namespace WebCore {
PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
@@ -30,11 +35,61 @@ PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOp
return this;
if (blendToIdentity)
- return RotateTransformOperation::create(m_angle - m_angle * progress, m_type);
+ return RotateTransformOperation::create(m_x, m_y, m_z, m_angle - m_angle * progress, m_type);
const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from);
- double fromAngle = fromOp ? fromOp->m_angle : 0;
- return RotateTransformOperation::create(fromAngle + (m_angle - fromAngle) * progress, m_type);
+
+ // Optimize for single axis rotation
+ if (!fromOp || (fromOp->m_x == 0 && fromOp->m_y == 0 && fromOp->m_z == 1) ||
+ (fromOp->m_x == 0 && fromOp->m_y == 1 && fromOp->m_z == 0) ||
+ (fromOp->m_x == 1 && fromOp->m_y == 0 && fromOp->m_z == 0)) {
+ double fromAngle = fromOp ? fromOp->m_angle : 0;
+ return RotateTransformOperation::create(fromOp ? fromOp->m_x : m_x,
+ fromOp ? fromOp->m_y : m_y,
+ fromOp ? fromOp->m_z : m_z,
+ fromAngle + (m_angle - fromAngle) * progress, m_type);
+ }
+
+ const RotateTransformOperation* toOp = this;
+
+ // Create the 2 rotation matrices
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ fromT.rotate3d((float)(fromOp ? fromOp->m_x : 0),
+ (float)(fromOp ? fromOp->m_y : 0),
+ (float)(fromOp ? fromOp->m_z : 1),
+ (float)(fromOp ? fromOp->m_angle : 0));
+
+ toT.rotate3d((float)(toOp ? toOp->m_x : 0),
+ (float)(toOp ? toOp->m_y : 0),
+ (float)(toOp ? toOp->m_z : 1),
+ (float)(toOp ? toOp->m_angle : 0));
+
+ // Blend them
+ toT.blend(fromT, progress);
+
+ // Extract the result as a quaternion
+ TransformationMatrix::DecomposedType decomp;
+ toT.decompose(decomp);
+
+ // Convert that to Axis/Angle form
+ double x = -decomp.quaternionX;
+ double y = -decomp.quaternionY;
+ double z = -decomp.quaternionZ;
+ double length = sqrt(x * x + y * y + z * z);
+ double angle = 0;
+
+ if (length > 0.00001) {
+ x /= length;
+ y /= length;
+ z /= length;
+ angle = rad2deg(acos(decomp.quaternionW) * 2);
+ } else {
+ x = 0;
+ y = 0;
+ z = 1;
+ }
+ return RotateTransformOperation::create(x, y, z, angle, ROTATE_3D);
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.h b/WebCore/platform/graphics/transforms/RotateTransformOperation.h
index adc6c4c..699ea43 100644
--- a/WebCore/platform/graphics/transforms/RotateTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.h
@@ -33,10 +33,19 @@ class RotateTransformOperation : public TransformOperation {
public:
static PassRefPtr<RotateTransformOperation> create(double angle, OperationType type)
{
- return adoptRef(new RotateTransformOperation(angle, type));
+ return adoptRef(new RotateTransformOperation(0, 0, 1, angle, type));
}
+ static PassRefPtr<RotateTransformOperation> create(double x, double y, double z, double angle, OperationType type)
+ {
+ return adoptRef(new RotateTransformOperation(x, y, z, angle, type));
+ }
+
+ double angle() const { return m_angle; }
+
+private:
virtual bool isIdentity() const { return m_angle == 0; }
+
virtual OperationType getOperationType() const { return m_type; }
virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
@@ -45,26 +54,30 @@ public:
if (!isSameType(o))
return false;
const RotateTransformOperation* r = static_cast<const RotateTransformOperation*>(&o);
- return m_angle == r->m_angle;
+ return m_x == r->m_x && m_y == r->m_y && m_z == r->m_z && m_angle == r->m_angle;
}
virtual bool apply(TransformationMatrix& transform, const IntSize& /*borderBoxSize*/) const
{
- transform.rotate(m_angle);
+ transform.rotate3d(m_x, m_y, m_z, m_angle);
return false;
}
virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
- double angle() const { return m_angle; }
-
-private:
- RotateTransformOperation(double angle, OperationType type)
- : m_angle(angle)
+ RotateTransformOperation(double x, double y, double z, double angle, OperationType type)
+ : m_x(x)
+ , m_y(y)
+ , m_z(z)
+ , m_angle(angle)
, m_type(type)
{
+ ASSERT(type == ROTATE_X || type == ROTATE_Y || type == ROTATE_Z || type == ROTATE_3D);
}
+ double m_x;
+ double m_y;
+ double m_z;
double m_angle;
OperationType m_type;
};
diff --git a/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp b/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
index 49a8fd8..45d119c 100644
--- a/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
@@ -30,12 +30,17 @@ PassRefPtr<TransformOperation> ScaleTransformOperation::blend(const TransformOpe
return this;
if (blendToIdentity)
- return ScaleTransformOperation::create(m_x + (1. - m_x) * progress, m_y + (1. - m_y) * progress, m_type);
+ return ScaleTransformOperation::create(m_x + (1. - m_x) * progress,
+ m_y + (1. - m_y) * progress,
+ m_z + (1. - m_z) * progress, m_type);
const ScaleTransformOperation* fromOp = static_cast<const ScaleTransformOperation*>(from);
double fromX = fromOp ? fromOp->m_x : 1.;
double fromY = fromOp ? fromOp->m_y : 1.;
- return ScaleTransformOperation::create(fromX + (m_x - fromX) * progress, fromY + (m_y - fromY) * progress, m_type);
+ double fromZ = fromOp ? fromOp->m_z : 1.;
+ return ScaleTransformOperation::create(fromX + (m_x - fromX) * progress,
+ fromY + (m_y - fromY) * progress,
+ fromZ + (m_z - fromZ) * progress, m_type);
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/ScaleTransformOperation.h b/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
index 289f8a1..a87bb3b 100644
--- a/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
@@ -33,11 +33,21 @@ class ScaleTransformOperation : public TransformOperation {
public:
static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, OperationType type)
{
- return adoptRef(new ScaleTransformOperation(sx, sy, type));
+ return adoptRef(new ScaleTransformOperation(sx, sy, 1, type));
}
+ static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, double sz, OperationType type)
+ {
+ return adoptRef(new ScaleTransformOperation(sx, sy, sz, type));
+ }
+
+ double x() const { return m_x; }
+ double y() const { return m_y; }
+ double z() const { return m_z; }
+
private:
- virtual bool isIdentity() const { return m_x == 1 && m_y == 1; }
+ virtual bool isIdentity() const { return m_x == 1 && m_y == 1 && m_z == 1; }
+
virtual OperationType getOperationType() const { return m_type; }
virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
@@ -46,26 +56,29 @@ private:
if (!isSameType(o))
return false;
const ScaleTransformOperation* s = static_cast<const ScaleTransformOperation*>(&o);
- return m_x == s->m_x && m_y == s->m_y;
+ return m_x == s->m_x && m_y == s->m_y && m_z == s->m_z;
}
virtual bool apply(TransformationMatrix& transform, const IntSize&) const
{
- transform.scale(m_x, m_y);
+ transform.scale3d(m_x, m_y, m_z);
return false;
}
virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
- ScaleTransformOperation(double sx, double sy, OperationType type)
+ ScaleTransformOperation(double sx, double sy, double sz, OperationType type)
: m_x(sx)
, m_y(sy)
+ , m_z(sz)
, m_type(type)
{
+ ASSERT(type == SCALE_X || type == SCALE_Y || type == SCALE_Z || type == SCALE || type == SCALE_3D);
}
double m_x;
double m_y;
+ double m_z;
OperationType m_type;
};
diff --git a/WebCore/platform/graphics/transforms/TransformOperation.h b/WebCore/platform/graphics/transforms/TransformOperation.h
index 65a0def..c610c4b 100644
--- a/WebCore/platform/graphics/transforms/TransformOperation.h
+++ b/WebCore/platform/graphics/transforms/TransformOperation.h
@@ -39,9 +39,16 @@ public:
enum OperationType {
SCALE_X, SCALE_Y, SCALE,
TRANSLATE_X, TRANSLATE_Y, TRANSLATE,
- ROTATE,
+ ROTATE,
+ ROTATE_Z = ROTATE,
SKEW_X, SKEW_Y, SKEW,
- MATRIX, IDENTITY, NONE
+ MATRIX,
+ SCALE_Z, SCALE_3D,
+ TRANSLATE_Z, TRANSLATE_3D,
+ ROTATE_X, ROTATE_Y, ROTATE_3D,
+ MATRIX_3D,
+ PERSPECTIVE,
+ IDENTITY, NONE
};
virtual ~TransformOperation() { }
@@ -51,12 +58,27 @@ public:
virtual bool isIdentity() const = 0;
+ // Return true if the borderBoxSize was used in the computation, false otherwise.
virtual bool apply(TransformationMatrix&, const IntSize& borderBoxSize) const = 0;
virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false) = 0;
virtual OperationType getOperationType() const = 0;
virtual bool isSameType(const TransformOperation&) const { return false; }
+
+ bool is3DOperation() const
+ {
+ OperationType opType = getOperationType();
+ return opType == SCALE_Z ||
+ opType == SCALE_3D ||
+ opType == TRANSLATE_Z ||
+ opType == TRANSLATE_3D ||
+ opType == ROTATE_X ||
+ opType == ROTATE_Y ||
+ opType == ROTATE_3D ||
+ opType == MATRIX_3D ||
+ opType == PERSPECTIVE;
+ }
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/TransformOperations.h b/WebCore/platform/graphics/transforms/TransformOperations.h
index f929417..11605e8 100644
--- a/WebCore/platform/graphics/transforms/TransformOperations.h
+++ b/WebCore/platform/graphics/transforms/TransformOperations.h
@@ -47,6 +47,16 @@ public:
m_operations[i]->apply(t, sz);
}
+ // Return true if any of the operation types are 3D operation types (even if the
+ // values describe affine transforms)
+ bool has3DOperation() const
+ {
+ for (unsigned i = 0; i < m_operations.size(); ++i)
+ if (m_operations[i]->is3DOperation())
+ return true;
+ return false;
+ }
+
Vector<RefPtr<TransformOperation> >& operations() { return m_operations; }
const Vector<RefPtr<TransformOperation> >& operations() const { return m_operations; }
diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
index b48d572..63a7b8e 100644
--- a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "TransformationMatrix.h"
+#include "FloatPoint3D.h"
#include "FloatRect.h"
#include "FloatQuad.h"
#include "IntRect.h"
@@ -34,76 +35,467 @@
namespace WebCore {
-static void affineTransformDecompose(const TransformationMatrix& matrix, double sr[9])
+//
+// Supporting Math Functions
+//
+// This is a set of function from various places (attributed inline) to do things like
+// inversion and decomposition of a 4x4 matrix. They are used throughout the code
+//
+
+//
+// Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.
+
+// EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code
+// as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial
+// or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there
+// are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or
+// webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes
+// with no guarantee.
+
+typedef double Vector4[4];
+typedef double Vector3[3];
+
+const double SMALL_NUMBER = 1.e-8;
+
+// inverse(original_matrix, inverse_matrix)
+//
+// calculate the inverse of a 4x4 matrix
+//
+// -1
+// A = ___1__ adjoint A
+// det A
+
+// double = determinant2x2(double a, double b, double c, double d)
+//
+// calculate the determinant of a 2x2 matrix.
+
+static double determinant2x2(double a, double b, double c, double d)
{
- TransformationMatrix m(matrix);
+ return a * d - b * c;
+}
- // 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 = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
+//
+// Calculate the determinant of a 3x3 matrix
+// in the form
+//
+// | a1, b1, c1 |
+// | a2, b2, c2 |
+// | a3, b3, c3 |
- /* Compute cross product of transformed unit vectors. If negative,
- one axis was flipped. */
+static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3)
+{
+ return a1 * determinant2x2(b2, b3, c2, c3)
+ - b1 * determinant2x2(a2, a3, c2, c3)
+ + c1 * determinant2x2(a2, a3, b2, b3);
+}
- if (m.a() * m.d() - m.c() * m.b() < 0.0) {
- // Flip axis with minimum unit vector dot product
+// double = determinant4x4(matrix)
+//
+// calculate the determinant of a 4x4 matrix.
- if (m.a() < m.d())
- sx = -sx;
- else
- sy = -sy;
- }
+static double determinant4x4(const TransformationMatrix::Matrix4& m)
+{
+ // Assign to individual variable names to aid selecting
+ // correct elements
+
+ double a1 = m[0][0];
+ double b1 = m[0][1];
+ double c1 = m[0][2];
+ double d1 = m[0][3];
+
+ double a2 = m[1][0];
+ double b2 = m[1][1];
+ double c2 = m[1][2];
+ double d2 = m[1][3];
+
+ double a3 = m[2][0];
+ double b3 = m[2][1];
+ double c3 = m[2][2];
+ double d3 = m[2][3];
+
+ double a4 = m[3][0];
+ double b4 = m[3][1];
+ double c4 = m[3][2];
+ double d4 = m[3][3];
+
+ return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
+ - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
+ + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
+ - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
+}
+
+// adjoint( original_matrix, inverse_matrix )
+//
+// calculate the adjoint of a 4x4 matrix
+//
+// Let a denote the minor determinant of matrix A obtained by
+// ij
+//
+// deleting the ith row and jth column from A.
+//
+// i+j
+// Let b = (-1) a
+// ij ji
+//
+// The matrix B = (b ) is the adjoint of A
+// ij
+
+static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
+{
+ // Assign to individual variable names to aid
+ // selecting correct values
+ double a1 = matrix[0][0];
+ double b1 = matrix[0][1];
+ double c1 = matrix[0][2];
+ double d1 = matrix[0][3];
- // Remove scale from matrix
+ double a2 = matrix[1][0];
+ double b2 = matrix[1][1];
+ double c2 = matrix[1][2];
+ double d2 = matrix[1][3];
- m.scale(1.0 / sx, 1.0 / sy);
+ double a3 = matrix[2][0];
+ double b3 = matrix[2][1];
+ double c3 = matrix[2][2];
+ double d3 = matrix[2][3];
- // Compute rotation
+ double a4 = matrix[3][0];
+ double b4 = matrix[3][1];
+ double c4 = matrix[3][2];
+ double d4 = matrix[3][3];
- double angle = atan2(m.b(), m.a());
+ // Row column labeling reversed since we transpose rows & columns
+ result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
+ result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
+ result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
+ result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
+
+ result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
+ result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
+ result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
+ result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
+
+ result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
+ result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
+ result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
+ result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
+
+ result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
+ result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
+ result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
+ result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
+}
+
+// Returns false if the matrix is not invertible
+static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
+{
+ // Calculate the adjoint matrix
+ adjoint(matrix, result);
- // Remove rotation from matrix
+ // Calculate the 4x4 determinant
+ // If the determinant is zero,
+ // then the inverse matrix is not unique.
+ double det = determinant4x4(matrix);
- m.rotate(rad2deg(-angle));
+ if (fabs(det) < SMALL_NUMBER)
+ return false;
- // Return results
+ // Scale the adjoint matrix to get the inverse
- sr[0] = sx; sr[1] = sy; sr[2] = angle;
- sr[3] = m.a(); sr[4] = m.b();
- sr[5] = m.c(); sr[6] = m.d();
- sr[7] = m.e(); sr[8] = m.f();
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ result[i][j] = result[i][j] / det;
+
+ return true;
}
-static void affineTransformCompose(TransformationMatrix& m, const double sr[9])
+// End of code adapted from Matrix Inversion by Richard Carling
+
+// Perform a decomposition on the passed matrix, return false if unsuccessful
+// From Graphics Gems: unmatrix.c
+
+// Transpose rotation portion of matrix a, return b
+static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b)
{
- m.setA(sr[3]);
- m.setB(sr[4]);
- m.setC(sr[5]);
- m.setD(sr[6]);
- m.setE(sr[7]);
- m.setF(sr[8]);
- m.rotate(rad2deg(sr[2]));
- m.scale(sr[0], sr[1]);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ b[i][j] = a[j][i];
}
-bool TransformationMatrix::isInvertible() const
+// Multiply a homogeneous point by a matrix and return the transformed point
+static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result)
{
- return det() != 0.0;
+ result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) +
+ (p[2] * m[2][0]) + (p[3] * m[3][0]);
+ result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) +
+ (p[2] * m[2][1]) + (p[3] * m[3][1]);
+ result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) +
+ (p[2] * m[2][2]) + (p[3] * m[3][2]);
+ result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) +
+ (p[2] * m[2][3]) + (p[3] * m[3][3]);
}
-TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& other)
+static double v3Length(Vector3 a)
{
- return (*this) *= other;
+ return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2]));
}
-TransformationMatrix& TransformationMatrix::scale(double s)
+static void v3Scale(Vector3 v, double desiredLength)
{
- return scale(s, s);
+ double len = v3Length(v);
+ if (len != 0) {
+ double l = desiredLength / len;
+ v[0] *= l;
+ v[1] *= l;
+ v[2] *= l;
+ }
}
-TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
+static double v3Dot(const Vector3 a, const Vector3 b)
{
- return scale(sx, sy);
+ return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
+}
+
+// Make a linear combination of two vectors and return the result.
+// result = (a * ascl) + (b * bscl)
+static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl)
+{
+ result[0] = (ascl * a[0]) + (bscl * b[0]);
+ result[1] = (ascl * a[1]) + (bscl * b[1]);
+ result[2] = (ascl * a[2]) + (bscl * b[2]);
+}
+
+// Return the cross product result = a cross b */
+static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result)
+{
+ result[0] = (a[1] * b[2]) - (a[2] * b[1]);
+ result[1] = (a[2] * b[0]) - (a[0] * b[2]);
+ result[2] = (a[0] * b[1]) - (a[1] * b[0]);
+}
+
+static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result)
+{
+ TransformationMatrix::Matrix4 localMatrix;
+ memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4));
+
+ // Normalize the matrix.
+ if (localMatrix[3][3] == 0)
+ return false;
+
+ int i, j;
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++)
+ localMatrix[i][j] /= localMatrix[3][3];
+
+ // perspectiveMatrix is used to solve for perspective, but it also provides
+ // an easy way to test for singularity of the upper 3x3 component.
+ TransformationMatrix::Matrix4 perspectiveMatrix;
+ memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4));
+ for (i = 0; i < 3; i++)
+ perspectiveMatrix[i][3] = 0;
+ perspectiveMatrix[3][3] = 1;
+
+ if (determinant4x4(perspectiveMatrix) == 0)
+ return false;
+
+ // First, isolate perspective. This is the messiest.
+ if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) {
+ // rightHandSide is the right hand side of the equation.
+ Vector4 rightHandSide;
+ rightHandSide[0] = localMatrix[0][3];
+ rightHandSide[1] = localMatrix[1][3];
+ rightHandSide[2] = localMatrix[2][3];
+ rightHandSide[3] = localMatrix[3][3];
+
+ // Solve the equation by inverting perspectiveMatrix and multiplying
+ // rightHandSide by the inverse. (This is the easiest way, not
+ // necessarily the best.)
+ TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix;
+ inverse(perspectiveMatrix, inversePerspectiveMatrix);
+ transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);
+
+ Vector4 perspectivePoint;
+ v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
+
+ result.perspectiveX = perspectivePoint[0];
+ result.perspectiveY = perspectivePoint[1];
+ result.perspectiveZ = perspectivePoint[2];
+ result.perspectiveW = perspectivePoint[3];
+
+ // Clear the perspective partition
+ localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0;
+ localMatrix[3][3] = 1;
+ } else {
+ // No perspective.
+ result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0;
+ result.perspectiveW = 1;
+ }
+
+ // Next take care of translation (easy).
+ result.translateX = localMatrix[3][0];
+ localMatrix[3][0] = 0;
+ result.translateY = localMatrix[3][1];
+ localMatrix[3][1] = 0;
+ result.translateZ = localMatrix[3][2];
+ localMatrix[3][2] = 0;
+
+ // Vector4 type and functions need to be added to the common set.
+ Vector3 row[3], pdum3;
+
+ // Now get scale and shear.
+ for (i = 0; i < 3; i++) {
+ row[i][0] = localMatrix[i][0];
+ row[i][1] = localMatrix[i][1];
+ row[i][2] = localMatrix[i][2];
+ }
+
+ // Compute X scale factor and normalize first row.
+ result.scaleX = v3Length(row[0]);
+ v3Scale(row[0], 1.0);
+
+ // Compute XY shear factor and make 2nd row orthogonal to 1st.
+ result.skewXY = v3Dot(row[0], row[1]);
+ v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY);
+
+ // Now, compute Y scale and normalize 2nd row.
+ result.scaleY = v3Length(row[1]);
+ v3Scale(row[1], 1.0);
+ result.skewXY /= result.scaleY;
+
+ // Compute XZ and YZ shears, orthogonalize 3rd row.
+ result.skewXZ = v3Dot(row[0], row[2]);
+ v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ);
+ result.skewYZ = v3Dot(row[1], row[2]);
+ v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ);
+
+ // Next, get Z scale and normalize 3rd row.
+ result.scaleZ = v3Length(row[2]);
+ v3Scale(row[2], 1.0);
+ result.skewXZ /= result.scaleZ;
+ result.skewYZ /= result.scaleZ;
+
+ // At this point, the matrix (in rows[]) is orthonormal.
+ // Check for a coordinate system flip. If the determinant
+ // is -1, then negate the matrix and the scaling factors.
+ v3Cross(row[1], row[2], pdum3);
+ if (v3Dot(row[0], pdum3) < 0) {
+ for (i = 0; i < 3; i++) {
+ result.scaleX *= -1;
+ row[i][0] *= -1;
+ row[i][1] *= -1;
+ row[i][2] *= -1;
+ }
+ }
+
+ // Now, get the rotations out, as described in the gem.
+
+ // FIXME - Add the ability to return either quaternions (which are
+ // easier to recompose with) or Euler angles (rx, ry, rz), which
+ // are easier for authors to deal with. The latter will only be useful
+ // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
+ // will leave the Euler angle code here for now.
+
+ // ret.rotateY = asin(-row[0][2]);
+ // if (cos(ret.rotateY) != 0) {
+ // ret.rotateX = atan2(row[1][2], row[2][2]);
+ // ret.rotateZ = atan2(row[0][1], row[0][0]);
+ // } else {
+ // ret.rotateX = atan2(-row[2][0], row[1][1]);
+ // ret.rotateZ = 0;
+ // }
+
+ double s, t, x, y, z, w;
+
+ t = row[0][0] + row[1][1] + row[2][2] + 1.0;
+
+ if (t > 1e-4) {
+ s = 0.5 / sqrt(t);
+ w = 0.25 / s;
+ x = (row[2][1] - row[1][2]) * s;
+ y = (row[0][2] - row[2][0]) * s;
+ z = (row[1][0] - row[0][1]) * s;
+ } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) {
+ s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx
+ x = 0.25 * s;
+ y = (row[0][1] + row[1][0]) / s;
+ z = (row[0][2] + row[2][0]) / s;
+ w = (row[2][1] - row[1][2]) / s;
+ } else if (row[1][1] > row[2][2]) {
+ s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy
+ x = (row[0][1] + row[1][0]) / s;
+ y = 0.25 * s;
+ z = (row[1][2] + row[2][1]) / s;
+ w = (row[0][2] - row[2][0]) / s;
+ } else {
+ s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz
+ x = (row[0][2] + row[2][0]) / s;
+ y = (row[1][2] + row[2][1]) / s;
+ z = 0.25 * s;
+ w = (row[1][0] - row[0][1]) / s;
+ }
+
+ result.quaternionX = x;
+ result.quaternionY = y;
+ result.quaternionZ = z;
+ result.quaternionW = w;
+
+ return true;
+}
+
+// Perform a spherical linear interpolation between the two
+// passed quaternions with 0 <= t <= 1
+static void slerp(double qa[4], const double qb[4], double t)
+{
+ double ax, ay, az, aw;
+ double bx, by, bz, bw;
+ double cx, cy, cz, cw;
+ double angle;
+ double th, invth, scale, invscale;
+
+ ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3];
+ bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3];
+
+ angle = ax * bx + ay * by + az * bz + aw * bw;
+
+ if (angle < 0.0) {
+ ax = -ax; ay = -ay;
+ az = -az; aw = -aw;
+ angle = -angle;
+ }
+
+ if (angle + 1.0 > .05) {
+ if (1.0 - angle >= .05) {
+ th = acos (angle);
+ invth = 1.0 / sin (th);
+ scale = sin (th * (1.0 - t)) * invth;
+ invscale = sin (th * t) * invth;
+ } else {
+ scale = 1.0 - t;
+ invscale = t;
+ }
+ } else {
+ bx = -ay;
+ by = ax;
+ bz = -aw;
+ bw = az;
+ scale = sin(piDouble * (.5 - t));
+ invscale = sin (piDouble * t);
+ }
+
+ cx = ax * scale + bx * invscale;
+ cy = ay * scale + by * invscale;
+ cz = az * scale + bz * invscale;
+ cw = aw * scale + bw * invscale;
+
+ qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw;
+}
+
+// End of Supporting Math Functions
+
+TransformationMatrix& TransformationMatrix::scale(double s)
+{
+ return scaleNonUniform(s, s);
}
TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
@@ -113,93 +505,588 @@ TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
TransformationMatrix& TransformationMatrix::flipX()
{
- return scale(-1.0f, 1.0f);
+ return scaleNonUniform(-1.0f, 1.0f);
}
TransformationMatrix& TransformationMatrix::flipY()
{
- return scale(1.0f, -1.0f);
+ return scaleNonUniform(1.0f, -1.0f);
}
-TransformationMatrix& TransformationMatrix::skew(double angleX, double angleY)
+FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p) const
{
- return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
+ // This is basically raytracing. We have a point in the destination
+ // plane with z=0, and we cast a ray parallel to the z-axis from that
+ // point to find the z-position at which it intersects the z=0 plane
+ // with the transform applied. Once we have that point we apply the
+ // inverse transform to find the corresponding point in the source
+ // space.
+ //
+ // Given a plane with normal Pn, and a ray starting at point R0 and
+ // with direction defined by the vector Rd, we can find the
+ // intersection point as a distance d from R0 in units of Rd by:
+ //
+ // d = -dot (Pn', R0) / dot (Pn', Rd)
+
+ double x = p.x();
+ double y = p.y();
+ double z = -(m13() * x + m23() * y + m43()) / m33();
+
+ double outX = x * m11() + y * m21() + z * m31() + m41();
+ double outY = x * m12() + y * m22() + z * m32() + m42();
+
+ double w = x * m14() + y * m24() + z * m34() + m44();
+ if (w != 1 && w != 0) {
+ outX /= w;
+ outY /= w;
+ }
+
+ return FloatPoint(static_cast<float>(outX), static_cast<float>(outY));
}
-TransformationMatrix& TransformationMatrix::skewX(double angle)
+FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q) const
{
- return shear(tan(deg2rad(angle)), 0.0f);
+ FloatQuad projectedQuad;
+ projectedQuad.setP1(projectPoint(q.p1()));
+ projectedQuad.setP2(projectPoint(q.p2()));
+ projectedQuad.setP3(projectPoint(q.p3()));
+ projectedQuad.setP4(projectPoint(q.p4()));
+ return projectedQuad;
}
-TransformationMatrix& TransformationMatrix::skewY(double angle)
+FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const
{
- return shear(0.0f, tan(deg2rad(angle)));
+ double x, y;
+ multVecMatrix(p.x(), p.y(), x, y);
+ return FloatPoint(static_cast<float>(x), static_cast<float>(y));
}
-TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
+FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const
{
- TransformationMatrix transform;
- transform.translate(dest.x() - source.x(), dest.y() - source.y());
- transform.scale(dest.width() / source.width(), dest.height() / source.height());
- return transform;
+ double x, y, z;
+ multVecMatrix(p.x(), p.y(), p.z(), x, y, z);
+ return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
}
IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const
{
- double x2, y2;
- map(point.x(), point.y(), &x2, &y2);
+ double x, y;
+ multVecMatrix(point.x(), point.y(), x, y);
// Round the point.
- return IntPoint(lround(x2), lround(y2));
+ return IntPoint(lround(x), lround(y));
+}
+
+IntRect TransformationMatrix::mapRect(const IntRect &rect) const
+{
+ return enclosingIntRect(mapRect(FloatRect(rect)));
}
-FloatPoint TransformationMatrix::mapPoint(const FloatPoint& point) const
+FloatRect TransformationMatrix::mapRect(const FloatRect& r) const
{
- double x2, y2;
- map(point.x(), point.y(), &x2, &y2);
+ FloatQuad resultQuad = mapQuad(FloatQuad(r));
+ return resultQuad.boundingBox();
+}
- return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
+FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const
+{
+ FloatQuad result;
+ result.setP1(mapPoint(q.p1()));
+ result.setP2(mapPoint(q.p2()));
+ result.setP3(mapPoint(q.p3()));
+ result.setP4(mapPoint(q.p4()));
+ return result;
}
-FloatQuad TransformationMatrix::mapQuad(const FloatQuad& quad) const
+TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
{
- // FIXME: avoid 4 seperate library calls. Point mapping really needs
- // to be platform-independent code.
- return FloatQuad(mapPoint(quad.p1()),
- mapPoint(quad.p2()),
- mapPoint(quad.p3()),
- mapPoint(quad.p4()));
+ TransformationMatrix mat;
+ mat.m_matrix[0][0] = sx;
+ mat.m_matrix[1][1] = sy;
+
+ multLeft(mat);
+ return *this;
}
-void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
+TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz)
+{
+ TransformationMatrix mat;
+ mat.m_matrix[0][0] = sx;
+ mat.m_matrix[1][1] = sy;
+ mat.m_matrix[2][2] = sz;
+
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle)
+{
+ // angles are in degrees. Switch to radians
+ angle = deg2rad(angle);
+
+ angle /= 2.0f;
+ double sinA = sin(angle);
+ double cosA = cos(angle);
+ double sinA2 = sinA * sinA;
+
+ // normalize
+ double length = sqrt(x * x + y * y + z * z);
+ if (length == 0) {
+ // bad vector, just use something reasonable
+ x = 0;
+ y = 0;
+ z = 1;
+ } else if (length != 1) {
+ x /= length;
+ y /= length;
+ z /= length;
+ }
+
+ TransformationMatrix mat;
+
+ // optimize case where axis is along major axis
+ if (x == 1.0f && y == 0.0f && z == 0.0f) {
+ mat.m_matrix[0][0] = 1.0f;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = -2.0f * sinA * cosA;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ } else if (x == 0.0f && y == 1.0f && z == 0.0f) {
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ } else if (x == 0.0f && y == 0.0f && z == 1.0f) {
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 2.0f * sinA * cosA;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ } else {
+ double x2 = x*x;
+ double y2 = y*y;
+ double z2 = z*z;
+
+ mat.m_matrix[0][0] = 1.0f - 2.0f * (y2 + z2) * sinA2;
+ mat.m_matrix[0][1] = 2.0f * (x * y * sinA2 + z * sinA * cosA);
+ mat.m_matrix[0][2] = 2.0f * (x * z * sinA2 - y * sinA * cosA);
+ mat.m_matrix[1][0] = 2.0f * (y * x * sinA2 - z * sinA * cosA);
+ mat.m_matrix[1][1] = 1.0f - 2.0f * (z2 + x2) * sinA2;
+ mat.m_matrix[1][2] = 2.0f * (y * z * sinA2 + x * sinA * cosA);
+ mat.m_matrix[2][0] = 2.0f * (z * x * sinA2 + y * sinA * cosA);
+ mat.m_matrix[2][1] = 2.0f * (z * y * sinA2 - x * sinA * cosA);
+ mat.m_matrix[2][2] = 1.0f - 2.0f * (x2 + y2) * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ }
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz)
+{
+ // angles are in degrees. Switch to radians
+ rx = deg2rad(rx);
+ ry = deg2rad(ry);
+ rz = deg2rad(rz);
+
+ TransformationMatrix mat;
+
+ rz /= 2.0f;
+ double sinA = sin(rz);
+ double cosA = cos(rz);
+ double sinA2 = sinA * sinA;
+
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 2.0f * sinA * cosA;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+
+ TransformationMatrix rmat(mat);
+
+ ry /= 2.0f;
+ sinA = sin(ry);
+ cosA = cos(ry);
+ sinA2 = sinA * sinA;
+
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+
+ rmat.multLeft(mat);
+
+ rx /= 2.0f;
+ sinA = sin(rx);
+ cosA = cos(rx);
+ sinA2 = sinA * sinA;
+
+ mat.m_matrix[0][0] = 1.0f;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = -2.0f * sinA * cosA;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+
+ rmat.multLeft(mat);
+
+ multLeft(rmat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
+{
+#ifdef ANDROID_FASTER_MATRIX
+ m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0];
+ m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1];
+ m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2];
+ m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3];
+#else
+ // FIXME: optimize to avoid matrix copy
+ TransformationMatrix mat;
+ mat.m_matrix[3][0] = tx;
+ mat.m_matrix[3][1] = ty;
+
+ multLeft(mat);
+#endif
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz)
{
- double srA[9], srB[9];
+#ifdef ANDROID_FASTER_MATRIX
+ m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0];
+ m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1];
+ m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2];
+ m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3];
+#else
+ // FIXME: optimize to avoid matrix copy
+ TransformationMatrix mat;
+ mat.m_matrix[3][0] = tx;
+ mat.m_matrix[3][1] = ty;
+ mat.m_matrix[3][2] = tz;
- affineTransformDecompose(from, srA);
- affineTransformDecompose(*this, srB);
+ multLeft(mat);
+#endif
+ return *this;
+}
- // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
- if ((srA[0] < 0.0 && srB[1] < 0.0) || (srA[1] < 0.0 && srB[0] < 0.0)) {
- srA[0] = -srA[0];
- srA[1] = -srA[1];
- srA[2] += srA[2] < 0 ? piDouble : -piDouble;
+TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty)
+{
+ if (tx != 0) {
+ m_matrix[0][0] += m_matrix[0][3] * tx;
+ m_matrix[1][0] += m_matrix[1][3] * tx;
+ m_matrix[2][0] += m_matrix[2][3] * tx;
+ m_matrix[3][0] += m_matrix[3][3] * tx;
}
- // Don't rotate the long way around.
- srA[2] = fmod(srA[2], 2.0 * piDouble);
- srB[2] = fmod(srB[2], 2.0 * piDouble);
+ if (ty != 0) {
+ m_matrix[0][1] += m_matrix[0][3] * ty;
+ m_matrix[1][1] += m_matrix[1][3] * ty;
+ m_matrix[2][1] += m_matrix[2][3] * ty;
+ m_matrix[3][1] += m_matrix[3][3] * ty;
+ }
- if (fabs(srA[2] - srB[2]) > piDouble) {
- if (srA[2] > srB[2])
- srA[2] -= piDouble * 2.0;
- else
- srB[2] -= piDouble * 2.0;
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz)
+{
+ translateRight(tx, ty);
+ if (tz != 0) {
+ m_matrix[0][2] += m_matrix[0][3] * tz;
+ m_matrix[1][2] += m_matrix[1][3] * tz;
+ m_matrix[2][2] += m_matrix[2][3] * tz;
+ m_matrix[3][2] += m_matrix[3][3] * tz;
}
- for (int i = 0; i < 9; i++)
- srA[i] = srA[i] + progress * (srB[i] - srA[i]);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::skew(double sx, double sy)
+{
+ // angles are in degrees. Switch to radians
+ sx = deg2rad(sx);
+ sy = deg2rad(sy);
+
+ TransformationMatrix mat;
+ mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row
+ mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row
+
+ multLeft(mat);
+ return *this;
+}
- affineTransformCompose(*this, srA);
+TransformationMatrix& TransformationMatrix::applyPerspective(double p)
+{
+ TransformationMatrix mat;
+ if (p != 0)
+ mat.m_matrix[2][3] = -1/p;
+
+ multLeft(mat);
+ return *this;
+}
+
+//
+// *this = mat * *this
+//
+TransformationMatrix& TransformationMatrix::multLeft(const TransformationMatrix& mat)
+{
+ Matrix4 tmp;
+
+ tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0]
+ + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]);
+ tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1]
+ + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]);
+ tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2]
+ + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]);
+ tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3]
+ + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]);
+
+ tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0]
+ + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]);
+ tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1]
+ + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]);
+ tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2]
+ + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]);
+ tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3]
+ + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]);
+
+ tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0]
+ + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]);
+ tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1]
+ + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]);
+ tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2]
+ + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]);
+ tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3]
+ + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]);
+
+ tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0]
+ + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]);
+ tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1]
+ + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]);
+ tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2]
+ + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]);
+ tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3]
+ + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]);
+
+ setMatrix(tmp);
+ return *this;
+}
+
+void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const
+{
+ resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0];
+ resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1];
+ double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3];
+ if (w != 1 && w != 0) {
+ resultX /= w;
+ resultY /= w;
+ }
+}
+
+void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const
+{
+ resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
+ resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
+ resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2];
+ double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3];
+ if (w != 1 && w != 0) {
+ resultX /= w;
+ resultY /= w;
+ resultZ /= w;
+ }
+}
+
+bool TransformationMatrix::isInvertible() const
+{
+ double det = WebCore::determinant4x4(m_matrix);
+
+ if (fabs(det) < SMALL_NUMBER)
+ return false;
+
+ return true;
+}
+
+TransformationMatrix TransformationMatrix::inverse() const
+{
+ TransformationMatrix invMat;
+
+ bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix);
+ if (!inverted)
+ return TransformationMatrix();
+
+ return invMat;
+}
+
+void TransformationMatrix::makeAffine()
+{
+ m_matrix[0][2] = 0;
+ m_matrix[0][3] = 0;
+
+ m_matrix[1][2] = 0;
+ m_matrix[1][3] = 0;
+
+ m_matrix[2][0] = 0;
+ m_matrix[2][1] = 0;
+ m_matrix[2][2] = 1;
+ m_matrix[2][3] = 0;
+
+ m_matrix[3][2] = 0;
+ m_matrix[3][3] = 1;
+}
+
+static inline void blendFloat(double& from, double to, double progress)
+{
+ if (from != to)
+ from = from + (to - from) * progress;
+}
+
+void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
+{
+ if (from.isIdentity() && isIdentity())
+ return;
+
+ // decompose
+ DecomposedType fromDecomp;
+ DecomposedType toDecomp;
+ from.decompose(fromDecomp);
+ decompose(toDecomp);
+
+ // interpolate
+ blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress);
+ blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress);
+ blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress);
+ blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress);
+ blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress);
+ blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress);
+ blendFloat(fromDecomp.translateX, toDecomp.translateX, progress);
+ blendFloat(fromDecomp.translateY, toDecomp.translateY, progress);
+ blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress);
+ blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress);
+ blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress);
+ blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress);
+ blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress);
+
+ slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress);
+
+ // recompose
+ recompose(fromDecomp);
+}
+
+bool TransformationMatrix::decompose(DecomposedType& decomp) const
+{
+ if (isIdentity()) {
+ memset(&decomp, 0, sizeof(decomp));
+ decomp.perspectiveW = 1;
+ decomp.scaleX = 1;
+ decomp.scaleY = 1;
+ decomp.scaleZ = 1;
+ }
+
+ if (!WebCore::decompose(m_matrix, decomp))
+ return false;
+ return true;
+}
+
+void TransformationMatrix::recompose(const DecomposedType& decomp)
+{
+ makeIdentity();
+
+ // first apply perspective
+ m_matrix[0][3] = (float) decomp.perspectiveX;
+ m_matrix[1][3] = (float) decomp.perspectiveY;
+ m_matrix[2][3] = (float) decomp.perspectiveZ;
+ m_matrix[3][3] = (float) decomp.perspectiveW;
+
+ // now translate
+ translate3d((float) decomp.translateX, (float) decomp.translateY, (float) decomp.translateZ);
+
+ // apply rotation
+ double xx = decomp.quaternionX * decomp.quaternionX;
+ double xy = decomp.quaternionX * decomp.quaternionY;
+ double xz = decomp.quaternionX * decomp.quaternionZ;
+ double xw = decomp.quaternionX * decomp.quaternionW;
+ double yy = decomp.quaternionY * decomp.quaternionY;
+ double yz = decomp.quaternionY * decomp.quaternionZ;
+ double yw = decomp.quaternionY * decomp.quaternionW;
+ double zz = decomp.quaternionZ * decomp.quaternionZ;
+ double zw = decomp.quaternionZ * decomp.quaternionW;
+
+ // Construct a composite rotation matrix from the quaternion values
+ TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0,
+ 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0,
+ 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0,
+ 0, 0, 0, 1);
+
+ multLeft(rotationMatrix);
+
+ // now apply skew
+ if (decomp.skewYZ) {
+ TransformationMatrix tmp;
+ tmp.setM32((float) decomp.skewYZ);
+ multLeft(tmp);
+ }
+
+ if (decomp.skewXZ) {
+ TransformationMatrix tmp;
+ tmp.setM31((float) decomp.skewXZ);
+ multLeft(tmp);
+ }
+
+ if (decomp.skewXY) {
+ TransformationMatrix tmp;
+ tmp.setM21((float) decomp.skewXY);
+ multLeft(tmp);
+ }
+
+ // finally, apply scale
+ scale3d((float) decomp.scaleX, (float) decomp.scaleY, (float) decomp.scaleZ);
}
}
diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h
index db121d1..62e4eb8 100644
--- a/WebCore/platform/graphics/transforms/TransformationMatrix.h
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h
@@ -28,112 +28,293 @@
#if PLATFORM(CG)
#include <CoreGraphics/CGAffineTransform.h>
-typedef CGAffineTransform PlatformTransformationMatrix;
-#elif PLATFORM(QT)
-#include <QMatrix>
-typedef QMatrix PlatformTransformationMatrix;
#elif PLATFORM(CAIRO)
#include <cairo.h>
-typedef cairo_matrix_t PlatformTransformationMatrix;
+#elif PLATFORM(QT)
+#include <QTransform>
#elif PLATFORM(SKIA) || PLATFORM(SGL)
-#include "SkMatrix.h"
-typedef SkMatrix PlatformTransformationMatrix;
+#include <SkMatrix.h>
#elif PLATFORM(WX) && USE(WXGC)
-#include <wx/defs.h>
#include <wx/graphics.h>
-typedef wxGraphicsMatrix PlatformTransformationMatrix;
#endif
+#include <string.h> //for memcpy
+
namespace WebCore {
class IntPoint;
class IntRect;
class FloatPoint;
+class FloatPoint3D;
class FloatRect;
class FloatQuad;
class TransformationMatrix {
public:
- TransformationMatrix();
- TransformationMatrix(double a, double b, double c, double d, double e, double f);
-#if !PLATFORM(WX) || USE(WXGC)
- TransformationMatrix(const PlatformTransformationMatrix&);
-#endif
+ typedef double Matrix4[4][4];
- void setMatrix(double a, double b, double c, double d, double e, double f);
- void map(double x, double y, double *x2, double *y2) const;
+ TransformationMatrix() { makeIdentity(); }
+ TransformationMatrix(const TransformationMatrix& t) { *this = t; }
+ TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); }
+ TransformationMatrix(double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44)
+ {
+ setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
+ }
- // Rounds the mapped point to the nearest integer value.
- IntPoint mapPoint(const IntPoint&) const;
+ void setMatrix(double a, double b, double c, double d, double e, double f)
+ {
+ m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0;
+ m_matrix[1][0] = c; m_matrix[1][1] = d; m_matrix[1][2] = 0; m_matrix[1][3] = 0;
+ m_matrix[2][0] = 0; m_matrix[2][1] = 0; m_matrix[2][2] = 1; m_matrix[2][3] = 0;
+ m_matrix[3][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1;
+ }
+
+ void setMatrix(double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44)
+ {
+ m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14;
+ m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24;
+ m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34;
+ m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44;
+ }
+
+ TransformationMatrix& operator =(const TransformationMatrix &t)
+ {
+ setMatrix(t.m_matrix);
+ return *this;
+ }
+
+ TransformationMatrix& makeIdentity()
+ {
+ setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ return *this;
+ }
+
+ bool isIdentity() const
+ {
+ return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 &&
+ m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 &&
+ m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 &&
+ m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1;
+ }
+
+ // This form preserves the double math from input to output
+ void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); }
+ // Map a 3D point through the transform, returning a 3D point.
+ FloatPoint3D mapPoint(const FloatPoint3D&) const;
+
+ // Map a 2D point through the transform, returning a 2D point.
+ // Note that this ignores the z component, effectively projecting the point into the z=0 plane.
FloatPoint mapPoint(const FloatPoint&) const;
+ // Like the version above, except that it rounds the mapped point to the nearest integer value.
+ IntPoint mapPoint(const IntPoint&) const;
+
+ // If the matrix has 3D components, the z component of the result is
+ // dropped, effectively projecting the rect into the z=0 plane
+ FloatRect mapRect(const FloatRect&) const;
+
// Rounds the resulting mapped rectangle out. This is helpful for bounding
// box computations but may not be what is wanted in other contexts.
IntRect mapRect(const IntRect&) const;
- FloatRect mapRect(const FloatRect&) const;
-
+ // If the matrix has 3D components, the z component of the result is
+ // dropped, effectively projecting the quad into the z=0 plane
FloatQuad mapQuad(const FloatQuad&) const;
- bool isIdentity() const;
+ // Map a point on the z=0 plane into a point on
+ // the plane with with the transform applied, by extending
+ // a ray perpendicular to the source plane and computing
+ // the local x,y position of the point where that ray intersects
+ // with the destination plane.
+ FloatPoint projectPoint(const FloatPoint&) const;
+ // Projects the four corners of the quad
+ FloatQuad projectQuad(const FloatQuad&) const;
- double a() const;
- void setA(double a);
+ double m11() const { return m_matrix[0][0]; }
+ void setM11(double f) { m_matrix[0][0] = f; }
+ double m12() const { return m_matrix[0][1]; }
+ void setM12(double f) { m_matrix[0][1] = f; }
+ double m13() const { return m_matrix[0][2]; }
+ void setM13(double f) { m_matrix[0][2] = f; }
+ double m14() const { return m_matrix[0][3]; }
+ void setM14(double f) { m_matrix[0][3] = f; }
+ double m21() const { return m_matrix[1][0]; }
+ void setM21(double f) { m_matrix[1][0] = f; }
+ double m22() const { return m_matrix[1][1]; }
+ void setM22(double f) { m_matrix[1][1] = f; }
+ double m23() const { return m_matrix[1][2]; }
+ void setM23(double f) { m_matrix[1][2] = f; }
+ double m24() const { return m_matrix[1][3]; }
+ void setM24(double f) { m_matrix[1][3] = f; }
+ double m31() const { return m_matrix[2][0]; }
+ void setM31(double f) { m_matrix[2][0] = f; }
+ double m32() const { return m_matrix[2][1]; }
+ void setM32(double f) { m_matrix[2][1] = f; }
+ double m33() const { return m_matrix[2][2]; }
+ void setM33(double f) { m_matrix[2][2] = f; }
+ double m34() const { return m_matrix[2][3]; }
+ void setM34(double f) { m_matrix[2][3] = f; }
+ double m41() const { return m_matrix[3][0]; }
+ void setM41(double f) { m_matrix[3][0] = f; }
+ double m42() const { return m_matrix[3][1]; }
+ void setM42(double f) { m_matrix[3][1] = f; }
+ double m43() const { return m_matrix[3][2]; }
+ void setM43(double f) { m_matrix[3][2] = f; }
+ double m44() const { return m_matrix[3][3]; }
+ void setM44(double f) { m_matrix[3][3] = f; }
+
+ double a() const { return m_matrix[0][0]; }
+ void setA(double a) { m_matrix[0][0] = a; }
- double b() const;
- void setB(double b);
+ double b() const { return m_matrix[0][1]; }
+ void setB(double b) { m_matrix[0][1] = b; }
- double c() const;
- void setC(double c);
+ double c() const { return m_matrix[1][0]; }
+ void setC(double c) { m_matrix[1][0] = c; }
- double d() const;
- void setD(double d);
+ double d() const { return m_matrix[1][1]; }
+ void setD(double d) { m_matrix[1][1] = d; }
- double e() const;
- void setE(double e);
+ double e() const { return m_matrix[3][0]; }
+ void setE(double e) { m_matrix[3][0] = e; }
- double f() const;
- void setF(double f);
+ double f() const { return m_matrix[3][1]; }
+ void setF(double f) { m_matrix[3][1] = f; }
- void reset();
+ // this = this * mat
+ TransformationMatrix& multiply(const TransformationMatrix& t) { return *this *= t; }
- TransformationMatrix& multiply(const TransformationMatrix&);
+ // this = mat * this
+ TransformationMatrix& multLeft(const TransformationMatrix& mat);
+
TransformationMatrix& scale(double);
- TransformationMatrix& scale(double sx, double sy);
TransformationMatrix& scaleNonUniform(double sx, double sy);
- TransformationMatrix& rotate(double d);
+ TransformationMatrix& scale3d(double sx, double sy, double sz);
+
+ TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); }
TransformationMatrix& rotateFromVector(double x, double y);
+ TransformationMatrix& rotate3d(double rx, double ry, double rz);
+
+ // The vector (x,y,z) is normalized if it's not already. A vector of
+ // (0,0,0) uses a vector of (0,0,1).
+ TransformationMatrix& rotate3d(double x, double y, double z, double angle);
+
TransformationMatrix& translate(double tx, double ty);
- TransformationMatrix& shear(double sx, double sy);
+ TransformationMatrix& translate3d(double tx, double ty, double tz);
+
+ // translation added with a post-multiply
+ TransformationMatrix& translateRight(double tx, double ty);
+ TransformationMatrix& translateRight3d(double tx, double ty, double tz);
+
TransformationMatrix& flipX();
TransformationMatrix& flipY();
TransformationMatrix& skew(double angleX, double angleY);
- TransformationMatrix& skewX(double angle);
- TransformationMatrix& skewY(double angle);
+ TransformationMatrix& skewX(double angle) { return skew(angle, 0); }
+ TransformationMatrix& skewY(double angle) { return skew(0, angle); }
+
+ TransformationMatrix& applyPerspective(double p);
+ bool hasPerspective() const { return m_matrix[2][3] != 0.0f; }
- double det() const;
bool isInvertible() const;
+
+ // This method returns the identity matrix if it is not invertible.
+ // Use isInvertible() before calling this if you need to know.
TransformationMatrix inverse() const;
+ // decompose the matrix into its component parts
+ typedef struct {
+ double scaleX, scaleY, scaleZ;
+ double skewXY, skewXZ, skewYZ;
+ double quaternionX, quaternionY, quaternionZ, quaternionW;
+ double translateX, translateY, translateZ;
+ double perspectiveX, perspectiveY, perspectiveZ, perspectiveW;
+ } DecomposedType;
+
+ bool decompose(DecomposedType& decomp) const;
+ void recompose(const DecomposedType& decomp);
+
void blend(const TransformationMatrix& from, double progress);
-#if !PLATFORM(WX) || USE(WXGC)
- operator PlatformTransformationMatrix() const;
-#endif
+ bool isAffine() const
+ {
+ return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 &&
+ m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1);
+ }
+
+ // Throw away the non-affine parts of the matrix (lossy!)
+ void makeAffine();
+
+ bool operator==(const TransformationMatrix& m2) const
+ {
+ return (m_matrix[0][0] == m2.m_matrix[0][0] &&
+ m_matrix[0][1] == m2.m_matrix[0][1] &&
+ m_matrix[0][2] == m2.m_matrix[0][2] &&
+ m_matrix[0][3] == m2.m_matrix[0][3] &&
+ m_matrix[1][0] == m2.m_matrix[1][0] &&
+ m_matrix[1][1] == m2.m_matrix[1][1] &&
+ m_matrix[1][2] == m2.m_matrix[1][2] &&
+ m_matrix[1][3] == m2.m_matrix[1][3] &&
+ m_matrix[2][0] == m2.m_matrix[2][0] &&
+ m_matrix[2][1] == m2.m_matrix[2][1] &&
+ m_matrix[2][2] == m2.m_matrix[2][2] &&
+ m_matrix[2][3] == m2.m_matrix[2][3] &&
+ m_matrix[3][0] == m2.m_matrix[3][0] &&
+ m_matrix[3][1] == m2.m_matrix[3][1] &&
+ m_matrix[3][2] == m2.m_matrix[3][2] &&
+ m_matrix[3][3] == m2.m_matrix[3][3]);
+ }
- bool operator==(const TransformationMatrix&) const;
bool operator!=(const TransformationMatrix& other) const { return !(*this == other); }
- TransformationMatrix& operator*=(const TransformationMatrix&);
- TransformationMatrix operator*(const TransformationMatrix&);
+
+ // *this = *this * t (i.e., a multRight)
+ TransformationMatrix& operator*=(const TransformationMatrix& t)
+ {
+ *this = *this * t;
+ return *this;
+ }
+
+ // result = *this * t (i.e., a multRight)
+ TransformationMatrix operator*(const TransformationMatrix& t)
+ {
+ TransformationMatrix result = t;
+ result.multLeft(*this);
+ return result;
+ }
-private:
-#if !PLATFORM(WX) || USE(WXGC)
- PlatformTransformationMatrix m_transform;
+#if PLATFORM(CG)
+ operator CGAffineTransform() const;
+#elif PLATFORM(CAIRO)
+ operator cairo_matrix_t() const;
+#elif PLATFORM(QT)
+ operator QTransform() const;
+#elif PLATFORM(SKIA) || PLATFORM(SGL)
+ operator SkMatrix() const;
+#elif PLATFORM(WX) && USE(WXGC)
+ operator wxGraphicsMatrix() const;
#endif
-};
-TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest);
+private:
+ // multiply passed 2D point by matrix (assume z=0)
+ void multVecMatrix(double x, double y, double& dstX, double& dstY) const;
+
+ // multiply passed 3D point by matrix
+ void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const;
+
+ void setMatrix(const Matrix4 m)
+ {
+ if (m && m != m_matrix)
+ memcpy(m_matrix, m, sizeof(Matrix4));
+ }
+
+ Matrix4 m_matrix;
+};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp b/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
index 47471c4..a8ad131 100644
--- a/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
@@ -30,12 +30,15 @@ PassRefPtr<TransformOperation> TranslateTransformOperation::blend(const Transfor
return this;
if (blendToIdentity)
- return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress), Length(m_y.type()).blend(m_y, progress), m_type);
+ return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress),
+ Length(m_y.type()).blend(m_y, progress),
+ Length(m_z.type()).blend(m_z, progress), m_type);
const TranslateTransformOperation* fromOp = static_cast<const TranslateTransformOperation*>(from);
Length fromX = fromOp ? fromOp->m_x : Length(m_x.type());
Length fromY = fromOp ? fromOp->m_y : Length(m_y.type());
- return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_type);
+ Length fromZ = fromOp ? fromOp->m_z : Length(m_z.type());
+ return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_z.blend(fromZ, progress), m_type);
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
index 61ccbcc..a66cc3d 100644
--- a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
@@ -34,10 +34,21 @@ class TranslateTransformOperation : public TransformOperation {
public:
static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, OperationType type)
{
- return adoptRef(new TranslateTransformOperation(tx, ty, type));
+ return adoptRef(new TranslateTransformOperation(tx, ty, Length(0, Fixed), type));
}
- virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0; }
+ static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, const Length& tz, OperationType type)
+ {
+ return adoptRef(new TranslateTransformOperation(tx, ty, tz, type));
+ }
+
+ double x(const IntSize& borderBoxSize) const { return m_x.calcFloatValue(borderBoxSize.width()); }
+ double y(const IntSize& borderBoxSize) const { return m_y.calcFloatValue(borderBoxSize.height()); }
+ double z(const IntSize&) const { return m_z.calcFloatValue(1); }
+
+private:
+ virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0 && m_z.calcFloatValue(1) == 0; }
+
virtual OperationType getOperationType() const { return m_type; }
virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
@@ -46,27 +57,29 @@ public:
if (!isSameType(o))
return false;
const TranslateTransformOperation* t = static_cast<const TranslateTransformOperation*>(&o);
- return m_x == t->m_x && m_y == t->m_y;
+ return m_x == t->m_x && m_y == t->m_y && m_z == t->m_z;
}
virtual bool apply(TransformationMatrix& transform, const IntSize& borderBoxSize) const
{
- transform.translate(m_x.calcFloatValue(borderBoxSize.width()), m_y.calcFloatValue(borderBoxSize.height()));
+ transform.translate3d(x(borderBoxSize), y(borderBoxSize), z(borderBoxSize));
return m_x.type() == Percent || m_y.type() == Percent;
}
virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
-private:
- TranslateTransformOperation(const Length& tx, const Length& ty, OperationType type)
+ TranslateTransformOperation(const Length& tx, const Length& ty, const Length& tz, OperationType type)
: m_x(tx)
, m_y(ty)
+ , m_z(tz)
, m_type(type)
{
+ ASSERT(type == TRANSLATE_X || type == TRANSLATE_Y || type == TRANSLATE_Z || type == TRANSLATE || type == TRANSLATE_3D);
}
Length m_x;
Length m_y;
+ Length m_z;
OperationType m_type;
};
diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp
index 9ca95f3..feeb2ae 100644
--- a/WebCore/platform/graphics/win/FontCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -223,8 +223,6 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData
ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
}
} else {
- RetainPtr<CGMutablePathRef> path(AdoptCF, CGPathCreateMutable());
-
XFORM xform;
GetWorldTransform(hdc, &xform);
TransformationMatrix hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy);
@@ -233,16 +231,8 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData
initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0));
initialGlyphTransform.tx = 0;
initialGlyphTransform.ty = 0;
- CGAffineTransform glyphTranslation = CGAffineTransformIdentity;
-
- for (unsigned i = 0; i < numGlyphs; ++i) {
- RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i)));
- CGAffineTransform glyphTransform = CGAffineTransformConcat(initialGlyphTransform, glyphTranslation);
- CGPathAddPath(path.get(), &glyphTransform, glyphPath.get());
- glyphTranslation = CGAffineTransformTranslate(glyphTranslation, gdiAdvances[i], 0);
- }
-
CGContextRef cgContext = graphicsContext->platformContext();
+
CGContextSaveGState(cgContext);
BOOL fontSmoothingEnabled = false;
@@ -252,26 +242,36 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData
CGContextScaleCTM(cgContext, 1.0, -1.0);
CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height()));
- if (drawingMode & cTextFill) {
- CGContextAddPath(cgContext, path.get());
- CGContextFillPath(cgContext);
- if (font->m_syntheticBoldOffset) {
- CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
- CGContextAddPath(cgContext, path.get());
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i)));
+ CGContextSaveGState(cgContext);
+ CGContextConcatCTM(cgContext, initialGlyphTransform);
+
+ if (drawingMode & cTextFill) {
+ CGContextAddPath(cgContext, glyphPath.get());
CGContextFillPath(cgContext);
- CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ if (font->m_syntheticBoldOffset) {
+ CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextFillPath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ }
}
- }
- if (drawingMode & cTextStroke) {
- CGContextAddPath(cgContext, path.get());
- CGContextStrokePath(cgContext);
- if (font->m_syntheticBoldOffset) {
- CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
- CGContextAddPath(cgContext, path.get());
+ if (drawingMode & cTextStroke) {
+ CGContextAddPath(cgContext, glyphPath.get());
CGContextStrokePath(cgContext);
- CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ if (font->m_syntheticBoldOffset) {
+ CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextStrokePath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ }
}
+
+ CGContextRestoreGState(cgContext);
+ CGContextTranslateCTM(cgContext, gdiAdvances[i], 0);
}
+
CGContextRestoreGState(cgContext);
}
@@ -298,8 +298,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();
if (font->platformData().useGDI()) {
- static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs();
- if (!canUsePlatformNativeGlyphs || !shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) {
+ if (!shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) {
drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
return;
}
diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp
index 9acc5a0..887bf79 100644
--- a/WebCore/platform/graphics/win/FontCacheWin.cpp
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -422,7 +422,24 @@ static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool
matchData.m_chosen.lfQuality = DEFAULT_QUALITY;
matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- return CreateFontIndirect(&matchData.m_chosen);
+ HFONT result = CreateFontIndirect(&matchData.m_chosen);
+ if (!result)
+ return 0;
+
+ HDC dc = GetDC(0);
+ SaveDC(dc);
+ SelectObject(dc, result);
+ WCHAR actualName[LF_FACESIZE];
+ GetTextFace(dc, LF_FACESIZE, actualName);
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+
+ if (wcsicmp(matchData.m_chosen.lfFaceName, actualName)) {
+ DeleteObject(result);
+ result = 0;
+ }
+
+ return result;
}
struct TraitsInFamilyProcData {
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
index ba8afe7..1ac3359 100644
--- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -65,10 +65,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
ASSERT(m_fontReference);
ASSERT(T2embedLibrary());
- static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs();
- LOGFONT _logFont;
-
- LOGFONT& logFont = canUsePlatformNativeGlyphs ? *static_cast<LOGFONT*>(malloc(sizeof(LOGFONT))) : _logFont;
+ LOGFONT& logFont = *static_cast<LOGFONT*>(malloc(sizeof(LOGFONT)));
if (m_name.isNull())
TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0);
else
@@ -90,8 +87,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
logFont.lfWeight = bold ? 700 : 400;
HFONT hfont = CreateFontIndirect(&logFont);
- if (canUsePlatformNativeGlyphs)
- wkSetFontPlatformInfo(m_cgFont, &logFont, free);
+ wkSetFontPlatformInfo(m_cgFont, &logFont, free);
return FontPlatformData(hfont, m_cgFont, size, bold, italic, renderingMode == AlternateRenderingMode);
}
@@ -120,7 +116,7 @@ size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count)
// Streams the concatenation of a header and font data.
class EOTStream {
public:
- EOTStream(const Vector<UInt8, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
+ EOTStream(const Vector<uint8_t, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
: m_eotHeader(eotHeader)
, m_fontData(fontData)
, m_overlayDst(overlayDst)
@@ -134,7 +130,7 @@ public:
size_t read(void* buffer, size_t count);
private:
- const Vector<UInt8, 512>& m_eotHeader;
+ const Vector<uint8_t, 512>& m_eotHeader;
const SharedBuffer* m_fontData;
size_t m_overlayDst;
size_t m_overlaySrc;
@@ -210,7 +206,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
// TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, so we need to create an EOT header
// and prepend it to the font data.
- Vector<UInt8, 512> eotHeader;
+ Vector<uint8_t, 512> eotHeader;
size_t overlayDst;
size_t overlaySrc;
size_t overlayLength;
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
index c7e59ab..59f7e5c 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
@@ -120,7 +120,7 @@ void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR*
ASSERT(m_cgFont);
}
}
- if (m_useGDI && wkCanUsePlatformNativeGlyphs()) {
+ if (m_useGDI) {
LOGFONT* logfont = static_cast<LOGFONT*>(malloc(sizeof(LOGFONT)));
GetObject(font, sizeof(*logfont), logfont);
wkSetFontPlatformInfo(m_cgFont.get(), logfont, free);
diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
index dccbe6c..da5b503 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -76,8 +76,6 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
}
}
-bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
-
// FIXME: Is it possible to merge getWindowsContext and createWindowsBitmap into a single API
// suitable for all clients?
HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
@@ -173,16 +171,6 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
m_data->restore();
}
-void GraphicsContext::setShouldIncludeChildWindows(bool include)
-{
- m_data->m_shouldIncludeChildWindows = include;
-}
-
-bool GraphicsContext::shouldIncludeChildWindows() const
-{
- return m_data->m_shouldIncludeChildWindows;
-}
-
GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
: m_hdc(0)
, m_size(size)
@@ -265,7 +253,7 @@ void GraphicsContext::drawFocusRing(const Color& color)
float radius = (focusRingWidth() - 1) / 2.0f;
int offset = radius + focusRingOffset();
- CGColorRef colorRef = color.isValid() ? cgColor(color) : 0;
+ CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0;
CGMutablePathRef focusRingPath = CGPathCreateMutable();
const Vector<IntRect>& rects = focusRingRects();
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
index 892d24a..1980d18 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -87,8 +87,6 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
return hdc;
}
-bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
-
void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
// FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs
diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
index b3ebcb0..e4c5b04 100644
--- a/WebCore/platform/graphics/win/GraphicsContextWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -43,6 +43,18 @@ namespace WebCore {
class SVGResourceImage;
+bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
+
+void GraphicsContext::setShouldIncludeChildWindows(bool include)
+{
+ m_data->m_shouldIncludeChildWindows = include;
+}
+
+bool GraphicsContext::shouldIncludeChildWindows() const
+{
+ return m_data->m_shouldIncludeChildWindows;
+}
+
void GraphicsContextPlatformPrivate::save()
{
if (!m_hdc)
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index 1b09e1f..c293f49 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -32,7 +32,10 @@
#include "KURL.h"
#include "QTMovieWin.h"
#include "ScrollView.h"
+#include "StringHash.h"
+#include <wtf/HashSet.h>
#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
#if DRAW_FRAME_RATE
#include "Font.h"
@@ -48,16 +51,25 @@ using namespace std;
namespace WebCore {
-static const double endPointTimerInterval = 0.020;
-
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_seekTo(-1)
, m_endTime(numeric_limits<float>::infinity())
, m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
- , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired)
, m_networkState(MediaPlayer::Empty)
- , m_readyState(MediaPlayer::DataUnavailable)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_enabledTrackCount(0)
, m_startedPlaying(false)
, m_isStreaming(false)
#if DRAW_FRAME_RATE
@@ -75,7 +87,8 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
void MediaPlayerPrivate::load(const String& url)
{
if (!QTMovieWin::initializeQuickTime()) {
- m_networkState = MediaPlayer::LoadFailed;
+ // FIXME: is this the right error to return?
+ m_networkState = MediaPlayer::DecodeError;
m_player->networkStateChanged();
return;
}
@@ -84,17 +97,16 @@ void MediaPlayerPrivate::load(const String& url)
m_networkState = MediaPlayer::Loading;
m_player->networkStateChanged();
}
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
cancelSeek();
- m_endPointTimer.stop();
m_qtMovie.set(new QTMovieWin(this));
m_qtMovie->load(url.characters(), url.length());
- m_qtMovie->setVolume(m_player->m_volume);
- m_qtMovie->setVisible(m_player->m_visible);
+ m_qtMovie->setVolume(m_player->volume());
+ m_qtMovie->setVisible(m_player->visible());
}
void MediaPlayerPrivate::play()
@@ -107,7 +119,6 @@ void MediaPlayerPrivate::play()
#endif
m_qtMovie->play();
- startEndPointTimerIfNeeded();
}
void MediaPlayerPrivate::pause()
@@ -119,7 +130,6 @@ void MediaPlayerPrivate::pause()
m_timeStoppedPlaying = GetTickCount();
#endif
m_qtMovie->pause();
- m_endPointTimer.stop();
}
float MediaPlayerPrivate::duration() const
@@ -156,11 +166,12 @@ void MediaPlayerPrivate::seek(float time)
void MediaPlayerPrivate::doSeek()
{
float oldRate = m_qtMovie->rate();
- m_qtMovie->setRate(0);
+ if (oldRate)
+ m_qtMovie->setRate(0);
m_qtMovie->setCurrentTime(m_seekTo);
float timeAfterSeek = currentTime();
// restore playback only if not at end, othewise QTMovie will loop
- if (timeAfterSeek < duration() && timeAfterSeek < m_endTime)
+ if (oldRate && timeAfterSeek < duration() && timeAfterSeek < m_endTime)
m_qtMovie->setRate(oldRate);
cancelSeek();
}
@@ -195,22 +206,6 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
void MediaPlayerPrivate::setEndTime(float time)
{
m_endTime = time;
- startEndPointTimerIfNeeded();
-}
-
-void MediaPlayerPrivate::startEndPointTimerIfNeeded()
-{
- if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive())
- m_endPointTimer.startRepeating(endPointTimerInterval);
-}
-
-void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
-{
- float time = currentTime();
- if (time >= m_endTime) {
- pause();
- didEnd();
- }
}
bool MediaPlayerPrivate::paused() const
@@ -325,42 +320,44 @@ void MediaPlayerPrivate::updateStates()
long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError;
- if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData && !m_player->inMediaDocument()) {
- unsigned enabledTrackCount;
- m_qtMovie->disableUnsupportedTracks(enabledTrackCount);
- // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692>
- if (!enabledTrackCount)
+ if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata && !m_player->inMediaDocument()) {
+ m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount);
+ if (!m_enabledTrackCount)
loadState = QTMovieLoadStateError;
}
// "Loaded" is reserved for fully buffered movies, never the case when streaming
if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
- if (m_networkState < MediaPlayer::Loaded)
- m_networkState = MediaPlayer::Loaded;
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (loadState >= QTMovieLoadStatePlaythroughOK) {
- if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
- m_networkState = MediaPlayer::LoadedFirstFrame;
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (loadState >= QTMovieLoadStatePlayable) {
- if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
- m_networkState = MediaPlayer::LoadedFirstFrame;
- m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable;
+ // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
} else if (loadState >= QTMovieLoadStateLoaded) {
- if (m_networkState < MediaPlayer::LoadedMetaData)
- m_networkState = MediaPlayer::LoadedMetaData;
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveMetadata;
} else if (loadState > QTMovieLoadStateError) {
- if (m_networkState < MediaPlayer::Loading)
- m_networkState = MediaPlayer::Loading;
- m_readyState = MediaPlayer::DataUnavailable;
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveNothing;
} else {
- m_networkState = MediaPlayer::LoadFailed;
- m_readyState = MediaPlayer::DataUnavailable;
+ float loaded = maxTimeLoaded();
+ if (!loaded)
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (!m_enabledTrackCount)
+ m_networkState = MediaPlayer::FormatError;
+ else {
+ // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
+ if (loaded > 0)
+ m_networkState = MediaPlayer::DecodeError;
+ else
+ m_readyState = MediaPlayer::HaveNothing;
+ }
}
if (seeking())
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveNothing;
if (m_networkState != oldNetworkState)
m_player->networkStateChanged();
@@ -371,7 +368,6 @@ void MediaPlayerPrivate::updateStates()
void MediaPlayerPrivate::didEnd()
{
- m_endPointTimer.stop();
m_startedPlaying = false;
#if DRAW_FRAME_RATE
m_timeStoppedPlaying = GetTickCount();
@@ -380,10 +376,10 @@ void MediaPlayerPrivate::didEnd()
m_player->timeChanged();
}
-void MediaPlayerPrivate::setRect(const IntRect& r)
+void MediaPlayerPrivate::setSize(const IntSize& size)
{
if (m_qtMovie)
- m_qtMovie->setSize(r.width(), r.height());
+ m_qtMovie->setSize(size.width(), size.height());
}
void MediaPlayerPrivate::setVisible(bool b)
@@ -403,7 +399,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
#if DRAW_FRAME_RATE
if (m_frameCountWhilePlaying > 10) {
- Frame* frame = m_player->m_frameView ? m_player->m_frameView->frame() : NULL;
+ Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : NULL;
Document* document = frame ? frame->document() : NULL;
RenderObject* renderer = document ? document->renderer() : NULL;
RenderStyle* styleToUse = renderer ? renderer->style() : NULL;
@@ -427,16 +423,30 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
#endif
}
-void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+static HashSet<String> mimeTypeCache()
{
- unsigned count = QTMovieWin::countSupportedTypes();
- for (unsigned n = 0; n < count; n++) {
- const UChar* character;
- unsigned len;
- QTMovieWin::getSupportedType(n, character, len);
- if (len)
- types.add(String(character, len));
+ DEFINE_STATIC_LOCAL(HashSet<String>, typeCache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ unsigned count = QTMovieWin::countSupportedTypes();
+ for (unsigned n = 0; n < count; n++) {
+ const UChar* character;
+ unsigned len;
+ QTMovieWin::getSupportedType(n, character, len);
+ if (len)
+ typeCache.add(String(character, len));
+ }
+
+ typeListInitialized = true;
}
+
+ return typeCache;
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+{
+ types = mimeTypeCache();
}
bool MediaPlayerPrivate::isAvailable()
@@ -444,6 +454,13 @@ bool MediaPlayerPrivate::isAvailable()
return QTMovieWin::initializeQuickTime();
}
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
+ // extended MIME type
+ return mimeTypeCache().contains(type) ? (!codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
void MediaPlayerPrivate::movieEnded(QTMovieWin* movie)
{
ASSERT(m_qtMovie.get() == movie);
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
index c4c893c..63aa62b 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,7 +28,7 @@
#if ENABLE(VIDEO)
-#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
#include "Timer.h"
#include <QTMovieWin.h>
#include <wtf/OwnPtr.h>
@@ -44,9 +44,10 @@ class IntSize;
class IntRect;
class String;
-class MediaPlayerPrivate : QTMovieWinClient, Noncopyable {
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface, public QTMovieWinClient {
public:
- MediaPlayerPrivate(MediaPlayer*);
+ static void registerMediaEngine(MediaEngineRegistrar);
+
~MediaPlayerPrivate();
IntSize naturalSize() const;
@@ -81,38 +82,42 @@ public:
unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect&);
+ void setSize(const IntSize&);
void loadStateChanged();
void didEnd();
void paint(GraphicsContext*, const IntRect&);
- static void getSupportedTypes(HashSet<String>& types);
- static bool isAvailable();
private:
+ MediaPlayerPrivate(MediaPlayer*);
+
void updateStates();
void doSeek();
void cancelSeek();
void seekTimerFired(Timer<MediaPlayerPrivate>*);
- void endPointTimerFired(Timer<MediaPlayerPrivate>*);
float maxTimeLoaded() const;
- void startEndPointTimerIfNeeded();
virtual void movieEnded(QTMovieWin*);
virtual void movieLoadStateChanged(QTMovieWin*);
virtual void movieTimeChanged(QTMovieWin*);
virtual void movieNewImageAvailable(QTMovieWin*);
-
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer*);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
MediaPlayer* m_player;
OwnPtr<QTMovieWin> m_qtMovie;
float m_seekTo;
float m_endTime;
Timer<MediaPlayerPrivate> m_seekTimer;
- Timer<MediaPlayerPrivate> m_endPointTimer;
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
+ unsigned m_enabledTrackCount;
bool m_startedPlaying;
bool m_isStreaming;
#if DRAW_FRAME_RATE
diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp
index 32aecd3..3f23698 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.cpp
+++ b/WebCore/platform/graphics/win/QTMovieWin.cpp
@@ -658,6 +658,12 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount)
continue;
if (!allowedTrackTypes->contains(mediaType)) {
+
+ // Different mpeg variants import as different track types so check for the "mpeg
+ // characteristic" instead of hard coding the (current) list of mpeg media types.
+ if (GetMovieIndTrackType(m_private->m_movie, 1, 'mpeg', movieTrackCharacteristic | movieTrackEnabledOnly))
+ continue;
+
SetTrackEnabled(currentTrack, false);
--enabledTrackCount;
}
diff --git a/WebCore/platform/graphics/win/QTMovieWinTimer.cpp b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
index d0aa3e6..f6103ea 100644
--- a/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
+++ b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2009 Apple Computer, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -51,6 +51,9 @@ static LRESULT CALLBACK TimerWindowWndProc(HWND hWnd, UINT message, WPARAM wPara
processingCustomTimerMessage = true;
sharedTimerFiredFunction();
processingCustomTimerMessage = false;
+ } else if (message == WM_TIMER && wParam == timerID) {
+ stopSharedTimer();
+ sharedTimerFiredFunction();
} else
return DefWindowProc(hWnd, message, wParam, lParam);
return 0;
@@ -79,11 +82,6 @@ void setSharedTimerFiredFunction(void (*f)())
sharedTimerFiredFunction = f;
}
-static void CALLBACK timerFired(HWND, UINT, UINT_PTR, DWORD)
-{
- sharedTimerFiredFunction();
-}
-
void setSharedTimerFireDelay(double interval)
{
ASSERT(sharedTimerFiredFunction);
@@ -99,29 +97,27 @@ void setSharedTimerFireDelay(double interval)
intervalInMS = (unsigned)interval;
}
- if (timerID) {
- KillTimer(0, timerID);
- timerID = 0;
- }
+ stopSharedTimer();
+ initializeOffScreenTimerWindow();
// We don't allow nested PostMessages, since the custom messages will effectively starve
// painting and user input. (Win32 has a tri-level queue with application messages >
// user input > WM_PAINT/WM_TIMER.)
// In addition, if the queue contains input events that have been there since the last call to
// GetQueueStatus, PeekMessage or GetMessage we favor timers.
- if (intervalInMS < USER_TIMER_MINIMUM && processingCustomTimerMessage &&
- !LOWORD(::GetQueueStatus(QS_ALLINPUT))) {
+ if (intervalInMS < USER_TIMER_MINIMUM
+ && !processingCustomTimerMessage
+ && !LOWORD(::GetQueueStatus(QS_ALLINPUT))) {
// Windows SetTimer does not allow timeouts smaller than 10ms (USER_TIMER_MINIMUM)
- initializeOffScreenTimerWindow();
PostMessage(timerWindowHandle, timerFiredMessage, 0, 0);
} else
- timerID = SetTimer(0, 0, intervalInMS, timerFired);
+ timerID = SetTimer(timerWindowHandle, timerFiredMessage, intervalInMS, 0);
}
void stopSharedTimer()
{
if (timerID) {
- KillTimer(0, timerID);
+ KillTimer(timerWindowHandle, timerID);
timerID = 0;
}
}
diff --git a/WebCore/platform/graphics/wx/FontCacheWx.cpp b/WebCore/platform/graphics/wx/FontCacheWx.cpp
index db107e4..db107e4 100755..100644
--- a/WebCore/platform/graphics/wx/FontCacheWx.cpp
+++ b/WebCore/platform/graphics/wx/FontCacheWx.cpp
diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h
index d2394dc..c77968a 100644
--- a/WebCore/platform/graphics/wx/FontPlatformData.h
+++ b/WebCore/platform/graphics/wx/FontPlatformData.h
@@ -30,41 +30,59 @@
#define FontPlatformData_H
#include "FontDescription.h"
-#include "CString.h"
#include "AtomicString.h"
+#include "CString.h"
#include "StringImpl.h"
+#include <wtf/RefPtr.h>
#include <wx/defs.h>
#include <wx/font.h>
namespace WebCore {
+class FontHolder: public WTF::RefCounted<FontHolder>
+{
+public:
+ FontHolder()
+ : m_font(0)
+ {}
+
+ FontHolder(wxFont* font)
+ : m_font(font)
+ {}
+
+ wxFont* font() { return m_font; }
+
+private:
+ wxFont* m_font;
+};
+
class FontPlatformData {
public:
enum FontState { UNINITIALIZED, DELETED, VALID };
FontPlatformData(WTF::HashTableDeletedValueType)
- : m_fontState(DELETED)
+ : m_fontState(DELETED),
+ m_font(0)
{ }
~FontPlatformData();
- FontPlatformData(wxFont f)
- : m_font(f)
- , m_fontState(VALID)
+ FontPlatformData(const FontDescription&, const AtomicString&);
+ FontPlatformData(float size, bool bold, bool italic)
+ : m_fontState(UNINITIALIZED)
+ , m_font(0)
{
- m_fontHash = computeHash();
}
- FontPlatformData(const FontDescription&, const AtomicString&);
-
FontPlatformData()
: m_fontState(UNINITIALIZED)
+ , m_font(0)
{
}
- wxFont font() const {
- return m_font;
+ wxFont* font() const {
+ return m_font->font();
}
unsigned hash() const {
@@ -78,32 +96,26 @@ public:
}
}
+ unsigned computeHash() const;
+
bool operator==(const FontPlatformData& other) const
{
- if (m_fontState == VALID)
- return other.m_fontState == VALID && m_font.IsOk() && other.m_font.IsOk() && m_font.IsSameAs(other.m_font);
+ if (m_font && m_fontState == VALID && other.m_fontState == VALID && other.m_font) {
+ wxFont* thisFont = m_font->font();
+ wxFont* otherFont = other.m_font->font();
+ return thisFont->IsOk() && otherFont->IsOk() && thisFont->IsSameAs(*otherFont);
+ }
else
return m_fontState == other.m_fontState;
}
bool isHashTableDeletedValue() const { return m_fontState == DELETED; }
- unsigned computeHash() const {
- ASSERT(m_font.IsOk());
-
- // make a hash that is unique for this font, but not globally unique - that is,
- // a font whose properties are equal should generate the same hash
- uintptr_t hashCodes[6] = { m_font.GetPointSize(), m_font.GetFamily(), m_font.GetStyle(),
- m_font.GetWeight(), m_font.GetUnderlined(),
- StringImpl::computeHash(m_font.GetFaceName().mb_str(wxConvUTF8)) };
-
- return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
- }
+
private:
- wxFont m_font;
- FontState m_fontState;
- unsigned m_fontHash;
+ WTF::RefPtr<FontHolder> m_font;
+ FontState m_fontState;
};
}
diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
index 7162eab..ce5e40e 100755..100644
--- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
+++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
@@ -58,6 +58,9 @@ static wxFontWeight fontWeightToWxFontWeight(FontWeight weight)
{
if (weight >= FontWeight600)
return wxFONTWEIGHT_BOLD;
+
+ if (weight <= FontWeight300)
+ return wxFONTWEIGHT_LIGHT;
return wxFONTWEIGHT_NORMAL;
}
@@ -78,30 +81,45 @@ FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicStri
// this is a moot issue on Linux and Mac as they only accept the point argument. So,
// we use the pixel size constructor on Windows, but we use point size on Linux and Mac.
#if __WXMSW__
- m_font = wxFont( wxSize(0, -desc.computedPixelSize()),
+ m_font = new FontHolder(new wxFont( wxSize(0, -desc.computedPixelSize()),
fontFamilyToWxFontFamily(desc.genericFamily()),
italicToWxFontStyle(desc.italic()),
fontWeightToWxFontWeight(desc.weight()),
false,
family.string()
- );
+ )
+ );
#else
- m_font = wxFont( desc.computedPixelSize(),
+ m_font = new FontHolder(new wxFont( desc.computedPixelSize(),
fontFamilyToWxFontFamily(desc.genericFamily()),
italicToWxFontStyle(desc.italic()),
fontWeightToWxFontWeight(desc.weight()),
false,
family.string()
- );
+ )
+ );
#endif
m_fontState = VALID;
- m_fontHash = computeHash();
}
-
+
+unsigned FontPlatformData::computeHash() const {
+ wxFont* thisFont = m_font->font();
+ ASSERT(thisFont && thisFont->IsOk());
+
+ // make a hash that is unique for this font, but not globally unique - that is,
+ // a font whose properties are equal should generate the same hash
+ uintptr_t hashCodes[6] = { thisFont->GetPointSize(), thisFont->GetFamily(), thisFont->GetStyle(),
+ thisFont->GetWeight(), thisFont->GetUnderlined(),
+ StringImpl::computeHash(thisFont->GetFaceName().mb_str(wxConvUTF8)) };
+
+ return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+}
+
FontPlatformData::~FontPlatformData()
{
m_fontState = UNINITIALIZED;
+ m_font = 0;
}
}
diff --git a/WebCore/platform/graphics/wx/GlyphMapWx.cpp b/WebCore/platform/graphics/wx/GlyphMapWx.cpp
index ebf86e4..ebf86e4 100755..100644
--- a/WebCore/platform/graphics/wx/GlyphMapWx.cpp
+++ b/WebCore/platform/graphics/wx/GlyphMapWx.cpp
diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
index d523354..fc8ce71 100644
--- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
@@ -170,7 +170,7 @@ void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer*
delete m_decoder;
m_decoder = 0;
if (data)
- setData(data, allDataReceived);
+ setData(data, allDataReceived);
}
NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp
index e52e9ff..e1d435e 100644
--- a/WebCore/platform/graphics/wx/ImageWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageWx.cpp
@@ -237,7 +237,7 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c
void BitmapImage::checkForSolidColor()
{
-
+ m_checkedForSolidColor = true;
}
void BitmapImage::invalidatePlatformData()
diff --git a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
index a509933..ab50518 100755..100644
--- a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
+++ b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
@@ -45,14 +45,16 @@ namespace WebCore
void SimpleFontData::platformInit()
{
- wxFont font = m_font.font();
- wxFontProperties props = wxFontProperties(&font);
- m_ascent = props.GetAscent();
- m_descent = props.GetDescent();
- m_lineSpacing = props.GetLineSpacing();
- m_xHeight = props.GetXHeight();
- m_unitsPerEm = 1; // FIXME!
- m_lineGap = props.GetLineGap();
+ wxFont *font = m_font.font();
+ if (font && font->IsOk()) {
+ wxFontProperties props = wxFontProperties(font);
+ m_ascent = props.GetAscent();
+ m_descent = props.GetDescent();
+ m_lineSpacing = props.GetLineSpacing();
+ m_xHeight = props.GetXHeight();
+ m_unitsPerEm = 1; // FIXME!
+ m_lineGap = props.GetLineGap();
+ }
}
void SimpleFontData::platformDestroy()
@@ -79,8 +81,8 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con
void SimpleFontData::determinePitch()
{
- if (m_font.font().Ok())
- m_treatAsFixedPitch = m_font.font().IsFixedWidth();
+ if (m_font.font() && m_font.font()->Ok())
+ m_treatAsFixedPitch = m_font.font()->IsFixedWidth();
else
m_treatAsFixedPitch = false;
}
@@ -89,7 +91,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
// TODO: fix this! Make GetTextExtents a method of wxFont in 2.9
int width = 10;
- GetTextExtent(m_font.font(), (wxChar)glyph, &width, NULL);
+ GetTextExtent(*m_font.font(), (wxChar)glyph, &width, NULL);
return width;
}
diff --git a/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
index e6a02b8..f21dc17 100644
--- a/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
+++ b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
@@ -37,235 +37,14 @@
namespace WebCore {
#if USE(WXGC)
-TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix)
-{
- m_transform = matrix;
-}
-#endif
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double e, double f)
-{
-#if USE(WXGC)
- wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
- m_transform = renderer->CreateMatrix();
-#endif
- setMatrix(a, b, c, d, e, f);
-}
-
-TransformationMatrix::TransformationMatrix()
-{
- // NB: If we ever support using Cairo backend on Win/Mac, this will need to be
- // changed somehow (though I'm not sure how as we don't have a reference to the
- // graphics context here.
-#if USE(WXGC)
- wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
- m_transform = renderer->CreateMatrix();
-#endif
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- notImplemented();
- return *this;
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double e, double f)
-{
-#if USE(WXGC)
- m_transform.Set(a, b, c, d, e, f);
-#endif
-}
-
-void TransformationMatrix::map(double x, double y, double *x2, double *y2) const
-{
- notImplemented();
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect &rect) const
-{
-#if USE(WXGC)
- double x, y, width, height;
- x = rect.x();
- y = rect.y();
- width = rect.width();
- height = rect.height();
-
- m_transform.TransformPoint(&x, &y);
- m_transform.TransformDistance(&width, &height);
- return IntRect(x, y, width, height);
-#endif
- return IntRect();
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
-{
-#if USE(WXGC)
- double x, y, width, height;
- x = rect.x();
- y = rect.y();
- width = rect.width();
- height = rect.height();
-
- m_transform.TransformPoint(&x, &y);
- m_transform.TransformDistance(&width, &height);
- return FloatRect(x, y, width, height);
-#endif
- return FloatRect();
-}
-
-
-TransformationMatrix& TransformationMatrix::scale(double sx, double sy)
-{
-#if USE(WXGC)
- m_transform.Scale((wxDouble)sx, (wxDouble)sy);
-#endif
- return *this;
-}
-
-void TransformationMatrix::reset()
-{
- notImplemented();
-}
-
-TransformationMatrix& TransformationMatrix::rotate(double d)
-{
-#if USE(WXGC)
- m_transform.Rotate((wxDouble)d);
-#endif
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
-{
-#if USE(WXGC)
- m_transform.Translate((wxDouble)tx, (wxDouble)ty);
-#endif
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::shear(double sx, double sy)
-{
- notImplemented();
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::operator*=(const TransformationMatrix& other)
-{
- notImplemented();
- return *this;
-}
-
-bool TransformationMatrix::operator== (const TransformationMatrix &other) const
-{
-#if USE(WXGC)
- return m_transform.IsEqual((wxGraphicsMatrix)other);
-#else
- notImplemented();
- return true;
-#endif
-}
-
-TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &other)
-{
- notImplemented();
- return *this; //m_transform * other.m_transform;
-}
-
-double TransformationMatrix::det() const
-{
- notImplemented();
- return 0;
-}
-
-#if USE(WXGC)
TransformationMatrix::operator wxGraphicsMatrix() const
{
- return m_transform;
-}
-#endif
-
-double TransformationMatrix::a() const
-{
- double a = 0;
-#if USE(WXGC)
- m_transform.Get(&a);
-#endif
- return a;
-}
-
-void TransformationMatrix::setA(double a)
-{
- setMatrix(a, b(), c(), d(), e(), f());
-}
-
-double TransformationMatrix::b() const
-{
- double b = 0;
-#if USE(WXGC)
- m_transform.Get(&b);
-#endif
- return b;
-}
-
-void TransformationMatrix::setB(double b)
-{
- setMatrix(a(), b, c(), d(), e(), f());
-}
-
-double TransformationMatrix::c() const
-{
- double c = 0;
-#if USE(WXGC)
- m_transform.Get(&c);
-#endif
- return c;
-}
-
-void TransformationMatrix::setC(double c)
-{
- setMatrix(a(), b(), c, d(), e(), f());
-}
-
-double TransformationMatrix::d() const
-{
- double d = 0;
-#if USE(WXGC)
- m_transform.Get(&d);
-#endif
- return d;
-}
-
-void TransformationMatrix::setD(double d)
-{
- setMatrix(a(), b(), c(), d, e(), f());
-}
-
-double TransformationMatrix::e() const
-{
- double e = 0;
-#if USE(WXGC)
- m_transform.Get(&e);
-#endif
- return e;
-}
-
-void TransformationMatrix::setE(double e)
-{
- setMatrix(a(), b(), c(), d(), e, f());
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ ASSERT(renderer);
+
+ wxGraphicsMatrix matrix = renderer->CreateMatrix(a(), b(), c(), d(), e(), f());
+ return matrix;
}
-
-double TransformationMatrix::f() const
-{
- double f = 0;
-#if USE(WXGC)
- m_transform.Get(&f);
#endif
- return f;
-}
-
-void TransformationMatrix::setF(double f)
-{
- setMatrix(a(), b(), c(), d(), e(), f);
-}
}
diff --git a/WebCore/platform/gtk/ContextMenuGtk.cpp b/WebCore/platform/gtk/ContextMenuGtk.cpp
index 2365379..210cfa6 100644
--- a/WebCore/platform/gtk/ContextMenuGtk.cpp
+++ b/WebCore/platform/gtk/ContextMenuGtk.cpp
@@ -39,12 +39,7 @@ ContextMenu::ContextMenu(const HitTestResult& result)
{
m_platformDescription = GTK_MENU(gtk_menu_new());
-#if GLIB_CHECK_VERSION(2,10,0)
g_object_ref_sink(G_OBJECT(m_platformDescription));
-#else
- g_object_ref(G_OBJECT(m_platformDescription));
- gtk_object_sink(GTK_OBJECT(m_platformDescription));
-#endif
}
ContextMenu::~ContextMenu()
diff --git a/WebCore/platform/gtk/ContextMenuItemGtk.cpp b/WebCore/platform/gtk/ContextMenuItemGtk.cpp
index 84f78c0..cf34640 100644
--- a/WebCore/platform/gtk/ContextMenuItemGtk.cpp
+++ b/WebCore/platform/gtk/ContextMenuItemGtk.cpp
@@ -232,12 +232,7 @@ void ContextMenuItem::setSubMenu(ContextMenu* menu)
m_platformDescription.subMenu = menu->releasePlatformDescription();
m_platformDescription.type = SubmenuType;
-#if GLIB_CHECK_VERSION(2,10,0)
g_object_ref_sink(G_OBJECT(m_platformDescription.subMenu));
-#else
- g_object_ref(G_OBJECT(m_platformDescription.subMenu));
- gtk_object_sink(GTK_OBJECT(m_platformDescription.subMenu));
-#endif
}
void ContextMenuItem::setChecked(bool shouldCheck)
diff --git a/WebCore/platform/gtk/FileSystemGtk.cpp b/WebCore/platform/gtk/FileSystemGtk.cpp
index 4f0ae01..94e06db 100644
--- a/WebCore/platform/gtk/FileSystemGtk.cpp
+++ b/WebCore/platform/gtk/FileSystemGtk.cpp
@@ -229,7 +229,7 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
if (!isHandleValid(fileDescriptor)) {
LOG_ERROR("Can't create a temporary file.");
g_free(tempPath);
- return 0;
+ return CString();
}
CString tempFilePath = tempPath;
g_free(tempPath);
diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.cpp b/WebCore/platform/gtk/GeolocationServiceGtk.cpp
index 0c80dd6..cc69d44 100644
--- a/WebCore/platform/gtk/GeolocationServiceGtk.cpp
+++ b/WebCore/platform/gtk/GeolocationServiceGtk.cpp
@@ -20,6 +20,21 @@
#include "config.h"
#include "GeolocationServiceGtk.h"
+#include "CString.h"
+#include "GOwnPtr.h"
+#include "NotImplemented.h"
+#include "PositionOptions.h"
+
+namespace WTF {
+ template<> void freeOwnedGPtr<GeoclueAccuracy>(GeoclueAccuracy* accuracy)
+ {
+ if (!accuracy)
+ return;
+
+ geoclue_accuracy_free(accuracy);
+ }
+}
+
namespace WebCore {
GeolocationService* GeolocationService::create(GeolocationServiceClient* client)
@@ -29,33 +44,170 @@ GeolocationService* GeolocationService::create(GeolocationServiceClient* client)
GeolocationServiceGtk::GeolocationServiceGtk(GeolocationServiceClient* client)
: GeolocationService(client)
-{}
+ , m_geoclueClient(0)
+ , m_geocluePosition(0)
+ , m_latitude(0.0)
+ , m_longitude(0.0)
+ , m_altitude(0.0)
+ , m_altitudeAccuracy(0.0)
+ , m_timestamp(0)
+{
+}
-bool GeolocationServiceGtk::startUpdating(PositionOptions*)
+GeolocationServiceGtk::~GeolocationServiceGtk()
{
- return false;
+ if (m_geoclueClient)
+ g_object_unref(m_geoclueClient);
+
+ if (m_geocluePosition)
+ g_object_unref(m_geocluePosition);
+}
+
+//
+// 1.) Initialize Geoclue with our requirements
+// 2.) Try to get a GeocluePosition
+// 3.) Update the Information and get the current position
+//
+// TODO: Also get GeoclueVelocity but there is no master client
+// API for that.
+//
+bool GeolocationServiceGtk::startUpdating(PositionOptions* options)
+{
+ ASSERT(!m_geoclueClient);
+
+ m_lastPosition = 0;
+ m_lastError = 0;
+
+ GOwnPtr<GError> error;
+ GeoclueMaster* master = geoclue_master_get_default();
+ GeoclueMasterClient* client = geoclue_master_create_client(master, 0, 0);
+ g_object_unref(master);
+
+ if (!client) {
+ setError(PositionError::UNKNOWN_ERROR, "Could not connect to location provider.");
+ return false;
+ }
+
+ GeoclueAccuracyLevel accuracyLevel = GEOCLUE_ACCURACY_LEVEL_LOCALITY;
+ int timeout = 0;
+ if (options) {
+ accuracyLevel = options->enableHighAccuracy() ? GEOCLUE_ACCURACY_LEVEL_DETAILED : GEOCLUE_ACCURACY_LEVEL_LOCALITY;
+ timeout = options->timeout();
+ }
+
+ gboolean result = geoclue_master_client_set_requirements(client, accuracyLevel, timeout,
+ true, GEOCLUE_RESOURCE_ALL, &error.outPtr());
+
+ if (!result) {
+ setError(PositionError::UNKNOWN_ERROR, error->message);
+ g_object_unref(client);
+ return false;
+ }
+
+ m_geocluePosition = geoclue_master_client_create_position(client, &error.outPtr());
+ if (!m_geocluePosition) {
+ setError(PositionError::UNKNOWN_ERROR, error->message);
+ g_object_unref(client);
+ return false;
+ }
+
+ g_signal_connect(G_OBJECT(m_geocluePosition), "position-changed",
+ G_CALLBACK(position_changed), this);
+
+ m_geoclueClient = client;
+ updateLocationInformation();
+
+ return true;
}
void GeolocationServiceGtk::stopUpdating()
{
+ if (!m_geoclueClient)
+ return;
+
+ g_object_unref(m_geocluePosition);
+ g_object_unref(m_geoclueClient);
+
+ m_geocluePosition = 0;
+ m_geoclueClient = 0;
}
void GeolocationServiceGtk::suspend()
{
+ // not available with geoclue
+ notImplemented();
}
void GeolocationServiceGtk::resume()
{
+ // not available with geoclue
+ notImplemented();
}
Geoposition* GeolocationServiceGtk::lastPosition() const
{
- return 0;
+ return m_lastPosition.get();
}
PositionError* GeolocationServiceGtk::lastError() const
{
- return 0;
+ return m_lastError.get();
+}
+
+void GeolocationServiceGtk::updateLocationInformation()
+{
+ ASSERT(m_geocluePosition);
+
+ GOwnPtr<GError> error;
+ GOwnPtr<GeoclueAccuracy> accuracy;
+
+ GeocluePositionFields fields = geoclue_position_get_position(m_geocluePosition, &m_timestamp,
+ &m_latitude, &m_longitude,
+ &m_altitude, &accuracy.outPtr(),
+ &error.outPtr());
+ if (error) {
+ setError(PositionError::POSITION_UNAVAILABLE, error->message);
+ return;
+ } else if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) {
+ setError(PositionError::POSITION_UNAVAILABLE, "Position could not be determined.");
+ return;
+ }
+
+
+}
+
+void GeolocationServiceGtk::updatePosition()
+{
+ m_lastError = 0;
+
+ RefPtr<Coordinates> coordinates = Coordinates::create(m_latitude, m_longitude,
+ m_altitude, m_accuracy,
+ m_altitudeAccuracy, 0.0, 0.0);
+ m_lastPosition = Geoposition::create(coordinates.release(), m_timestamp * 1000.0);
+ positionChanged();
+}
+
+void GeolocationServiceGtk::position_changed(GeocluePosition*, GeocluePositionFields fields, int timestamp, double latitude, double longitude, double altitude, GeoclueAccuracy* accuracy, GeolocationServiceGtk* that)
+{
+ if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) {
+ that->setError(PositionError::POSITION_UNAVAILABLE, "Position could not be determined.");
+ return;
+ }
+
+ that->m_timestamp = timestamp;
+ that->m_latitude = latitude;
+ that->m_longitude = longitude;
+ that->m_altitude = altitude;
+
+ GeoclueAccuracyLevel level;
+ geoclue_accuracy_get_details(accuracy, &level, &that->m_accuracy, &that->m_altitudeAccuracy);
+ that->updatePosition();
+}
+
+void GeolocationServiceGtk::setError(PositionError::ErrorCode errorCode, const char* message)
+{
+ m_lastPosition = 0;
+ m_lastError = PositionError::create(errorCode, String::fromUTF8(message));
}
}
diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.h b/WebCore/platform/gtk/GeolocationServiceGtk.h
index 02aff2d..90699ad 100644
--- a/WebCore/platform/gtk/GeolocationServiceGtk.h
+++ b/WebCore/platform/gtk/GeolocationServiceGtk.h
@@ -21,11 +21,18 @@
#define GeolocationServiceGtk_h
#include "GeolocationService.h"
+#include "Geoposition.h"
+#include "PositionError.h"
+#include "RefPtr.h"
+
+#include <geoclue/geoclue-master.h>
+#include <geoclue/geoclue-position.h>
namespace WebCore {
class GeolocationServiceGtk : public GeolocationService {
public:
GeolocationServiceGtk(GeolocationServiceClient*);
+ ~GeolocationServiceGtk();
virtual bool startUpdating(PositionOptions*);
virtual void stopUpdating();
@@ -35,6 +42,29 @@ namespace WebCore {
Geoposition* lastPosition() const;
PositionError* lastError() const;
+
+ private:
+ void updateLocationInformation();
+ void setError(PositionError::ErrorCode, const char* message);
+ void updatePosition();
+
+ static void position_changed(GeocluePosition*, GeocluePositionFields, int, double, double, double, GeoclueAccuracy*, GeolocationServiceGtk*);
+
+ private:
+ RefPtr<Geoposition> m_lastPosition;
+ RefPtr<PositionError> m_lastError;
+
+ // state objects
+ GeoclueMasterClient* m_geoclueClient;
+ GeocluePosition* m_geocluePosition;
+
+ // Error and Position state
+ double m_latitude;
+ double m_longitude;
+ double m_altitude;
+ double m_accuracy;
+ double m_altitudeAccuracy;
+ int m_timestamp;
};
}
diff --git a/WebCore/platform/gtk/LoggingGtk.cpp b/WebCore/platform/gtk/LoggingGtk.cpp
index 5bc1559..c46364c 100644
--- a/WebCore/platform/gtk/LoggingGtk.cpp
+++ b/WebCore/platform/gtk/LoggingGtk.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -20,12 +21,93 @@
#include "config.h"
#include "Logging.h"
+#include <glib.h>
+#include <string.h>
+
namespace WebCore {
+// Inspired by the code used by the Qt port
+
+static WTFLogChannel* getChannelFromName(const char* channelName)
+{
+ if (strlen(channelName) < 3)
+ return 0;
+
+ if (!g_ascii_strcasecmp(channelName, "BackForward"))
+ return &LogBackForward;
+ if (!g_ascii_strcasecmp(channelName, "Editing"))
+ return &LogEditing;
+ if (!g_ascii_strcasecmp(channelName, "Events"))
+ return &LogEvents;
+ if (!g_ascii_strcasecmp(channelName, "Frames"))
+ return &LogFrames;
+ if (!g_ascii_strcasecmp(channelName, "FTP"))
+ return &LogFTP;
+ if (!g_ascii_strcasecmp(channelName, "History"))
+ return &LogHistory;
+ if (!g_ascii_strcasecmp(channelName, "IconDatabase"))
+ return &LogIconDatabase;
+ if (!g_ascii_strcasecmp(channelName, "Loading"))
+ return &LogLoading;
+ if (!g_ascii_strcasecmp(channelName, "Media"))
+ return &LogMedia;
+ if (!g_ascii_strcasecmp(channelName, "Network"))
+ return &LogNetwork;
+ if (!g_ascii_strcasecmp(channelName, "NotYetImplemented"))
+ return &LogNotYetImplemented;
+ if (!g_ascii_strcasecmp(channelName, "PageCache"))
+ return &LogPageCache;
+ if (!g_ascii_strcasecmp(channelName, "PlatformLeaks"))
+ return &LogPlatformLeaks;
+ if (!g_ascii_strcasecmp(channelName, "Plugin"))
+ return &LogPlugin;
+ if (!g_ascii_strcasecmp(channelName, "PopupBlocking"))
+ return &LogPopupBlocking;
+ if (!g_ascii_strcasecmp(channelName, "SpellingAndGrammar"))
+ return &LogSpellingAndGrammar;
+ if (!g_ascii_strcasecmp(channelName, "SQLDatabase"))
+ return &LogSQLDatabase;
+ if (!g_ascii_strcasecmp(channelName, "StorageAPI"))
+ return &LogStorageAPI;
+ if (!g_ascii_strcasecmp(channelName, "TextConversion"))
+ return &LogTextConversion;
+ if (!g_ascii_strcasecmp(channelName, "Threading"))
+ return &LogThreading;
+
+ return 0;
+}
+
void InitializeLoggingChannelsIfNecessary()
{
- // FIXME: Add a way for the user to specify which
- // logs he/she would like turned on.
+ static bool didInitializeLoggingChannels = false;
+ if (didInitializeLoggingChannels)
+ return;
+
+ didInitializeLoggingChannels = true;
+
+ char* logEnv = getenv("WEBKIT_DEBUG");
+ if (!logEnv)
+ return;
+
+ // we set up the logs anyway because some of our logging, such as
+ // soup's is available in release builds
+#if defined(NDEBUG)
+ g_warning("WEBKIT_DEBUG is not empty, but this is a release build. Notice that many log messages will only appear in a debug build.");
+#endif
+
+ char** logv = g_strsplit(logEnv, " ", -1);
+
+ for (int i = 0; logv[i]; i++) {
+ WTFLogChannel* channel = getChannelFromName(logv[i]);
+ if (!channel)
+ continue;
+ channel->state = WTFLogChannelOn;
+ }
+
+ g_strfreev(logv);
+
+ // to disable logging notImplemented set the DISABLE_NI_WARNING
+ // environment variable to 1
LogNotYetImplemented.state = WTFLogChannelOn;
}
diff --git a/WebCore/platform/gtk/PopupMenuGtk.cpp b/WebCore/platform/gtk/PopupMenuGtk.cpp
index 85c5aa0..54b41ab 100644
--- a/WebCore/platform/gtk/PopupMenuGtk.cpp
+++ b/WebCore/platform/gtk/PopupMenuGtk.cpp
@@ -52,12 +52,7 @@ void PopupMenu::show(const IntRect& rect, FrameView* view, int index)
if (!m_popup) {
m_popup = GTK_MENU(gtk_menu_new());
-#if GLIB_CHECK_VERSION(2,10,0)
g_object_ref_sink(G_OBJECT(m_popup));
-#else
- g_object_ref(G_OBJECT(m_popup));
- gtk_object_sink(GTK_OBJECT(m_popup));
-#endif
g_signal_connect(m_popup, "unmap", G_CALLBACK(menuUnmapped), this);
} else
gtk_container_foreach(GTK_CONTAINER(m_popup), reinterpret_cast<GtkCallback>(menuRemoveItem), this);
diff --git a/WebCore/platform/gtk/ScrollViewGtk.cpp b/WebCore/platform/gtk/ScrollViewGtk.cpp
index e1316ee..b3b6dd9 100644
--- a/WebCore/platform/gtk/ScrollViewGtk.cpp
+++ b/WebCore/platform/gtk/ScrollViewGtk.cpp
@@ -154,7 +154,7 @@ bool ScrollView::platformHandleHorizontalAdjustment(const IntSize& scroll)
m_horizontalAdjustment->upper = contentsWidth();
gtk_adjustment_changed(m_horizontalAdjustment);
- if (m_scrollOffset.width() != scroll.width()) {
+ if (m_horizontalAdjustment->value != scroll.width()) {
m_horizontalAdjustment->value = scroll.width();
gtk_adjustment_value_changed(m_horizontalAdjustment);
}
@@ -173,7 +173,7 @@ bool ScrollView::platformHandleVerticalAdjustment(const IntSize& scroll)
m_verticalAdjustment->upper = contentsHeight();
gtk_adjustment_changed(m_verticalAdjustment);
- if (m_scrollOffset.height() != scroll.height()) {
+ if (m_verticalAdjustment->value != scroll.height()) {
m_verticalAdjustment->value = scroll.height();
gtk_adjustment_value_changed(m_verticalAdjustment);
}
diff --git a/WebCore/platform/gtk/ScrollbarGtk.cpp b/WebCore/platform/gtk/ScrollbarGtk.cpp
index df165e3..7543e23 100644
--- a/WebCore/platform/gtk/ScrollbarGtk.cpp
+++ b/WebCore/platform/gtk/ScrollbarGtk.cpp
@@ -44,19 +44,18 @@ static gboolean gtkScrollEventCallback(GtkWidget* widget, GdkEventScroll* event,
}
ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orientation,
- ScrollbarControlSize controlSize)
+ ScrollbarControlSize controlSize)
: Scrollbar(client, orientation, controlSize)
, m_adjustment(GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)))
{
- GtkScrollbar* scrollBar = orientation == HorizontalScrollbar ?
- GTK_SCROLLBAR(::gtk_hscrollbar_new(m_adjustment)) :
- GTK_SCROLLBAR(::gtk_vscrollbar_new(m_adjustment));
- gtk_widget_show(GTK_WIDGET(scrollBar));
- g_object_ref(G_OBJECT(scrollBar));
- g_signal_connect(G_OBJECT(scrollBar), "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this);
- g_signal_connect(G_OBJECT(scrollBar), "scroll-event", G_CALLBACK(gtkScrollEventCallback), this);
+ GtkWidget* scrollBar = orientation == HorizontalScrollbar ?
+ gtk_hscrollbar_new(m_adjustment):
+ gtk_vscrollbar_new(m_adjustment);
+ gtk_widget_show(scrollBar);
+ g_signal_connect(scrollBar, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this);
+ g_signal_connect(scrollBar, "scroll-event", G_CALLBACK(gtkScrollEventCallback), this);
- setPlatformWidget(GTK_WIDGET(scrollBar));
+ setPlatformWidget(scrollBar);
/*
* assign a sane default width and height to the Scrollbar, otherwise
@@ -66,22 +65,24 @@ ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orienta
ScrollbarTheme::nativeTheme()->scrollbarThickness());
}
-ScrollbarGtk::~ScrollbarGtk()
+IntPoint ScrollbarGtk::getLocationInParentWindow(const IntRect& rect)
{
- /*
- * the Widget does not take over ownership.
- */
- g_signal_handlers_disconnect_by_func(G_OBJECT(platformWidget()), (gpointer)ScrollbarGtk::gtkValueChanged, this);
- g_signal_handlers_disconnect_by_func(G_OBJECT(platformWidget()), (gpointer)gtkScrollEventCallback, this);
- g_object_unref(G_OBJECT(platformWidget()));
+ IntPoint loc;
+
+ if (parent()->isScrollViewScrollbar(this))
+ loc = parent()->convertToContainingWindow(rect.location());
+ else
+ loc = parent()->contentsToWindow(rect.location());
+
+ return loc;
}
void ScrollbarGtk::frameRectsChanged()
{
- if (!parent() || !parent()->isScrollViewScrollbar(this))
+ if (!parent())
return;
- IntPoint loc = parent()->convertToContainingWindow(frameRect().location());
+ IntPoint loc = getLocationInParentWindow(frameRect());
// Don't allow the allocation size to be negative
IntSize sz = frameRect().size();
@@ -129,5 +130,44 @@ void ScrollbarGtk::setEnabled(bool shouldEnable)
gtk_widget_set_sensitive(platformWidget(), shouldEnable);
}
+/*
+ * Strategy to painting a Widget:
+ * 1.) do not paint if there is no GtkWidget set
+ * 2.) We assume that GTK_NO_WINDOW is set and that frameRectsChanged positioned
+ * the widget correctly. ATM we do not honor the GraphicsContext translation.
+ */
+void ScrollbarGtk::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!platformWidget())
+ return;
+
+ if (!context->gdkExposeEvent())
+ return;
+
+ GtkWidget* widget = platformWidget();
+ ASSERT(GTK_WIDGET_NO_WINDOW(widget));
+ GdkEvent* event = gdk_event_new(GDK_EXPOSE);
+ event->expose = *context->gdkExposeEvent();
+ event->expose.area = static_cast<GdkRectangle>(rect);
+ IntPoint loc = getLocationInParentWindow(rect);
+
+ event->expose.area.x = loc.x();
+ event->expose.area.y = loc.y();
+
+ event->expose.region = gdk_region_rectangle(&event->expose.area);
+
+ /*
+ * This will be unref'ed by gdk_event_free.
+ */
+ g_object_ref(event->expose.window);
+
+ /*
+ * If we are going to paint do the translation and GtkAllocation manipulation.
+ */
+ if (!gdk_region_empty(event->expose.region))
+ gtk_widget_send_expose(widget, event);
+
+ gdk_event_free(event);
+}
diff --git a/WebCore/platform/gtk/ScrollbarGtk.h b/WebCore/platform/gtk/ScrollbarGtk.h
index 11ff079..1ef4c49 100644
--- a/WebCore/platform/gtk/ScrollbarGtk.h
+++ b/WebCore/platform/gtk/ScrollbarGtk.h
@@ -37,9 +37,8 @@ class ScrollbarGtk : public Scrollbar {
public:
friend class Scrollbar;
- virtual ~ScrollbarGtk();
-
virtual void setFrameRect(const IntRect&);
+ virtual void paint(GraphicsContext*, const IntRect&);
virtual bool handleMouseMoveEvent(const PlatformMouseEvent&) { return false; }
virtual bool handleMouseOutEvent(const PlatformMouseEvent&) { return false; }
@@ -58,6 +57,7 @@ protected:
private:
static void gtkValueChanged(GtkAdjustment*, ScrollbarGtk*);
+ IntPoint getLocationInParentWindow(const IntRect&);
GtkAdjustment* m_adjustment;
};
diff --git a/WebCore/platform/gtk/WheelEventGtk.cpp b/WebCore/platform/gtk/WheelEventGtk.cpp
index 64ec65a..075bed2 100644
--- a/WebCore/platform/gtk/WheelEventGtk.cpp
+++ b/WebCore/platform/gtk/WheelEventGtk.cpp
@@ -27,6 +27,7 @@
#include "config.h"
#include "PlatformWheelEvent.h"
+#include "Scrollbar.h"
#include <gdk/gdk.h>
@@ -52,16 +53,18 @@ PlatformWheelEvent::PlatformWheelEvent(GdkEventScroll* event)
m_deltaY = -delta;
break;
case GDK_SCROLL_LEFT:
- m_deltaX = -delta;
+ m_deltaX = delta;
break;
case GDK_SCROLL_RIGHT:
- m_deltaX = delta;
+ m_deltaX = -delta;
break;
}
+ m_wheelTicksX = m_deltaX;
+ m_wheelTicksY = m_deltaY;
- m_position = IntPoint((int)event->x, (int)event->y);
- m_globalPosition = IntPoint((int)event->x_root, (int)event->y_root);
- m_granularity = ScrollByLineWheelEvent;
+ m_position = IntPoint(static_cast<int>(event->x), static_cast<int>(event->y));
+ m_globalPosition = IntPoint(static_cast<int>(event->x_root), static_cast<int>(event->y_root));
+ m_granularity = ScrollByPixelWheelEvent;
m_isAccepted = false;
m_shiftKey = event->state & GDK_SHIFT_MASK;
m_ctrlKey = event->state & GDK_CONTROL_MASK;
@@ -74,8 +77,8 @@ PlatformWheelEvent::PlatformWheelEvent(GdkEventScroll* event)
#endif
// FIXME: retrieve the user setting for the number of lines to scroll on each wheel event
- m_deltaX *= horizontalLineMultiplier();
- m_deltaY *= verticalLineMultiplier();
+ m_deltaX *= static_cast<float>(cScrollbarPixelsPerLineStep);
+ m_deltaY *= static_cast<float>(cScrollbarPixelsPerLineStep);
}
}
diff --git a/WebCore/platform/gtk/WidgetGtk.cpp b/WebCore/platform/gtk/WidgetGtk.cpp
index 82fed74..4f09e77 100644
--- a/WebCore/platform/gtk/WidgetGtk.cpp
+++ b/WebCore/platform/gtk/WidgetGtk.cpp
@@ -41,23 +41,17 @@
namespace WebCore {
-class WidgetPrivate {
-public:
- GdkCursor* cursor;
-};
+static GdkCursor* lastSetCursor;
Widget::Widget(PlatformWidget widget)
- : m_data(new WidgetPrivate)
{
init(widget);
- m_data->cursor = 0;
}
Widget::~Widget()
{
ASSERT(!parent());
releasePlatformWidget();
- delete m_data;
}
void Widget::setFocus()
@@ -65,11 +59,6 @@ void Widget::setFocus()
gtk_widget_grab_focus(platformWidget() ? platformWidget() : GTK_WIDGET(root()->hostWindow()->platformWindow()));
}
-Cursor Widget::cursor()
-{
- return Cursor(m_data->cursor);
-}
-
static GdkDrawable* gdkDrawable(PlatformWidget widget)
{
return widget ? widget->window : 0;
@@ -77,7 +66,7 @@ static GdkDrawable* gdkDrawable(PlatformWidget widget)
void Widget::setCursor(const Cursor& cursor)
{
- GdkCursor* pcur = cursor.impl();
+ GdkCursor* platformCursor = cursor.impl();
// http://bugs.webkit.org/show_bug.cgi?id=16388
// [GTK] Widget::setCursor() gets called frequently
@@ -85,11 +74,11 @@ void Widget::setCursor(const Cursor& cursor)
// gdk_window_set_cursor() in certain GDK backends seems to be an
// expensive operation, so avoid it if possible.
- if (pcur == m_data->cursor)
+ if (platformCursor == lastSetCursor)
return;
- gdk_window_set_cursor(gdkDrawable(platformWidget()) ? GDK_WINDOW(gdkDrawable(platformWidget())) : GTK_WIDGET(root()->hostWindow()->platformWindow())->window, pcur);
- m_data->cursor = pcur;
+ gdk_window_set_cursor(gdkDrawable(platformWidget()) ? GDK_WINDOW(gdkDrawable(platformWidget())) : GTK_WIDGET(root()->hostWindow()->platformWindow())->window, platformCursor);
+ lastSetCursor = platformCursor;
}
void Widget::show()
@@ -106,41 +95,8 @@ void Widget::hide()
gtk_widget_hide(platformWidget());
}
-/*
- * Strategy to painting a Widget:
- * 1.) do not paint if there is no GtkWidget set
- * 2.) We assume that GTK_NO_WINDOW is set and that frameRectsChanged positioned
- * the widget correctly. ATM we do not honor the GraphicsContext translation.
- */
-void Widget::paint(GraphicsContext* context, const IntRect&)
+void Widget::paint(GraphicsContext* context, const IntRect& rect)
{
- if (!platformWidget())
- return;
-
- if (!context->gdkExposeEvent())
- return;
-
- GtkWidget* widget = platformWidget();
- ASSERT(GTK_WIDGET_NO_WINDOW(widget));
-
- GdkEvent* event = gdk_event_new(GDK_EXPOSE);
- event->expose = *context->gdkExposeEvent();
- event->expose.region = gtk_widget_region_intersect(widget, event->expose.region);
-
- /*
- * This will be unref'ed by gdk_event_free.
- */
- g_object_ref(event->expose.window);
-
- /*
- * If we are going to paint do the translation and GtkAllocation manipulation.
- */
- if (!gdk_region_empty(event->expose.region)) {
- gdk_region_get_clipbox(event->expose.region, &event->expose.area);
- gtk_widget_send_expose(widget, event);
- }
-
- gdk_event_free(event);
}
void Widget::setIsSelected(bool)
@@ -169,12 +125,7 @@ void Widget::retainPlatformWidget()
{
if (!platformWidget())
return;
-#if GLIB_CHECK_VERSION(2,10,0)
g_object_ref_sink(platformWidget());
-#else
- g_object_ref(platformWidget());
- gtk_object_sink(GTK_OBJECT(platformWidget()));
-#endif
}
}
diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h
index e21ddcf..17756ac 100644
--- a/WebCore/platform/image-decoders/ImageDecoder.h
+++ b/WebCore/platform/image-decoders/ImageDecoder.h
@@ -57,12 +57,11 @@ public:
void clear() {
m_bytes.clear();
- m_rect = IntRect();
- m_height = 0;
m_status = FrameEmpty;
- m_duration = 0;
- m_disposalMethod = DisposeNotSpecified;
- m_hasAlpha = false;
+ // NOTE: Do not reset other members here; clearFrameBufferCache() calls
+ // this to free the bitmap data, but other functions like
+ // initFrameBuffer() and frameComplete() may still need to read other
+ // metadata out of this frame later.
}
const RGBA32Array& bytes() const { return m_bytes; }
diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
index 843e65a..5b4b675 100644
--- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
@@ -188,7 +188,8 @@ void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
// In some cases, like if the decoder was destroyed while animating, we
// can be asked to clear more frames than we currently have.
if (m_frameBufferCache.isEmpty())
- return; // Nothing to do.
+ return; // Nothing to do.
+
// The "-1" here is tricky. It does not mean that |clearBeforeFrame| is the
// last frame we wish to preserve, but rather that we never want to clear
// the very last frame in the cache: it's empty (so clearing it is
@@ -199,21 +200,36 @@ void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
// this case.
clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1);
const Vector<RGBA32Buffer>::iterator end(m_frameBufferCache.begin() + clearBeforeFrame);
- for (Vector<RGBA32Buffer>::iterator i(m_frameBufferCache.begin()); i != end; ++i) {
- if (i->status() == RGBA32Buffer::FrameEmpty)
- continue; // Nothing to do.
-
- // The layout of frames is:
- // [empty frames][complete frames][partial frame][empty frames]
- // ...where each of these groups may be empty. We should not clear a
- // partial frame since that's what's being decoded right now, and we
- // also should not clear the last complete frame, since it may be needed
- // when constructing the next frame. Note that "i + 1" is safe since
- // i < end < m_frameBufferCache.end().
- if ((i->status() == RGBA32Buffer::FramePartial) || ((i + 1)->status() != RGBA32Buffer::FrameComplete))
- break;
-
- i->clear();
+
+ // We need to preserve frames such that:
+ // * We don't clear |end|
+ // * We don't clear the frame we're currently decoding
+ // * We don't clear any frame from which a future initFrameBuffer() call
+ // will copy bitmap data
+ // All other frames can be cleared. Because of the constraints on when
+ // ImageSource::clear() can be called (see ImageSource.h), we're guaranteed
+ // not to have non-empty frames after the frame we're currently decoding.
+ // So, scan backwards from |end| as follows:
+ // * If the frame is empty, we're still past any frames we care about.
+ // * If the frame is complete, but is DisposeOverwritePrevious, we'll
+ // skip over it in future initFrameBuffer() calls. We can clear it
+ // unless it's |end|, and keep scanning. For any other disposal method,
+ // stop scanning, as we've found the frame initFrameBuffer() will need
+ // next.
+ // * If the frame is partial, we're decoding it, so don't clear it; if it
+ // has a disposal method other than DisposeOverwritePrevious, stop
+ // scanning, as we'll only need this frame when decoding the next one.
+ Vector<RGBA32Buffer>::iterator i(end);
+ for (; (i != m_frameBufferCache.begin()) && ((i->status() == RGBA32Buffer::FrameEmpty) || (i->disposalMethod() == RGBA32Buffer::DisposeOverwritePrevious)); --i) {
+ if ((i->status() == RGBA32Buffer::FrameComplete) && (i != end))
+ i->clear();
+ }
+
+ // Now |i| holds the last frame we need to preserve; clear prior frames.
+ for (Vector<RGBA32Buffer>::iterator j(m_frameBufferCache.begin()); j != i; ++j) {
+ ASSERT(j->status() != RGBA32Buffer::FramePartial);
+ if (j->status() != RGBA32Buffer::FrameEmpty)
+ j->clear();
}
}
diff --git a/WebCore/platform/image-decoders/skia/ImageDecoder.h b/WebCore/platform/image-decoders/skia/ImageDecoder.h
index b983315..cddb69b 100644
--- a/WebCore/platform/image-decoders/skia/ImageDecoder.h
+++ b/WebCore/platform/image-decoders/skia/ImageDecoder.h
@@ -132,10 +132,11 @@ namespace WebCore {
void clear()
{
m_bitmapRef = RefCountedNativeImageSkia::create();
- m_rect = IntRect();
m_status = FrameEmpty;
- m_duration = 0;
- m_disposalMethod = DisposeNotSpecified;
+ // NOTE: Do not reset other members here; clearFrameBufferCache()
+ // calls this to free the bitmap data, but other functions like
+ // initFrameBuffer() and frameComplete() may still need to read
+ // other metadata out of this frame later.
}
// This function creates a new copy of the image data in |other|, so the
diff --git a/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp b/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp
new file mode 100644
index 0000000..aa20c62
--- /dev/null
+++ b/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2006-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 "IntSize.h"
+#include "OwnArrayPtr.h"
+#include "PNGImageEncoder.h"
+#include "Vector.h"
+
+#include "SkBitmap.h"
+
+extern "C" {
+#include "png.h"
+}
+
+namespace WebCore {
+
+// Converts BGRA->RGBA and RGBA->BGRA.
+static void convertBetweenBGRAandRGBA(const unsigned char* input, int numberOfPixels,
+ unsigned char* output)
+{
+ for (int x = 0; x < numberOfPixels; x++) {
+ const unsigned char* pixelIn = &input[x * 4];
+ unsigned char* pixelOut = &output[x * 4];
+ pixelOut[0] = pixelIn[2];
+ pixelOut[1] = pixelIn[1];
+ pixelOut[2] = pixelIn[0];
+ pixelOut[3] = pixelIn[3];
+ }
+}
+
+// Encoder --------------------------------------------------------------------
+//
+// This section of the code is based on nsPNGEncoder.cpp in Mozilla
+// (Copyright 2005 Google Inc.)
+
+// Passed around as the io_ptr in the png structs so our callbacks know where
+// to write data.
+struct PNGEncoderState {
+ PNGEncoderState(Vector<unsigned char>* o) : m_out(o) {}
+ Vector<unsigned char>* m_out;
+};
+
+// Called by libpng to flush its internal buffer to ours.
+void encoderWriteCallback(png_structp png, png_bytep data, png_size_t size)
+{
+ PNGEncoderState* state = static_cast<PNGEncoderState*>(png_get_io_ptr(png));
+ ASSERT(state->m_out);
+
+ size_t oldSize = state->m_out->size();
+ state->m_out->resize(oldSize + size);
+ memcpy(&(*state->m_out)[oldSize], data, size);
+}
+
+// Automatically destroys the given write structs on destruction to make
+// cleanup and error handling code cleaner.
+class PNGWriteStructDestroyer {
+public:
+ PNGWriteStructDestroyer(png_struct** ps, png_info** pi)
+ : m_pngStruct(ps)
+ , m_pngInfo(pi) {
+ }
+
+ ~PNGWriteStructDestroyer() {
+ png_destroy_write_struct(m_pngStruct, m_pngInfo);
+ }
+
+private:
+ png_struct** m_pngStruct;
+ png_info** m_pngInfo;
+};
+
+// static
+bool PNGImageEncoder::encode(const SkBitmap& image, Vector<unsigned char>* output)
+{
+ if (image.config() != SkBitmap::kARGB_8888_Config)
+ return false; // Only support ARGB at 8 bpp now.
+
+ image.lockPixels();
+ bool result = PNGImageEncoder::encode(static_cast<unsigned char*>(
+ image.getPixels()), IntSize(image.width(), image.height()),
+ image.rowBytes(), output);
+ image.unlockPixels();
+ return result;
+}
+
+// static
+bool PNGImageEncoder::encode(const unsigned char* input, const IntSize& size,
+ int bytesPerRow,
+ Vector<unsigned char>* output)
+{
+ int inputColorComponents = 4;
+ int outputColorComponents = 4;
+ int pngOutputColorType = PNG_COLOR_TYPE_RGB_ALPHA;
+ IntSize imageSize(size);
+ imageSize.clampNegativeToZero();
+
+ // Row stride should be at least as long as the length of the data.
+ if (inputColorComponents * imageSize.width() > bytesPerRow) {
+ ASSERT(false);
+ return false;
+ }
+
+ png_struct* pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ png_voidp_NULL,
+ png_error_ptr_NULL,
+ png_error_ptr_NULL);
+ if (!pngPtr)
+ return false;
+
+ png_info* infoPtr = png_create_info_struct(pngPtr);
+ if (!infoPtr) {
+ png_destroy_write_struct(&pngPtr, NULL);
+ return false;
+ }
+ PNGWriteStructDestroyer destroyer(&pngPtr, &infoPtr);
+
+ if (setjmp(png_jmpbuf(pngPtr))) {
+ // The destroyer will ensure that the structures are cleaned up in this
+ // case, even though we may get here as a jump from random parts of the
+ // PNG library called below.
+ return false;
+ }
+
+ // Set our callback for libpng to give us the data.
+ PNGEncoderState state(output);
+ png_set_write_fn(pngPtr, &state, encoderWriteCallback, NULL);
+
+ png_set_IHDR(pngPtr, infoPtr, imageSize.width(), imageSize.height(), 8, pngOutputColorType,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+ png_write_info(pngPtr, infoPtr);
+
+ OwnArrayPtr<unsigned char> rowPixels(new unsigned char[imageSize.width() * outputColorComponents]);
+ for (int y = 0; y < imageSize.height(); y ++) {
+ convertBetweenBGRAandRGBA(&input[y * bytesPerRow], imageSize.width(), rowPixels.get());
+ png_write_row(pngPtr, rowPixels.get());
+ }
+
+ png_write_end(pngPtr, infoPtr);
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/image-encoders/skia/PNGImageEncoder.h b/WebCore/platform/image-encoders/skia/PNGImageEncoder.h
new file mode 100644
index 0000000..b5865d2
--- /dev/null
+++ b/WebCore/platform/image-encoders/skia/PNGImageEncoder.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2006-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 PNGImageEncoder_h
+#define PNGImageEncoder_h
+
+#include "Vector.h"
+
+class IntSize;
+class SkBitmap;
+
+namespace WebCore {
+
+ // Interface for encoding PNG data. This is a wrapper around libpng.
+ class PNGImageEncoder {
+ public:
+ // Encodes the specific SkBitmap into the supplied vector.
+ static bool encode(const SkBitmap&, WTF::Vector<unsigned char>* output);
+
+ // Encodes the specified image data into the supplied vector.
+ // w, h give the size of the image and bytes_per_row gives the bytes
+ // per row.
+ static bool encode(const unsigned char* input, const IntSize& size, int bytesPerRow, WTF::Vector<unsigned char>* output);
+ };
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/mac/FoundationExtras.h b/WebCore/platform/mac/FoundationExtras.h
index 51a7df0..85ce8d7 100644
--- a/WebCore/platform/mac/FoundationExtras.h
+++ b/WebCore/platform/mac/FoundationExtras.h
@@ -23,6 +23,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#import <CoreFoundation/CFBase.h>
+#import <Foundation/NSObject.h>
+
// nil-checked CFRetain/CFRelease covers for Objective-C ids
// Use CFRetain, CFRelease, HardRetain, or HardRelease instead of
diff --git a/WebCore/platform/mac/GeolocationServiceMac.h b/WebCore/platform/mac/GeolocationServiceMac.h
new file mode 100644
index 0000000..d0342e7
--- /dev/null
+++ b/WebCore/platform/mac/GeolocationServiceMac.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeolocationServiceMac_h
+#define GeolocationServiceMac_h
+
+#if ENABLE(GEOLOCATION)
+
+#include "GeolocationService.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/RetainPtr.h>
+
+#ifdef __OBJC__
+@class CLLocationManager;
+@class WebCoreCoreLocationObserver;
+#else
+class CLLocationManager;
+class WebCoreCoreLocationObserver;
+#endif
+
+namespace WebCore {
+
+class GeolocationServiceMac : public GeolocationService {
+public:
+ GeolocationServiceMac(GeolocationServiceClient*);
+ virtual ~GeolocationServiceMac();
+
+ virtual bool startUpdating(PositionOptions*);
+ virtual void stopUpdating();
+
+ virtual void suspend();
+ virtual void resume();
+
+ virtual Geoposition* lastPosition() const { return m_lastPosition.get(); }
+ virtual PositionError* lastError() const { return m_lastError.get(); }
+
+ void positionChanged(PassRefPtr<Geoposition>);
+ void errorOccurred(PassRefPtr<PositionError>);
+
+private:
+ RetainPtr<CLLocationManager> m_locationManager;
+ RetainPtr<WebCoreCoreLocationObserver> m_objcObserver;
+
+ RefPtr<Geoposition> m_lastPosition;
+ RefPtr<PositionError> m_lastError;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(GEOLOCATION)
+
+#endif // GeolocationServiceMac_h
diff --git a/WebCore/platform/mac/GeolocationServiceMac.mm b/WebCore/platform/mac/GeolocationServiceMac.mm
new file mode 100644
index 0000000..c21b02c
--- /dev/null
+++ b/WebCore/platform/mac/GeolocationServiceMac.mm
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if ENABLE(GEOLOCATION)
+
+#import "GeolocationServiceMac.h"
+
+#import "Geoposition.h"
+#import "PositionError.h"
+#import "PositionOptions.h"
+#import "SoftLinking.h"
+#import <CoreLocation/CoreLocation.h>
+#import <objc/objc-runtime.h>
+#import <wtf/RefPtr.h>
+#import <wtf/UnusedParam.h>
+
+SOFT_LINK_FRAMEWORK(CoreLocation)
+
+SOFT_LINK_CLASS(CoreLocation, CLLocationManager)
+SOFT_LINK_CLASS(CoreLocation, CLLocation)
+
+SOFT_LINK_CONSTANT(CoreLocation, kCLLocationAccuracyBest, double)
+SOFT_LINK_CONSTANT(CoreLocation, kCLLocationAccuracyHundredMeters, double)
+
+#define kCLLocationAccuracyBest getkCLLocationAccuracyBest()
+#define kCLLocationAccuracyHundredMeters getkCLLocationAccuracyHundredMeters()
+
+using namespace WebCore;
+
+@interface WebCoreCoreLocationObserver : NSObject<CLLocationManagerDelegate>
+{
+ GeolocationServiceMac* m_callback;
+}
+
+- (id)initWithCallback:(GeolocationServiceMac*)callback;
+
+- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation;
+- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error;
+
+@end
+
+namespace WebCore {
+
+GeolocationService* GeolocationService::create(GeolocationServiceClient* client)
+{
+ return new GeolocationServiceMac(client);
+}
+
+GeolocationServiceMac::GeolocationServiceMac(GeolocationServiceClient* client)
+ : GeolocationService(client)
+ , m_objcObserver(AdoptNS, [[WebCoreCoreLocationObserver alloc] initWithCallback:this])
+{
+}
+
+GeolocationServiceMac::~GeolocationServiceMac()
+{
+ [m_locationManager.get() stopUpdatingLocation];
+ m_locationManager.get().delegate = nil;
+}
+
+bool GeolocationServiceMac::startUpdating(PositionOptions* options)
+{
+ #define CLLocationManager getCLLocationManagerClass()
+ if (!m_locationManager.get()) {
+ m_locationManager.adoptNS([[CLLocationManager alloc] init]);
+ m_locationManager.get().delegate = m_objcObserver.get();
+ }
+
+ if (!m_locationManager.get().locationServicesEnabled)
+ return false;
+
+ if (options) {
+ // CLLocationAccuracy values suggested by Ron Huang.
+ CLLocationAccuracy accuracy = options->enableHighAccuracy() ? kCLLocationAccuracyBest : kCLLocationAccuracyHundredMeters;
+ m_locationManager.get().desiredAccuracy = accuracy;
+ }
+
+ // This can safely be called multiple times.
+ [m_locationManager.get() startUpdatingLocation];
+
+ return true;
+ #undef CLLocationManager
+}
+
+void GeolocationServiceMac::stopUpdating()
+{
+ [m_locationManager.get() stopUpdatingLocation];
+}
+
+void GeolocationServiceMac::suspend()
+{
+ [m_locationManager.get() stopUpdatingLocation];
+}
+
+void GeolocationServiceMac::resume()
+{
+ [m_locationManager.get() startUpdatingLocation];
+}
+
+void GeolocationServiceMac::positionChanged(PassRefPtr<Geoposition> position)
+{
+ m_lastPosition = position;
+ GeolocationService::positionChanged();
+}
+
+void GeolocationServiceMac::errorOccurred(PassRefPtr<PositionError> error)
+{
+ m_lastError = error;
+ GeolocationService::errorOccurred();
+}
+
+} // namespace WebCore
+
+@implementation WebCoreCoreLocationObserver
+
+- (id)initWithCallback:(GeolocationServiceMac *)callback
+{
+ self = [super init];
+ if (self)
+ m_callback = callback;
+ return self;
+}
+
+- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
+{
+ ASSERT(m_callback);
+ ASSERT(newLocation);
+ UNUSED_PARAM(manager);
+ UNUSED_PARAM(oldLocation);
+
+ // Normalize
+ double altitude = newLocation.altitude;
+ double altitudeAccuracy = newLocation.verticalAccuracy;
+ if (altitudeAccuracy < 0.0) {
+ altitudeAccuracy = 0.0;
+ altitude = 0.0;
+ }
+ double speed = newLocation.speed;
+ if (speed < 0.0)
+ speed = 0.0;
+ double heading = newLocation.course;
+ if (heading < 0.0)
+ heading = 0.0;
+
+ WTF::RefPtr<WebCore::Coordinates> newCoordinates = WebCore::Coordinates::create(
+ newLocation.coordinate.latitude,
+ newLocation.coordinate.longitude,
+ altitude,
+ newLocation.horizontalAccuracy,
+ altitudeAccuracy,
+ heading,
+ speed);
+ WTF::RefPtr<WebCore::Geoposition> newPosition = WebCore::Geoposition::create(
+ newCoordinates.release(),
+ [newLocation.timestamp timeIntervalSince1970] * 1000.0); // seconds -> milliseconds
+
+ m_callback->positionChanged(newPosition.release());
+}
+
+- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
+{
+ ASSERT(m_callback);
+ ASSERT(error);
+
+ UNUSED_PARAM(manager);
+
+ PositionError::ErrorCode code;
+ switch ([error code]) {
+ case kCLErrorDenied:
+ code = PositionError::PERMISSION_DENIED;
+ break;
+ case kCLErrorLocationUnknown:
+ code = PositionError::POSITION_UNAVAILABLE;
+ break;
+ default:
+ code = PositionError::POSITION_UNAVAILABLE;
+ break;
+ }
+
+ m_callback->errorOccurred(PositionError::create(code, [error localizedDescription]));
+}
+
+@end
+
+#endif // ENABLE(GEOLOCATION)
diff --git a/WebCore/platform/mac/LocalCurrentGraphicsContext.h b/WebCore/platform/mac/LocalCurrentGraphicsContext.h
index 856cf52..1c5cae7 100644
--- a/WebCore/platform/mac/LocalCurrentGraphicsContext.h
+++ b/WebCore/platform/mac/LocalCurrentGraphicsContext.h
@@ -19,7 +19,11 @@
#include <wtf/Noncopyable.h>
+#ifdef __OBJC__
+@class NSGraphicsContext;
+#else
class NSGraphicsContext;
+#endif
namespace WebCore {
diff --git a/WebCore/platform/mac/PasteboardMac.mm b/WebCore/platform/mac/PasteboardMac.mm
index de369fc..36b00f6 100644
--- a/WebCore/platform/mac/PasteboardMac.mm
+++ b/WebCore/platform/mac/PasteboardMac.mm
@@ -278,7 +278,7 @@ void Pasteboard::writeImage(Node* node, const KURL& url, const String& title)
ASSERT(cocoaURL);
ASSERT(node->renderer() && node->renderer()->isImage());
- RenderImage* renderer = static_cast<RenderImage*>(node->renderer());
+ RenderImage* renderer = toRenderImage(node->renderer());
CachedImage* cachedImage = static_cast<CachedImage*>(renderer->cachedImage());
ASSERT(cachedImage);
@@ -310,7 +310,7 @@ String Pasteboard::plainText(Frame* frame)
NSArray *types = [m_pasteboard.get() types];
if ([types containsObject:NSStringPboardType])
- return [m_pasteboard.get() stringForType:NSStringPboardType];
+ return [[m_pasteboard.get() stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping];
NSAttributedString *attributedString = nil;
NSString *string;
@@ -320,13 +320,13 @@ String Pasteboard::plainText(Frame* frame)
if (attributedString == nil && [types containsObject:NSRTFPboardType])
attributedString = [[NSAttributedString alloc] initWithRTF:[m_pasteboard.get() dataForType:NSRTFPboardType] documentAttributes:NULL];
if (attributedString != nil) {
- string = [[attributedString string] copy];
+ string = [[attributedString string] precomposedStringWithCanonicalMapping];
[attributedString release];
- return [string autorelease];
+ return string;
}
if ([types containsObject:NSFilenamesPboardType]) {
- string = [[m_pasteboard.get() propertyListForType:NSFilenamesPboardType] componentsJoinedByString:@"\n"];
+ string = [[[m_pasteboard.get() propertyListForType:NSFilenamesPboardType] componentsJoinedByString:@"\n"] precomposedStringWithCanonicalMapping];
if (string != nil)
return string;
}
@@ -338,7 +338,7 @@ String Pasteboard::plainText(Frame* frame)
// helper code that should either be done in a separate patch or figured out in another way.
string = frame->editor()->client()->userVisibleString(url);
if ([string length] > 0)
- return string;
+ return [string precomposedStringWithCanonicalMapping];
}
diff --git a/WebCore/platform/mac/PlatformScreenMac.mm b/WebCore/platform/mac/PlatformScreenMac.mm
index 8f12df0..5dbfcf4 100644
--- a/WebCore/platform/mac/PlatformScreenMac.mm
+++ b/WebCore/platform/mac/PlatformScreenMac.mm
@@ -45,11 +45,7 @@ int screenDepthPerComponent(Widget*)
bool screenIsMonochrome(Widget*)
{
- NSString *colorSpace = NSColorSpaceFromDepth([[NSScreen deepestScreen] depth]);
- return colorSpace == NSCalibratedWhiteColorSpace
- || colorSpace == NSCalibratedBlackColorSpace
- || colorSpace == NSDeviceWhiteColorSpace
- || colorSpace == NSDeviceBlackColorSpace;
+ return false;
}
// These functions scale between screen and page coordinates because JavaScript/DOM operations
diff --git a/WebCore/platform/mac/SharedBufferMac.mm b/WebCore/platform/mac/SharedBufferMac.mm
index f1d9517..c4e7528 100644
--- a/WebCore/platform/mac/SharedBufferMac.mm
+++ b/WebCore/platform/mac/SharedBufferMac.mm
@@ -39,7 +39,7 @@ using namespace WebCore;
@interface WebCoreSharedBufferData : NSData
{
- SharedBuffer* sharedBuffer;
+ RefPtr<SharedBuffer> sharedBuffer;
}
- (id)initWithSharedBuffer:(SharedBuffer*)buffer;
@@ -59,16 +59,12 @@ using namespace WebCore;
{
if (WebCoreObjCScheduleDeallocateOnMainThread([WebCoreSharedBufferData class], self))
return;
-
- sharedBuffer->deref();
[super dealloc];
}
- (void)finalize
{
- sharedBuffer->deref();
-
[super finalize];
}
@@ -76,10 +72,8 @@ using namespace WebCore;
{
self = [super init];
- if (self) {
+ if (self)
sharedBuffer = buffer;
- sharedBuffer->ref();
- }
return self;
}
diff --git a/WebCore/platform/mac/ThreadCheck.mm b/WebCore/platform/mac/ThreadCheck.mm
index b862598..ddee05c 100644
--- a/WebCore/platform/mac/ThreadCheck.mm
+++ b/WebCore/platform/mac/ThreadCheck.mm
@@ -32,56 +32,74 @@
namespace WebCore {
-static ThreadViolationBehavior defaultThreadViolationBehavior = RaiseExceptionOnThreadViolation;
-
static bool didReadThreadViolationBehaviorFromUserDefaults = false;
-static bool threadViolationBehaviorIsDefault;
-static ThreadViolationBehavior threadViolationBehavior;
+static bool threadViolationBehaviorIsDefault = true;
+static ThreadViolationBehavior threadViolationBehavior[MaximumThreadViolationRound] = { RaiseExceptionOnThreadViolation, RaiseExceptionOnThreadViolation };
static void readThreadViolationBehaviorFromUserDefaults()
{
+ didReadThreadViolationBehaviorFromUserDefaults = true;
+
+ ThreadViolationBehavior newBehavior = LogOnFirstThreadViolation;
NSString *threadCheckLevel = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebCoreThreadCheck"];
+ if (!threadCheckLevel)
+ return;
+
if ([threadCheckLevel isEqualToString:@"None"])
- threadViolationBehavior = NoThreadCheck;
+ newBehavior = NoThreadCheck;
else if ([threadCheckLevel isEqualToString:@"Exception"])
- threadViolationBehavior = RaiseExceptionOnThreadViolation;
+ newBehavior = RaiseExceptionOnThreadViolation;
else if ([threadCheckLevel isEqualToString:@"Log"])
- threadViolationBehavior = LogOnThreadViolation;
+ newBehavior = LogOnThreadViolation;
else if ([threadCheckLevel isEqualToString:@"LogOnce"])
- threadViolationBehavior = LogOnFirstThreadViolation;
- else {
- threadViolationBehavior = defaultThreadViolationBehavior;
- threadViolationBehaviorIsDefault = true;
- }
- didReadThreadViolationBehaviorFromUserDefaults = true;
+ newBehavior = LogOnFirstThreadViolation;
+ else
+ ASSERT_NOT_REACHED();
+
+ threadViolationBehaviorIsDefault = false;
+
+ for (unsigned i = 0; i < MaximumThreadViolationRound; ++i)
+ threadViolationBehavior[i] = newBehavior;
}
-void setDefaultThreadViolationBehavior(ThreadViolationBehavior behavior)
+void setDefaultThreadViolationBehavior(ThreadViolationBehavior behavior, ThreadViolationRound round)
{
- defaultThreadViolationBehavior = behavior;
+ ASSERT(round < MaximumThreadViolationRound);
+ if (round >= MaximumThreadViolationRound)
+ return;
+ if (!didReadThreadViolationBehaviorFromUserDefaults)
+ readThreadViolationBehaviorFromUserDefaults();
if (threadViolationBehaviorIsDefault)
- threadViolationBehavior = behavior;
+ threadViolationBehavior[round] = behavior;
}
-void reportThreadViolation(const char* function)
+void reportThreadViolation(const char* function, ThreadViolationRound round)
{
+ ASSERT(round < MaximumThreadViolationRound);
+ if (round >= MaximumThreadViolationRound)
+ return;
if (!didReadThreadViolationBehaviorFromUserDefaults)
- readThreadViolationBehaviorFromUserDefaults();
- if (threadViolationBehavior == NoThreadCheck)
+ readThreadViolationBehaviorFromUserDefaults();
+ if (threadViolationBehavior[round] == NoThreadCheck)
return;
if (pthread_main_np())
return;
- WebCoreReportThreadViolation(function);
+ WebCoreReportThreadViolation(function, round);
}
} // namespace WebCore
// Split out the actual reporting of the thread violation to make it easier to set a breakpoint
-void WebCoreReportThreadViolation(const char* function)
+void WebCoreReportThreadViolation(const char* function, WebCore::ThreadViolationRound round)
{
using namespace WebCore;
+
+ ASSERT(round < MaximumThreadViolationRound);
+ if (round >= MaximumThreadViolationRound)
+ return;
+
DEFINE_STATIC_LOCAL(HashSet<String>, loggedFunctions, ());
- switch (threadViolationBehavior) {
+ switch (threadViolationBehavior[round]) {
case NoThreadCheck:
break;
case LogOnFirstThreadViolation:
diff --git a/WebCore/platform/mac/WebCoreSystemInterface.h b/WebCore/platform/mac/WebCoreSystemInterface.h
index 14d1713..3feed69 100644
--- a/WebCore/platform/mac/WebCoreSystemInterface.h
+++ b/WebCore/platform/mac/WebCoreSystemInterface.h
@@ -40,12 +40,21 @@ typedef struct _NSRect NSRect;
#endif
#ifdef __OBJC__
+@class NSArray;
@class NSButtonCell;
@class NSData;
+@class NSDate;
@class NSEvent;
@class NSFont;
+@class NSImage;
+@class NSMenu;
@class NSMutableURLRequest;
+@class NSString;
+@class NSTextFieldCell;
+@class NSURLConnection;
@class NSURLRequest;
+@class NSURLResponse;
+@class NSView;
@class QTMovie;
@class QTMovieView;
#else
diff --git a/WebCore/platform/mac/WebCoreSystemInterface.mm b/WebCore/platform/mac/WebCoreSystemInterface.mm
index b629b4e..edd9d50 100644
--- a/WebCore/platform/mac/WebCoreSystemInterface.mm
+++ b/WebCore/platform/mac/WebCoreSystemInterface.mm
@@ -25,6 +25,7 @@
#import "config.h"
#import "WebCoreSystemInterface.h"
+#import <Foundation/Foundation.h>
void (*wkAdvanceDefaultButtonPulseAnimation)(NSButtonCell *);
BOOL (*wkCGContextGetShouldSmoothFonts)(CGContextRef);
diff --git a/WebCore/platform/mac/WebCoreTextRenderer.h b/WebCore/platform/mac/WebCoreTextRenderer.h
index 3e77434..73753bc 100644
--- a/WebCore/platform/mac/WebCoreTextRenderer.h
+++ b/WebCore/platform/mac/WebCoreTextRenderer.h
@@ -23,6 +23,15 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#import <AppKit/NSFontManager.h>
+#import <CoreFoundation/CFString.h>
+
+#ifdef __OBJC__
+@class NSColor;
+@class NSFont;
+@class NSString;
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/WebCore/platform/mac/WebCoreTextRenderer.mm b/WebCore/platform/mac/WebCoreTextRenderer.mm
index 0cd5967..ab053ef 100644
--- a/WebCore/platform/mac/WebCoreTextRenderer.mm
+++ b/WebCore/platform/mac/WebCoreTextRenderer.mm
@@ -31,6 +31,7 @@
#import "GraphicsContext.h"
#import "IntPoint.h"
#import "WebFontCache.h"
+#import <AppKit/AppKit.h>
using namespace WebCore;
diff --git a/WebCore/platform/mac/WebFontCache.h b/WebCore/platform/mac/WebFontCache.h
index b31a684..8d3e4dd 100644
--- a/WebCore/platform/mac/WebFontCache.h
+++ b/WebCore/platform/mac/WebFontCache.h
@@ -24,7 +24,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <wtf/Vector.h>
+#import <AppKit/NSFontManager.h>
+#import <wtf/Vector.h>
// This interface exists so that third party products (like Silk) can patch in to an Obj-C method to manipulate WebKit's font caching/substitution.
@interface WebFontCache : NSObject
diff --git a/WebCore/platform/mac/WebFontCache.mm b/WebCore/platform/mac/WebFontCache.mm
index 6cf1ef4..ac70f06 100644
--- a/WebCore/platform/mac/WebFontCache.mm
+++ b/WebCore/platform/mac/WebFontCache.mm
@@ -31,6 +31,8 @@
#import "WebFontCache.h"
#import "FontTraitsMask.h"
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
#import <math.h>
using namespace WebCore;
diff --git a/WebCore/platform/mac/WheelEventMac.mm b/WebCore/platform/mac/WheelEventMac.mm
index 7b60494..5821139 100644
--- a/WebCore/platform/mac/WheelEventMac.mm
+++ b/WebCore/platform/mac/WheelEventMac.mm
@@ -27,6 +27,7 @@
#import "PlatformWheelEvent.h"
#import "PlatformMouseEvent.h"
+#import "Scrollbar.h"
#import "WebCoreSystemInterface.h"
namespace WebCore {
@@ -34,6 +35,7 @@ namespace WebCore {
PlatformWheelEvent::PlatformWheelEvent(NSEvent* event)
: m_position(pointForEvent(event))
, m_globalPosition(globalPointForEvent(event))
+ , m_granularity(ScrollByPixelWheelEvent)
, m_isAccepted(false)
, m_shiftKey([event modifierFlags] & NSShiftKeyMask)
, m_ctrlKey([event modifierFlags] & NSControlKeyMask)
@@ -42,10 +44,14 @@ PlatformWheelEvent::PlatformWheelEvent(NSEvent* event)
{
BOOL continuous;
wkGetWheelEventDeltas(event, &m_deltaX, &m_deltaY, &continuous);
- m_granularity = continuous ? ScrollByPixelWheelEvent : ScrollByLineWheelEvent;
- if (m_granularity == ScrollByLineWheelEvent) {
- m_deltaX *= horizontalLineMultiplier();
- m_deltaY *= verticalLineMultiplier();
+ if (continuous) {
+ m_wheelTicksX = m_deltaX / static_cast<float>(cScrollbarPixelsPerLineStep);
+ m_wheelTicksY = m_deltaY / static_cast<float>(cScrollbarPixelsPerLineStep);
+ } else {
+ m_wheelTicksX = m_deltaX;
+ m_wheelTicksY = m_deltaY;
+ m_deltaX *= static_cast<float>(cScrollbarPixelsPerLineStep);
+ m_deltaY *= static_cast<float>(cScrollbarPixelsPerLineStep);
}
}
diff --git a/WebCore/platform/network/FormData.cpp b/WebCore/platform/network/FormData.cpp
index 3cac168..af3b7f0 100644
--- a/WebCore/platform/network/FormData.cpp
+++ b/WebCore/platform/network/FormData.cpp
@@ -29,7 +29,8 @@
namespace WebCore {
inline FormData::FormData()
- : m_hasGeneratedFiles(false)
+ : m_identifier(0)
+ , m_hasGeneratedFiles(false)
, m_alwaysStream(false)
{
}
@@ -37,6 +38,7 @@ inline FormData::FormData()
inline FormData::FormData(const FormData& data)
: RefCounted<FormData>()
, m_elements(data.m_elements)
+ , m_identifier(data.m_identifier)
, m_hasGeneratedFiles(false)
, m_alwaysStream(false)
{
@@ -98,7 +100,7 @@ PassRefPtr<FormData> FormData::deepCopy() const
formData->m_alwaysStream = m_alwaysStream;
size_t n = m_elements.size();
- formData->m_elements.reserveCapacity(n);
+ formData->m_elements.reserveInitialCapacity(n);
for (size_t i = 0; i < n; ++i) {
const FormDataElement& e = m_elements[i];
switch (e.m_type) {
diff --git a/WebCore/platform/network/FormData.h b/WebCore/platform/network/FormData.h
index 5998b1b..7278f2e 100644
--- a/WebCore/platform/network/FormData.h
+++ b/WebCore/platform/network/FormData.h
@@ -86,11 +86,17 @@ public:
bool alwaysStream() const { return m_alwaysStream; }
void setAlwaysStream(bool alwaysStream) { m_alwaysStream = alwaysStream; }
+ // Identifies a particular form submission instance. A value of 0 is used
+ // to indicate an unspecified identifier.
+ void setIdentifier(int64_t identifier) { m_identifier = identifier; }
+ int64_t identifier() const { return m_identifier; }
+
private:
FormData();
FormData(const FormData&);
-
+
Vector<FormDataElement> m_elements;
+ int64_t m_identifier;
bool m_hasGeneratedFiles;
bool m_alwaysStream;
};
diff --git a/WebCore/platform/network/HTTPHeaderMap.cpp b/WebCore/platform/network/HTTPHeaderMap.cpp
index aa9c5fa..ff470a0 100644
--- a/WebCore/platform/network/HTTPHeaderMap.cpp
+++ b/WebCore/platform/network/HTTPHeaderMap.cpp
@@ -41,7 +41,7 @@ namespace WebCore {
auto_ptr<CrossThreadHTTPHeaderMapData> HTTPHeaderMap::copyData() const
{
auto_ptr<CrossThreadHTTPHeaderMapData> data(new CrossThreadHTTPHeaderMapData());
- data->reserveCapacity(size());
+ data->reserveInitialCapacity(size());
HTTPHeaderMap::const_iterator end_it = end();
for (HTTPHeaderMap::const_iterator it = begin(); it != end_it; ++it) {
diff --git a/WebCore/platform/network/HTTPParsers.cpp b/WebCore/platform/network/HTTPParsers.cpp
index 0858fc9..f36e9fb 100644
--- a/WebCore/platform/network/HTTPParsers.cpp
+++ b/WebCore/platform/network/HTTPParsers.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -131,18 +132,18 @@ String filenameFromHTTPContentDisposition(const String& value)
String extractMIMETypeFromMediaType(const String& mediaType)
{
- String mimeType;
+ Vector<UChar, 64> mimeType;
unsigned length = mediaType.length();
+ mimeType.reserveCapacity(length);
for (unsigned offset = 0; offset < length; offset++) {
UChar c = mediaType[offset];
if (c == ';')
break;
else if (isSpaceOrNewline(c)) // FIXME: This seems wrong, " " is an invalid MIME type character according to RFC 2045. bug 8644
continue;
- // FIXME: This is a very slow way to build a string, given WebCore::String's implementation.
- mimeType += String(&c, 1);
+ mimeType.append(c);
}
- return mimeType;
+ return String(mimeType.data(), mimeType.size());
}
String extractCharsetFromMediaType(const String& mediaType)
diff --git a/WebCore/platform/network/ResourceErrorBase.cpp b/WebCore/platform/network/ResourceErrorBase.cpp
index 1ea35b0..370650f 100644
--- a/WebCore/platform/network/ResourceErrorBase.cpp
+++ b/WebCore/platform/network/ResourceErrorBase.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,6 +29,20 @@
namespace WebCore {
+ResourceError ResourceErrorBase::copy() const
+{
+ lazyInit();
+
+ ResourceError errorCopy;
+ errorCopy.m_domain = m_domain.copy();
+ errorCopy.m_errorCode = m_errorCode;
+ errorCopy.m_failingURL = m_failingURL.copy();
+ errorCopy.m_localizedDescription = m_localizedDescription.copy();
+ errorCopy.m_isNull = m_isNull;
+ errorCopy.m_isCancellation = m_isCancellation;
+ return errorCopy;
+}
+
void ResourceErrorBase::lazyInit() const
{
const_cast<ResourceError*>(static_cast<const ResourceError*>(this))->platformLazyInit();
@@ -59,4 +74,4 @@ bool ResourceErrorBase::compare(const ResourceError& a, const ResourceError& b)
return platformCompare(a, b);
}
-}
+} // namespace WebCore
diff --git a/WebCore/platform/network/ResourceErrorBase.h b/WebCore/platform/network/ResourceErrorBase.h
index 4631324..237db9e 100644
--- a/WebCore/platform/network/ResourceErrorBase.h
+++ b/WebCore/platform/network/ResourceErrorBase.h
@@ -34,6 +34,9 @@ class ResourceError;
class ResourceErrorBase {
public:
+ // Makes a deep copy. Useful for when you need to use a ResourceError on another thread.
+ ResourceError copy() const;
+
bool isNull() const { return m_isNull; }
const String& domain() const { lazyInit(); return m_domain; }
@@ -44,7 +47,7 @@ public:
void setIsCancellation(bool isCancellation) { m_isCancellation = isCancellation; }
bool isCancellation() const { return m_isCancellation; }
- static bool compare(const ResourceError& a, const ResourceError& b);
+ static bool compare(const ResourceError&, const ResourceError&);
protected:
ResourceErrorBase()
@@ -85,4 +88,4 @@ inline bool operator!=(const ResourceError& a, const ResourceError& b) { return
} // namespace WebCore
-#endif // ResourceErrorBase_h_
+#endif // ResourceErrorBase_h
diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h
index c981483..e3038ca 100644
--- a/WebCore/platform/network/ResourceHandle.h
+++ b/WebCore/platform/network/ResourceHandle.h
@@ -30,6 +30,10 @@
#include "HTTPHeaderMap.h"
#include <wtf/OwnPtr.h>
+#if USE(SOUP)
+typedef struct _SoupSession SoupSession;
+#endif
+
#if PLATFORM(CF)
typedef const struct __CFData * CFDataRef;
#endif
@@ -79,7 +83,7 @@ class KURL;
class ResourceError;
class ResourceHandleClient;
class ResourceHandleInternal;
-class ResourceRequest;
+struct ResourceRequest;
class ResourceResponse;
class SchedulePair;
class SharedBuffer;
@@ -159,6 +163,10 @@ public:
ResourceHandleInternal* getInternal() { return d.get(); }
#endif
+#if USE(SOUP)
+ static SoupSession* defaultSession();
+#endif
+
// Used to work around the fact that you don't get any more NSURLConnection callbacks until you return from the one you're in.
static bool loadsBlocked();
@@ -179,7 +187,7 @@ private:
#if USE(SOUP)
bool startData(String urlString);
bool startHttp(String urlString);
- bool startGio(String urlString);
+ bool startGio(KURL url);
#endif
void scheduleFailure(FailureType);
diff --git a/WebCore/platform/network/ResourceHandleClient.h b/WebCore/platform/network/ResourceHandleClient.h
index 3668d88..54c27d2 100644
--- a/WebCore/platform/network/ResourceHandleClient.h
+++ b/WebCore/platform/network/ResourceHandleClient.h
@@ -32,6 +32,7 @@
#if USE(CFNETWORK)
#include <ConditionalMacros.h>
+#include <CFNetwork/CFURLCachePriv.h>
#include <CFNetwork/CFURLResponsePriv.h>
#endif
@@ -49,7 +50,7 @@ namespace WebCore {
class KURL;
class ResourceHandle;
class ResourceError;
- class ResourceRequest;
+ struct ResourceRequest;
class ResourceResponse;
enum CacheStoragePolicy {
@@ -86,6 +87,9 @@ namespace WebCore {
virtual NSCachedURLResponse* willCacheResponse(ResourceHandle*, NSCachedURLResponse* response) { return response; }
virtual void willStopBufferingData(ResourceHandle*, const char*, int) { }
#endif
+#if USE(CFNETWORK)
+ virtual bool shouldCacheResponse(ResourceHandle*, CFCachedURLResponseRef response) { return true; }
+#endif
};
}
diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h
index cc90cc8..c592a1a 100644
--- a/WebCore/platform/network/ResourceHandleInternal.h
+++ b/WebCore/platform/network/ResourceHandleInternal.h
@@ -47,6 +47,7 @@
#if USE(SOUP)
#include <libsoup/soup.h>
+class Frame;
#endif
#if PLATFORM(QT)
@@ -116,13 +117,15 @@ namespace WebCore {
#if USE(SOUP)
, m_msg(0)
, m_cancelled(false)
+ , m_reportedHeaders(false)
, m_gfile(0)
- , m_input_stream(0)
+ , m_inputStream(0)
, m_cancellable(0)
, m_buffer(0)
- , m_bufsize(0)
+ , m_bufferSize(0)
, m_total(0)
, m_idleHandler(0)
+ , m_frame(0)
#endif
#if PLATFORM(QT)
, m_job(0)
@@ -190,12 +193,14 @@ namespace WebCore {
SoupMessage* m_msg;
ResourceResponse m_response;
bool m_cancelled;
+ bool m_reportedHeaders;
GFile* m_gfile;
- GInputStream* m_input_stream;
+ GInputStream* m_inputStream;
GCancellable* m_cancellable;
char* m_buffer;
- gsize m_bufsize, m_total;
+ gsize m_bufferSize, m_total;
guint m_idleHandler;
+ Frame* m_frame;
#endif
#if PLATFORM(QT)
#if QT_VERSION < 0x040400
diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp
index 15469a0..fd27718 100644
--- a/WebCore/platform/network/ResourceRequestBase.cpp
+++ b/WebCore/platform/network/ResourceRequestBase.cpp
@@ -76,7 +76,7 @@ auto_ptr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const
data->m_httpMethod = httpMethod().copy();
data->m_httpHeaders.adopt(httpHeaderFields().copyData());
- data->m_responseContentDispositionEncodingFallbackArray.reserveCapacity(m_responseContentDispositionEncodingFallbackArray.size());
+ data->m_responseContentDispositionEncodingFallbackArray.reserveInitialCapacity(m_responseContentDispositionEncodingFallbackArray.size());
size_t encodingArraySize = m_responseContentDispositionEncodingFallbackArray.size();
for (size_t index = 0; index < encodingArraySize; ++index) {
data->m_responseContentDispositionEncodingFallbackArray.append(m_responseContentDispositionEncodingFallbackArray[index].copy());
@@ -130,7 +130,8 @@ void ResourceRequestBase::setCachePolicy(ResourceRequestCachePolicy cachePolicy)
m_cachePolicy = cachePolicy;
- m_platformRequestUpdated = false;
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
}
double ResourceRequestBase::timeoutInterval() const
@@ -146,7 +147,8 @@ void ResourceRequestBase::setTimeoutInterval(double timeoutInterval)
m_timeoutInterval = timeoutInterval;
- m_platformRequestUpdated = false;
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
}
const KURL& ResourceRequestBase::mainDocumentURL() const
@@ -178,7 +180,8 @@ void ResourceRequestBase::setHTTPMethod(const String& httpMethod)
m_httpMethod = httpMethod;
- m_platformRequestUpdated = false;
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
}
const HTTPHeaderMap& ResourceRequestBase::httpHeaderFields() const
@@ -201,7 +204,8 @@ void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const Str
m_httpHeaderFields.set(name, value);
- m_platformRequestUpdated = false;
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
}
void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2, const String& encoding3)
@@ -216,7 +220,8 @@ void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(con
if (!encoding3.isNull())
m_responseContentDispositionEncodingFallbackArray.append(encoding3);
- m_platformRequestUpdated = false;
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
}
FormData* ResourceRequestBase::httpBody() const
@@ -232,7 +237,8 @@ void ResourceRequestBase::setHTTPBody(PassRefPtr<FormData> httpBody)
m_httpBody = httpBody;
- m_platformRequestUpdated = false;
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
}
bool ResourceRequestBase::allowHTTPCookies() const
@@ -248,7 +254,8 @@ void ResourceRequestBase::setAllowHTTPCookies(bool allowHTTPCookies)
m_allowHTTPCookies = allowHTTPCookies;
- m_platformRequestUpdated = false;
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
}
void ResourceRequestBase::addHTTPHeaderField(const AtomicString& name, const String& value)
diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h
index 0f6bb47..4fd57e1 100644
--- a/WebCore/platform/network/ResourceRequestBase.h
+++ b/WebCore/platform/network/ResourceRequestBase.h
@@ -46,7 +46,7 @@ namespace WebCore {
const int unspecifiedTimeoutInterval = INT_MAX;
- class ResourceRequest;
+ struct ResourceRequest;
struct CrossThreadResourceRequestData;
// Do not use this type directly. Use ResourceRequest instead.
@@ -107,12 +107,18 @@ namespace WebCore {
void setAllowHTTPCookies(bool allowHTTPCookies);
bool isConditional() const;
-
+
+ // Whether the associated ResourceHandleClient needs to be notified of
+ // upload progress made for that resource.
+ bool reportUploadProgress() const { return m_reportUploadProgress; }
+ void setReportUploadProgress(bool reportUploadProgress) { m_reportUploadProgress = reportUploadProgress; }
+
protected:
// Used when ResourceRequest is initialized from a platform representation of the request
ResourceRequestBase()
: m_resourceRequestUpdated(false)
, m_platformRequestUpdated(true)
+ , m_reportUploadProgress(false)
{
}
@@ -124,6 +130,7 @@ namespace WebCore {
, m_allowHTTPCookies(true)
, m_resourceRequestUpdated(true)
, m_platformRequestUpdated(false)
+ , m_reportUploadProgress(false)
{
}
@@ -142,6 +149,7 @@ namespace WebCore {
bool m_allowHTTPCookies;
mutable bool m_resourceRequestUpdated;
mutable bool m_platformRequestUpdated;
+ bool m_reportUploadProgress;
private:
const ResourceRequest& asResourceRequest() const;
diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp
index 92ece8c..60c0097 100644
--- a/WebCore/platform/network/ResourceResponseBase.cpp
+++ b/WebCore/platform/network/ResourceResponseBase.cpp
@@ -39,7 +39,7 @@ static void parseCacheControlDirectiveValues(const String& directives, Vector<St
auto_ptr<ResourceResponse> ResourceResponseBase::adopt(auto_ptr<CrossThreadResourceResponseData> data)
{
auto_ptr<ResourceResponse> response(new ResourceResponse());
- response->setUrl(data->m_url);
+ response->setURL(data->m_url);
response->setMimeType(data->m_mimeType);
response->setExpectedContentLength(data->m_expectedContentLength);
response->setTextEncodingName(data->m_textEncodingName);
@@ -94,7 +94,7 @@ const KURL& ResourceResponseBase::url() const
return m_url;
}
-void ResourceResponseBase::setUrl(const KURL& url)
+void ResourceResponseBase::setURL(const KURL& url)
{
lazyInit();
m_isNull = false;
diff --git a/WebCore/platform/network/ResourceResponseBase.h b/WebCore/platform/network/ResourceResponseBase.h
index c06f75b..ff34a26 100644
--- a/WebCore/platform/network/ResourceResponseBase.h
+++ b/WebCore/platform/network/ResourceResponseBase.h
@@ -49,7 +49,7 @@ public:
bool isHTTP() const;
const KURL& url() const;
- void setUrl(const KURL& url);
+ void setURL(const KURL& url);
const String& mimeType() const;
void setMimeType(const String& mimeType);
@@ -97,6 +97,13 @@ public:
return m_cacheControlContainsMustRevalidate;
}
+ // The ResourceResponse subclass may "shadow" this method to provide platform-specific memory usage information
+ unsigned memoryUsage() const
+ {
+ // average size, mostly due to URL and Header Map strings
+ return 1280;
+ }
+
static bool compare(const ResourceResponse& a, const ResourceResponse& b);
protected:
diff --git a/WebCore/platform/network/android/ResourceHandleAndroid.cpp b/WebCore/platform/network/android/ResourceHandleAndroid.cpp
index 4d9199a..59084ab 100644
--- a/WebCore/platform/network/android/ResourceHandleAndroid.cpp
+++ b/WebCore/platform/network/android/ResourceHandleAndroid.cpp
@@ -118,7 +118,7 @@ bool ResourceHandle::loadsBlocked()
// Class to handle synchronized loading of resources.
class SyncLoader : public ResourceHandleClient {
public:
- SyncLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data) {
+ SyncLoader(ResourceError& error, ResourceResponse& response, WTF::Vector<char>& data) {
m_error = &error;
m_response = &response;
m_data = &data;
@@ -140,11 +140,11 @@ public:
private:
ResourceError* m_error;
ResourceResponse* m_response;
- Vector<char>* m_data;
+ WTF::Vector<char>* m_data;
};
void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request,
- ResourceError& error, ResourceResponse& response, Vector<char>& data,
+ ResourceError& error, ResourceResponse& response, WTF::Vector<char>& data,
Frame* frame)
{
SyncLoader s(error, response, data);
diff --git a/WebCore/platform/network/cf/FormDataStreamCFNet.cpp b/WebCore/platform/network/cf/FormDataStreamCFNet.cpp
index 71fbfe7..3414d90 100644
--- a/WebCore/platform/network/cf/FormDataStreamCFNet.cpp
+++ b/WebCore/platform/network/cf/FormDataStreamCFNet.cpp
@@ -317,8 +317,7 @@ static void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, vo
void setHTTPBody(CFMutableURLRequestRef request, PassRefPtr<FormData> formData)
{
if (!formData) {
- if (wkCanAccessCFURLRequestHTTPBodyParts())
- wkCFURLRequestSetHTTPRequestBodyParts(request, 0);
+ wkCFURLRequestSetHTTPRequestBodyParts(request, 0);
return;
}
@@ -338,52 +337,20 @@ void setHTTPBody(CFMutableURLRequestRef request, PassRefPtr<FormData> formData)
}
}
- if (wkCanAccessCFURLRequestHTTPBodyParts()) {
- RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks));
-
- for (size_t i = 0; i < count; ++i) {
- const FormDataElement& element = formData->elements()[i];
- if (element.m_type == FormDataElement::data) {
- RetainPtr<CFDataRef> data(AdoptCF, CFDataCreate(0, reinterpret_cast<const UInt8*>(element.m_data.data()), element.m_data.size()));
- CFArrayAppendValue(array.get(), data.get());
- } else {
- RetainPtr<CFStringRef> filename(AdoptCF, element.m_filename.createCFString());
- CFArrayAppendValue(array.get(), filename.get());
- }
- }
+ RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks));
- wkCFURLRequestSetHTTPRequestBodyParts(request, array.get());
- return;
- }
-
- // Precompute the content length so CFURLConnection doesn't use chunked mode.
- bool haveLength = true;
- long long length = 0;
for (size_t i = 0; i < count; ++i) {
const FormDataElement& element = formData->elements()[i];
- if (element.m_type == FormDataElement::data)
- length += element.m_data.size();
- else {
- long long size;
- if (getFileSize(element.m_filename, size))
- length += size;
- else
- haveLength = false;
+ if (element.m_type == FormDataElement::data) {
+ RetainPtr<CFDataRef> data(AdoptCF, CFDataCreate(0, reinterpret_cast<const UInt8*>(element.m_data.data()), element.m_data.size()));
+ CFArrayAppendValue(array.get(), data.get());
+ } else {
+ RetainPtr<CFStringRef> filename(AdoptCF, element.m_filename.createCFString());
+ CFArrayAppendValue(array.get(), filename.get());
}
}
- if (haveLength) {
- CFStringRef lengthStr = CFStringCreateWithFormat(0, 0, CFSTR("%lld"), length);
- CFURLRequestSetHTTPHeaderFieldValue(request, CFSTR("Content-Length"), lengthStr);
- CFRelease(lengthStr);
- }
-
- static WCReadStreamCallBacks formDataStreamCallbacks =
- { 1, formCreate, formFinalize, 0, formOpen, 0, formRead, 0, formCanRead, formClose, 0, 0, 0, formSchedule, formUnschedule };
-
- CFReadStreamRef stream = CFReadStreamCreate(0, (CFReadStreamCallBacks *)&formDataStreamCallbacks, formData.releaseRef());
- CFURLRequestSetHTTPRequestBodyStream(request, stream);
- CFRelease(stream);
+ wkCFURLRequestSetHTTPRequestBodyParts(request, array.get());
}
PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef request)
@@ -391,28 +358,23 @@ PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef request)
if (RetainPtr<CFDataRef> bodyData = CFURLRequestCopyHTTPRequestBody(request))
return FormData::create(CFDataGetBytePtr(bodyData.get()), CFDataGetLength(bodyData.get()));
- if (wkCanAccessCFURLRequestHTTPBodyParts()) {
- if (RetainPtr<CFArrayRef> bodyParts = wkCFURLRequestCopyHTTPRequestBodyParts(request)) {
- RefPtr<FormData> formData = FormData::create();
-
- CFIndex count = CFArrayGetCount(bodyParts.get());
- for (CFIndex i = 0; i < count; i++) {
- CFTypeRef bodyPart = CFArrayGetValueAtIndex(bodyParts.get(), i);
- CFTypeID typeID = CFGetTypeID(bodyPart);
- if (typeID == CFStringGetTypeID()) {
- String filename = (CFStringRef)bodyPart;
- formData->appendFile(filename);
- } else if (typeID == CFDataGetTypeID()) {
- CFDataRef data = (CFDataRef)bodyPart;
- formData->appendData(CFDataGetBytePtr(data), CFDataGetLength(data));
- } else
- ASSERT_NOT_REACHED();
- }
- return formData.release();
+ if (RetainPtr<CFArrayRef> bodyParts = wkCFURLRequestCopyHTTPRequestBodyParts(request)) {
+ RefPtr<FormData> formData = FormData::create();
+
+ CFIndex count = CFArrayGetCount(bodyParts.get());
+ for (CFIndex i = 0; i < count; i++) {
+ CFTypeRef bodyPart = CFArrayGetValueAtIndex(bodyParts.get(), i);
+ CFTypeID typeID = CFGetTypeID(bodyPart);
+ if (typeID == CFStringGetTypeID()) {
+ String filename = (CFStringRef)bodyPart;
+ formData->appendFile(filename);
+ } else if (typeID == CFDataGetTypeID()) {
+ CFDataRef data = (CFDataRef)bodyPart;
+ formData->appendData(CFDataGetBytePtr(data), CFDataGetLength(data));
+ } else
+ ASSERT_NOT_REACHED();
}
- } else {
- if (RetainPtr<CFReadStreamRef> bodyStream = CFURLRequestCopyHTTPRequestBodyStream(request))
- return getStreamFormDatas().get(bodyStream.get());
+ return formData.release();
}
// FIXME: what to do about arbitrary body streams?
diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
index a4000a3..2dcbbed 100644
--- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
+++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -53,51 +53,6 @@
namespace WebCore {
-static HMODULE findCFNetworkModule()
-{
- if (HMODULE module = GetModuleHandleA("CFNetwork"))
- return module;
- return GetModuleHandleA("CFNetwork_debug");
-}
-
-static DWORD cfNetworkVersion()
-{
- HMODULE cfNetworkModule = findCFNetworkModule();
- WCHAR filename[MAX_PATH];
- GetModuleFileName(cfNetworkModule, filename, MAX_PATH);
- DWORD handle;
- DWORD versionInfoSize = GetFileVersionInfoSize(filename, &handle);
- Vector<BYTE> versionInfo(versionInfoSize);
- GetFileVersionInfo(filename, handle, versionInfoSize, versionInfo.data());
- VS_FIXEDFILEINFO* fixedFileInfo;
- UINT fixedFileInfoLength;
- VerQueryValue(versionInfo.data(), TEXT("\\"), reinterpret_cast<LPVOID*>(&fixedFileInfo), &fixedFileInfoLength);
- return fixedFileInfo->dwProductVersionMS;
-}
-
-static CFIndex highestSupportedCFURLConnectionClientVersion()
-{
- const DWORD firstCFNetworkVersionWithConnectionClientV2 = 0x000101a8; // 1.424
- const DWORD firstCFNetworkVersionWithConnectionClientV3 = 0x000101ad; // 1.429
-
-#ifndef _CFURLConnectionClientV2Present
- return 1;
-#else
-
- DWORD version = cfNetworkVersion();
- if (version < firstCFNetworkVersionWithConnectionClientV2)
- return 1;
-#ifndef _CFURLConnectionClientV3Present
- return 2;
-#else
-
- if (version < firstCFNetworkVersionWithConnectionClientV3)
- return 2;
- return 3;
-#endif // _CFURLConnectionClientV3Present
-#endif // _CFURLConnectionClientV2Present
-}
-
static HashSet<String>& allowsAnyHTTPSCertificateHosts()
{
static HashSet<String> hosts;
@@ -154,7 +109,6 @@ void didReceiveData(CFURLConnectionRef conn, CFDataRef data, CFIndex originalLen
handle->client()->didReceiveData(handle, (const char*)bytes, length, originalLength);
}
-#ifdef _CFURLConnectionClientV2Present
static void didSendBodyData(CFURLConnectionRef conn, CFIndex bytesWritten, CFIndex totalBytesWritten, CFIndex totalBytesExpectedToWrite, const void *clientInfo)
{
ResourceHandle* handle = (ResourceHandle*)clientInfo;
@@ -162,9 +116,7 @@ static void didSendBodyData(CFURLConnectionRef conn, CFIndex bytesWritten, CFInd
return;
handle->client()->didSendData(handle, totalBytesWritten, totalBytesExpectedToWrite);
}
-#endif
-#ifdef _CFURLConnectionClientV3Present
static Boolean shouldUseCredentialStorageCallback(CFURLConnectionRef conn, const void* clientInfo)
{
ResourceHandle* handle = const_cast<ResourceHandle*>(static_cast<const ResourceHandle*>(clientInfo));
@@ -176,7 +128,6 @@ static Boolean shouldUseCredentialStorageCallback(CFURLConnectionRef conn, const
return handle->shouldUseCredentialStorage();
}
-#endif
void didFinishLoading(CFURLConnectionRef conn, const void* clientInfo)
{
@@ -202,6 +153,9 @@ CFCachedURLResponseRef willCacheResponse(CFURLConnectionRef conn, CFCachedURLRes
{
ResourceHandle* handle = (ResourceHandle*)clientInfo;
+ if (handle->client() && !handle->client()->shouldCacheResponse(handle, cachedResponse))
+ return 0;
+
CacheStoragePolicy policy = static_cast<CacheStoragePolicy>(CFCachedURLResponseGetStoragePolicy(cachedResponse));
if (handle->client())
@@ -297,7 +251,7 @@ void* runLoaderThread(void *unused)
CFRunLoopRef ResourceHandle::loaderRunLoop()
{
if (!loaderRL) {
- createThread(runLoaderThread, 0, "CFNetwork::Loader");
+ createThread(runLoaderThread, 0, "WebCore: CFNetwork Loader");
while (loaderRL == 0) {
// FIXME: sleep 10? that can't be right...
Sleep(10);
@@ -348,20 +302,9 @@ bool ResourceHandle::start(Frame* frame)
RetainPtr<CFURLRequestRef> request(AdoptCF, makeFinalRequest(d->m_request, d->m_shouldContentSniff));
- static CFIndex clientVersion = highestSupportedCFURLConnectionClientVersion();
- CFURLConnectionClient* client;
-#if defined(_CFURLConnectionClientV3Present)
- CFURLConnectionClient_V3 client_V3 = {clientVersion, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData, shouldUseCredentialStorageCallback, 0};
- client = reinterpret_cast<CFURLConnectionClient*>(&client_V3);
-#elif defined(_CFURLConnectionClientV2Present)
- CFURLConnectionClient_V2 client_V2 = {clientVersion, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData};
- client = reinterpret_cast<CFURLConnectionClient*>(&client_V2);
-#else
- CFURLConnectionClient client_V1 = {1, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge};
- client = &client_V1;
-#endif
-
- d->m_connection.adoptCF(CFURLConnectionCreate(0, request.get(), client));
+ CFURLConnectionClient_V3 client = { 3, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData, shouldUseCredentialStorageCallback, 0};
+
+ d->m_connection.adoptCF(CFURLConnectionCreate(0, request.get(), reinterpret_cast<CFURLConnectionClient*>(&client)));
CFURLConnectionScheduleWithCurrentMessageQueue(d->m_connection.get());
CFURLConnectionScheduleDownloadWithRunLoop(d->m_connection.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
@@ -519,12 +462,22 @@ bool ResourceHandle::loadsBlocked()
return false;
}
-bool ResourceHandle::willLoadFromCache(ResourceRequest&)
+bool ResourceHandle::willLoadFromCache(ResourceRequest& request)
{
- // Not having this function means that we'll ask the user about re-posting a form
- // even when we go back to a page that's still in the cache.
- notImplemented();
- return false;
+ request.setCachePolicy(ReturnCacheDataDontLoad);
+
+ CFURLResponseRef cfResponse = 0;
+ CFErrorRef cfError = 0;
+ RetainPtr<CFURLRequestRef> cfRequest(AdoptCF, makeFinalRequest(request, true));
+ RetainPtr<CFDataRef> data(AdoptCF, CFURLConnectionSendSynchronousRequest(cfRequest.get(), &cfResponse, &cfError, request.timeoutInterval()));
+ bool cached = cfResponse && !cfError;
+
+ if (cfError)
+ CFRelease(cfError);
+ if (cfResponse)
+ CFRelease(cfResponse);
+
+ return cached;
}
} // namespace WebCore
diff --git a/WebCore/platform/network/cf/ResourceRequestCFNet.h b/WebCore/platform/network/cf/ResourceRequestCFNet.h
index e9ebe76..d26072d 100644
--- a/WebCore/platform/network/cf/ResourceRequestCFNet.h
+++ b/WebCore/platform/network/cf/ResourceRequestCFNet.h
@@ -30,7 +30,7 @@ typedef const struct _CFURLRequest* CFURLRequestRef;
namespace WebCore {
- class ResourceRequest;
+ struct ResourceRequest;
void getResourceRequest(ResourceRequest&, CFURLRequestRef);
CFURLRequestRef cfURLRequest(const ResourceRequest&);
diff --git a/WebCore/platform/network/cf/ResourceResponse.h b/WebCore/platform/network/cf/ResourceResponse.h
index e14c79e..04cc82c 100644
--- a/WebCore/platform/network/cf/ResourceResponse.h
+++ b/WebCore/platform/network/cf/ResourceResponse.h
@@ -52,6 +52,18 @@ public:
{
}
+ unsigned memoryUsage() const
+ {
+ // FIXME: Find some programmatic lighweight way to calculate ResourceResponse and associated classes.
+ // This is a rough estimate of resource overhead based on stats collected from the stress test.
+ return 3072;
+ /* 1280 * 2 + // average size of ResourceResponse. Doubled to account for the WebCore copy and the CF copy.
+ // Mostly due to the size of the hash maps, the Header Map strings and the URL.
+ 256 * 2 // Overhead from ResourceRequest, doubled to account for WebCore copy and CF copy.
+ // Mostly due to the URL and Header Map.
+ */
+ }
+
CFURLResponseRef cfURLResponse() const;
private:
diff --git a/WebCore/platform/network/chromium/ResourceRequest.h b/WebCore/platform/network/chromium/ResourceRequest.h
index 76b8b99..b14dba6 100644
--- a/WebCore/platform/network/chromium/ResourceRequest.h
+++ b/WebCore/platform/network/chromium/ResourceRequest.h
@@ -35,7 +35,7 @@ namespace WebCore {
class Frame;
- class ResourceRequest : public ResourceRequestBase {
+ struct ResourceRequest : public ResourceRequestBase {
public:
enum TargetType {
TargetIsMainFrame,
@@ -47,16 +47,16 @@ namespace WebCore {
ResourceRequest(const String& url)
: ResourceRequestBase(KURL(url), UseProtocolCachePolicy)
- , m_frame(0)
- , m_originPid(0)
+ , m_requestorID(0)
+ , m_requestorProcessID(0)
, m_targetType(TargetIsSubResource)
{
}
ResourceRequest(const KURL& url, const CString& securityInfo)
: ResourceRequestBase(url, UseProtocolCachePolicy)
- , m_frame(0)
- , m_originPid(0)
+ , m_requestorID(0)
+ , m_requestorProcessID(0)
, m_targetType(TargetIsSubResource)
, m_securityInfo(securityInfo)
{
@@ -64,16 +64,16 @@ namespace WebCore {
ResourceRequest(const KURL& url)
: ResourceRequestBase(url, UseProtocolCachePolicy)
- , m_frame(0)
- , m_originPid(0)
+ , m_requestorID(0)
+ , m_requestorProcessID(0)
, m_targetType(TargetIsSubResource)
{
}
ResourceRequest(const KURL& url, const String& referrer, ResourceRequestCachePolicy policy = UseProtocolCachePolicy)
: ResourceRequestBase(url, policy)
- , m_frame(0)
- , m_originPid(0)
+ , m_requestorID(0)
+ , m_requestorProcessID(0)
, m_targetType(TargetIsSubResource)
{
setHTTPReferrer(referrer);
@@ -81,26 +81,30 @@ namespace WebCore {
ResourceRequest()
: ResourceRequestBase(KURL(), UseProtocolCachePolicy)
- , m_frame(0)
- , m_originPid(0)
+ , m_requestorID(0)
+ , m_requestorProcessID(0)
, m_targetType(TargetIsSubResource)
{
}
- // Provides context for the resource request.
- Frame* frame() const { return m_frame; }
- void setFrame(Frame* frame) { m_frame = frame; }
+ // Allows the request to be matched up with its requestor.
+ int requestorID() const { return m_requestorID; }
+ void setRequestorID(int requestorID) { m_requestorID = requestorID; }
// What this request is for.
- void setTargetType(TargetType type) { m_targetType = type; }
TargetType targetType() const { return m_targetType; }
-
- // The origin pid is the process id of the process from which this
- // request originated. In the case of out-of-process plugins, this
- // allows to link back the request to the plugin process (as it is
- // processed through a render view process).
- int originPid() const { return m_originPid; }
- void setOriginPid(int originPid) { m_originPid = originPid; }
+ void setTargetType(TargetType type) { m_targetType = type; }
+
+ // The document's policy base url.
+ KURL policyURL() const { return m_policyURL; }
+ void setPolicyURL(const KURL& policyURL) { m_policyURL = policyURL; }
+
+ // The process id of the process from which this request originated. In
+ // the case of out-of-process plugins, this allows to link back the
+ // request to the plugin process (as it is processed through a render
+ // view process).
+ int requestorProcessID() const { return m_requestorProcessID; }
+ void setRequestorProcessID(int requestorProcessID) { m_requestorProcessID = requestorProcessID; }
// Opaque buffer that describes the security state (including SSL
// connection state) for the resource that should be reported when the
@@ -117,10 +121,11 @@ namespace WebCore {
void doUpdatePlatformRequest() {}
void doUpdateResourceRequest() {}
- Frame* m_frame;
- int m_originPid;
+ int m_requestorID;
+ int m_requestorProcessID;
TargetType m_targetType;
CString m_securityInfo;
+ KURL m_policyURL;
};
} // namespace WebCore
diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp
index 6a44233..6f009db 100644
--- a/WebCore/platform/network/curl/ResourceHandleManager.cpp
+++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp
@@ -126,7 +126,7 @@ static size_t writeCallback(void* ptr, size_t size, size_t nmemb, void* data)
if (!d->m_response.responseFired()) {
const char* hdr;
err = curl_easy_getinfo(h, CURLINFO_EFFECTIVE_URL, &hdr);
- d->m_response.setUrl(KURL(hdr));
+ d->m_response.setURL(KURL(hdr));
if (d->client())
d->client()->didReceiveResponse(job, d->m_response);
d->m_response.setResponseFired(true);
@@ -180,7 +180,7 @@ static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* data)
const char* hdr;
err = curl_easy_getinfo(h, CURLINFO_EFFECTIVE_URL, &hdr);
- d->m_response.setUrl(KURL(hdr));
+ d->m_response.setURL(KURL(hdr));
long httpCode = 0;
err = curl_easy_getinfo(h, CURLINFO_RESPONSE_CODE, &httpCode);
diff --git a/WebCore/platform/network/mac/FormDataStreamMac.mm b/WebCore/platform/network/mac/FormDataStreamMac.mm
index b618949..94fdb25 100644
--- a/WebCore/platform/network/mac/FormDataStreamMac.mm
+++ b/WebCore/platform/network/mac/FormDataStreamMac.mm
@@ -204,7 +204,7 @@ static void* formCreate(CFReadStreamRef stream, void* context)
// Append in reverse order since we remove elements from the end.
size_t size = formData->elements().size();
- newInfo->remainingElements.reserveCapacity(size);
+ newInfo->remainingElements.reserveInitialCapacity(size);
for (size_t i = 0; i < size; ++i)
newInfo->remainingElements.append(formData->elements()[size - i - 1]);
diff --git a/WebCore/platform/network/mac/ResourceErrorMac.mm b/WebCore/platform/network/mac/ResourceErrorMac.mm
index e59eadd..94c2124 100644
--- a/WebCore/platform/network/mac/ResourceErrorMac.mm
+++ b/WebCore/platform/network/mac/ResourceErrorMac.mm
@@ -26,6 +26,7 @@
#import "config.h"
#import "ResourceError.h"
+#import "BlockExceptions.h"
#import "KURL.h"
#import <Foundation/Foundation.h>
@@ -46,8 +47,12 @@ void ResourceError::platformLazyInit()
NSString* failingURLString = [[m_platformError.get() userInfo] valueForKey:@"NSErrorFailingURLStringKey"];
if (!failingURLString)
failingURLString = [[[m_platformError.get() userInfo] valueForKey:@"NSErrorFailingURLKey"] absoluteString];
-
+
+ // Workaround for <rdar://problem/6554067>
+ m_localizedDescription = failingURLString;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
m_localizedDescription = [m_platformError.get() _web_localizedDescription];
+ END_BLOCK_OBJC_EXCEPTIONS;
m_dataIsUpToDate = true;
}
diff --git a/WebCore/platform/network/mac/ResourceRequestMac.mm b/WebCore/platform/network/mac/ResourceRequestMac.mm
index a9bbd40..92c37ee 100644
--- a/WebCore/platform/network/mac/ResourceRequestMac.mm
+++ b/WebCore/platform/network/mac/ResourceRequestMac.mm
@@ -119,8 +119,8 @@ void ResourceRequest::doUpdatePlatformRequest()
for (HTTPHeaderMap::const_iterator it = httpHeaderFields().begin(); it != end; ++it)
[nsRequest setValue:it->second forHTTPHeaderField:it->first];
- // The below check can be removed once we require a version of Foundation with -[NSMutableURLRequest setContentDispositionEncodingFallbackArray] method.
- static bool supportsContentDispositionEncodingFallbackArray = [NSMutableURLRequest instancesRespondToSelector:@selector(setContentDispositionEncodingFallbackArray)];
+ // The below check can be removed once we require a version of Foundation with -[NSMutableURLRequest setContentDispositionEncodingFallbackArray:] method.
+ static bool supportsContentDispositionEncodingFallbackArray = [NSMutableURLRequest instancesRespondToSelector:@selector(setContentDispositionEncodingFallbackArray:)];
if (supportsContentDispositionEncodingFallbackArray) {
NSMutableArray *encodingFallbacks = [NSMutableArray array];
unsigned count = m_responseContentDispositionEncodingFallbackArray.size();
diff --git a/WebCore/platform/network/mac/ResourceResponse.h b/WebCore/platform/network/mac/ResourceResponse.h
index b65760c..16b0cbf 100644
--- a/WebCore/platform/network/mac/ResourceResponse.h
+++ b/WebCore/platform/network/mac/ResourceResponse.h
@@ -57,6 +57,18 @@ public:
{
}
+ unsigned memoryUsage() const
+ {
+ // FIXME: Find some programmatic lighweight way to calculate ResourceResponse and associated classes.
+ // This is a rough estimate of resource overhead based on stats collected from the stress test.
+ return 3072;
+ /* 1280 * 2 + // average size of ResourceResponse. Doubled to account for the WebCore copy and the CF copy.
+ // Mostly due to the size of the hash maps, the Header Map strings and the URL.
+ 256 * 2 // Overhead from ResourceRequest, doubled to account for WebCore copy and CF copy.
+ // Mostly due to the URL and Header Map.
+ */
+ }
+
NSURLResponse *nsURLResponse() const;
private:
diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
index 2de2125..2c730a6 100644
--- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
+++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
@@ -269,8 +269,10 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
const bool isLocalFileReply = (m_reply->url().scheme() == QLatin1String("file"));
int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
- if (!isLocalFileReply)
+ if (!isLocalFileReply) {
response.setHTTPStatusCode(statusCode);
+ response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData());
+ }
else if (m_reply->error() == QNetworkReply::ContentNotFoundError)
response.setHTTPStatusCode(404);
diff --git a/WebCore/platform/network/soup/CookieJarSoup.cpp b/WebCore/platform/network/soup/CookieJarSoup.cpp
index 88109e8..e3064e1 100644
--- a/WebCore/platform/network/soup/CookieJarSoup.cpp
+++ b/WebCore/platform/network/soup/CookieJarSoup.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 Xan Lopez <xan@gnome.org>
+ * Copyright (C) 2009 Igalia S.L.
* Copyright (C) 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -25,15 +26,35 @@
namespace WebCore {
-SoupCookieJar* getCookieJar()
+static bool cookiesInitialized;
+static SoupCookieJar* cookieJar;
+
+SoupCookieJar* defaultCookieJar()
+{
+ if (!cookiesInitialized) {
+ cookiesInitialized = true;
+ setDefaultCookieJar(soup_cookie_jar_new());
+ }
+
+ return cookieJar;
+}
+
+void setDefaultCookieJar(SoupCookieJar* jar)
{
- static SoupCookieJar* jar = soup_cookie_jar_new();
- return jar;
+ cookiesInitialized = true;
+
+ if (cookieJar)
+ g_object_unref(cookieJar);
+
+ cookieJar = jar;
+
+ if (cookieJar)
+ g_object_ref(cookieJar);
}
void setCookies(Document* /*document*/, const KURL& url, const KURL& /*policyURL*/, const String& value)
{
- SoupCookieJar* jar = getCookieJar();
+ SoupCookieJar* jar = defaultCookieJar();
if (!jar)
return;
@@ -45,7 +66,7 @@ void setCookies(Document* /*document*/, const KURL& url, const KURL& /*policyURL
String cookies(const Document* /*document*/, const KURL& url)
{
- SoupCookieJar* jar = getCookieJar();
+ SoupCookieJar* jar = defaultCookieJar();
if (!jar)
return String();
@@ -61,7 +82,7 @@ String cookies(const Document* /*document*/, const KURL& url)
bool cookiesEnabled(const Document* /*document*/)
{
- return getCookieJar();
+ return defaultCookieJar();
}
}
diff --git a/WebCore/platform/network/soup/CookieJarSoup.h b/WebCore/platform/network/soup/CookieJarSoup.h
index 61179ae..ab1f95c 100644
--- a/WebCore/platform/network/soup/CookieJarSoup.h
+++ b/WebCore/platform/network/soup/CookieJarSoup.h
@@ -31,7 +31,8 @@
#include <libsoup/soup.h>
namespace WebCore {
- SoupCookieJar* getCookieJar();
+ SoupCookieJar* defaultCookieJar();
+ void setDefaultCookieJar(SoupCookieJar* jar);
}
#endif
diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
index da96873..1b91e32 100644
--- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp
+++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
@@ -3,6 +3,9 @@
* Copyright (C) 2008 Xan Lopez <xan@gnome.org>
* Copyright (C) 2008 Collabora Ltd.
* Copyright (C) 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
+ * Copyright (C) 2009 Christian Dywan <christian@imendio.com>
+ * Copyright (C) 2009 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
@@ -21,41 +24,109 @@
*/
#include "config.h"
-#include "CString.h"
#include "ResourceHandle.h"
#include "Base64.h"
#include "CookieJarSoup.h"
+#include "ChromeClient.h"
+#include "CString.h"
#include "DocLoader.h"
+#include "FileSystem.h"
#include "Frame.h"
#include "HTTPParsers.h"
+#include "Logging.h"
#include "MIMETypeRegistry.h"
#include "NotImplemented.h"
+#include "Page.h"
#include "ResourceError.h"
#include "ResourceHandleClient.h"
#include "ResourceHandleInternal.h"
#include "ResourceResponse.h"
#include "TextEncoding.h"
+#include <errno.h>
+#include <fcntl.h>
#include <gio/gio.h>
+#include <gtk/gtk.h>
#include <libsoup/soup.h>
-#include <libsoup/soup-message.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#if PLATFORM(GTK)
- #if GLIB_CHECK_VERSION(2,12,0)
- #define USE_GLIB_BASE64
- #endif
+#define USE_GLIB_BASE64
#endif
namespace WebCore {
-static SoupSession* session = 0;
+class WebCoreSynchronousLoader : public ResourceHandleClient, Noncopyable {
+public:
+ WebCoreSynchronousLoader(ResourceError&, ResourceResponse &, Vector<char>&);
+ ~WebCoreSynchronousLoader();
+
+ virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
+ virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived);
+ virtual void didFinishLoading(ResourceHandle*);
+ virtual void didFail(ResourceHandle*, const ResourceError&);
+
+ void run();
+
+private:
+ ResourceError& m_error;
+ ResourceResponse& m_response;
+ Vector<char>& m_data;
+ bool m_finished;
+ GMainLoop* m_mainLoop;
+};
+
+WebCoreSynchronousLoader::WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data)
+ : m_error(error)
+ , m_response(response)
+ , m_data(data)
+ , m_finished(false)
+{
+ m_mainLoop = g_main_loop_new(0, false);
+}
+
+WebCoreSynchronousLoader::~WebCoreSynchronousLoader()
+{
+ g_main_loop_unref(m_mainLoop);
+}
+
+void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
+{
+ m_response = response;
+}
+
+void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, int length, int)
+{
+ m_data.append(data, length);
+}
+
+void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*)
+{
+ g_main_loop_quit(m_mainLoop);
+ m_finished = true;
+}
+
+void WebCoreSynchronousLoader::didFail(ResourceHandle* handle, const ResourceError& error)
+{
+ m_error = error;
+ didFinishLoading(handle);
+}
+
+void WebCoreSynchronousLoader::run()
+{
+ if (!m_finished)
+ g_main_loop_run(m_mainLoop);
+}
enum
{
ERROR_TRANSPORT,
ERROR_UNKNOWN_PROTOCOL,
- ERROR_BAD_NON_HTTP_METHOD
+ ERROR_BAD_NON_HTTP_METHOD,
+ ERROR_UNABLE_TO_OPEN_FILE,
};
static void cleanupGioOperation(ResourceHandleInternal* handle);
@@ -82,20 +153,47 @@ ResourceHandle::~ResourceHandle()
static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response)
{
SoupMessageHeadersIter iter;
- const char* name = NULL;
- const char* value = NULL;
+ const char* name = 0;
+ const char* value = 0;
soup_message_headers_iter_init(&iter, msg->response_headers);
while (soup_message_headers_iter_next(&iter, &name, &value))
response->setHTTPHeaderField(name, value);
- String contentType = soup_message_headers_get(msg->response_headers, "Content-Type");
- char* uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE);
- response->setUrl(KURL(uri));
- g_free(uri);
+ GHashTable* contentTypeParameters = 0;
+ String contentType = soup_message_headers_get_content_type(msg->response_headers, &contentTypeParameters);
+
+ // When the server sends multiple Content-Type headers, soup will
+ // give us their values concatenated with commas as a separator;
+ // we need to handle this and use only one value. We use the first
+ // value, and add all the parameters, afterwards, if any.
+ Vector<String> contentTypes;
+ contentType.split(',', true, contentTypes);
+ contentType = contentTypes[0];
+
+ if (contentTypeParameters) {
+ GHashTableIter hashTableIter;
+ gpointer hashKey;
+ gpointer hashValue;
+
+ g_hash_table_iter_init(&hashTableIter, contentTypeParameters);
+ while (g_hash_table_iter_next(&hashTableIter, &hashKey, &hashValue)) {
+ contentType += String("; ");
+ contentType += String(static_cast<char*>(hashKey));
+ contentType += String("=");
+ contentType += String(static_cast<char*>(hashValue));
+ }
+ g_hash_table_destroy(contentTypeParameters);
+ }
+
response->setMimeType(extractMIMETypeFromMediaType(contentType));
+
+ char* uri = soup_uri_to_string(soup_message_get_uri(msg), false);
+ response->setURL(KURL(KURL(), uri));
+ g_free(uri);
response->setTextEncodingName(extractCharsetFromMediaType(contentType));
response->setExpectedContentLength(soup_message_headers_get_content_length(msg->response_headers));
response->setHTTPStatusCode(msg->status_code);
+ response->setHTTPStatusText(msg->reason_phrase);
response->setSuggestedFilename(filenameFromHTTPContentDisposition(response->httpHeaderField("Content-Disposition")));
}
@@ -110,11 +208,20 @@ static void restartedCallback(SoupMessage* msg, gpointer data)
if (d->m_cancelled)
return;
- char* uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE);
+ char* uri = soup_uri_to_string(soup_message_get_uri(msg), false);
String location = String(uri);
g_free(uri);
KURL newURL = KURL(handle->request().url(), location);
+ // FIXME: This is needed because some servers use broken URIs in
+ // their Location header, when redirecting, such as URIs with
+ // white spaces instead of %20; this should be fixed in soup, in
+ // the future, and this work-around removed.
+ // See http://bugzilla.gnome.org/show_bug.cgi?id=575378.
+ SoupURI* soup_uri = soup_uri_new(newURL.string().utf8().data());
+ soup_message_set_uri(msg, soup_uri);
+ soup_uri_free(soup_uri);
+
ResourceRequest request = handle->request();
ResourceResponse response;
request.setURL(newURL);
@@ -127,7 +234,32 @@ static void restartedCallback(SoupMessage* msg, gpointer data)
static void gotHeadersCallback(SoupMessage* msg, gpointer data)
{
- if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code))
+ // 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) {
+ soup_message_body_set_accumulate(msg->response_body, TRUE);
+ return;
+ }
+
+ // For all the other responses, we handle each chunk ourselves,
+ // and we don't need msg->response_body to contain all of the data
+ // we got, when we finish downloading.
+ soup_message_body_set_accumulate(msg->response_body, FALSE);
+
+ // The 304 status code (SOUP_STATUS_NOT_MODIFIED) needs to be fed
+ // into WebCore, as opposed to other kinds of redirections, which
+ // are handled by soup directly, so we special-case it here and in
+ // gotChunk.
+ if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)
+ || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED)))
+ return;
+
+ // We still don't know anything about Content-Type, so we will try
+ // sniffing the contents of the file, and then report that we got
+ // headers; we will not do content sniffing for 304 responses,
+ // though, since they do not have a body.
+ if ((msg->status_code != SOUP_STATUS_NOT_MODIFIED)
+ && !soup_message_headers_get_content_type(msg->response_headers, NULL))
return;
ResourceHandle* handle = static_cast<ResourceHandle*>(data);
@@ -142,12 +274,14 @@ static void gotHeadersCallback(SoupMessage* msg, gpointer data)
fillResponseFromMessage(msg, &d->m_response);
client->didReceiveResponse(handle, d->m_response);
- soup_message_set_flags(msg, SOUP_MESSAGE_OVERWRITE_CHUNKS);
+ d->m_reportedHeaders = true;
}
static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data)
{
- if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code))
+ if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)
+ || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED))
+ || (msg->status_code == SOUP_STATUS_UNAUTHORIZED))
return;
ResourceHandle* handle = static_cast<ResourceHandle*>(data);
@@ -160,6 +294,17 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data)
if (!client)
return;
+ if (!d->m_reportedHeaders) {
+ gboolean uncertain;
+ char* contentType = g_content_type_guess(d->m_request.url().lastPathComponent().utf8().data(), reinterpret_cast<const guchar*>(chunk->data), chunk->length, &uncertain);
+ soup_message_headers_set_content_type(msg->response_headers, contentType, NULL);
+ g_free(contentType);
+
+ fillResponseFromMessage(msg, &d->m_response);
+ client->didReceiveResponse(handle, d->m_response);
+ d->m_reportedHeaders = true;
+ }
+
client->didReceiveData(handle, chunk->data, chunk->length, false);
}
@@ -167,7 +312,7 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data)
// Doesn't get called for redirects.
static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer data)
{
- ResourceHandle* handle = static_cast<ResourceHandle*>(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;
@@ -182,24 +327,26 @@ static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer da
return;
if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
- char* uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE);
+ char* uri = soup_uri_to_string(soup_message_get_uri(msg), false);
ResourceError error("webkit-network-error", ERROR_TRANSPORT, uri, String::fromUTF8(msg->reason_phrase));
g_free(uri);
- client->didFail(handle, error);
+ client->didFail(handle.get(), error);
return;
- } else if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
+ }
+
+ if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
fillResponseFromMessage(msg, &d->m_response);
- client->didReceiveResponse(handle, 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, msg->response_body->data, msg->response_body->length, true);
+ client->didReceiveData(handle.get(), msg->response_body->data, msg->response_body->length, true);
}
- client->didFinishLoading(handle);
+ client->didFinishLoading(handle.get());
}
// parseDataUrl() is taken from the CURL http backend.
@@ -212,7 +359,7 @@ static gboolean parseDataUrl(gpointer callback_data)
ASSERT(client);
if (!client)
- return FALSE;
+ return false;
String url = handle->request().url().string();
ASSERT(url.startsWith("data:", false));
@@ -220,14 +367,14 @@ static gboolean parseDataUrl(gpointer callback_data)
int index = url.find(',');
if (index == -1) {
client->cannotShowURL(handle);
- return FALSE;
+ return false;
}
String mediaType = url.substring(5, index - 5);
String data = url.substring(index + 1);
- bool base64 = mediaType.endsWith(";base64", false);
- if (base64)
+ bool isBase64 = mediaType.endsWith(";base64", false);
+ if (isBase64)
mediaType = mediaType.left(mediaType.length() - 7);
if (mediaType.isEmpty())
@@ -239,7 +386,7 @@ static gboolean parseDataUrl(gpointer callback_data)
ResourceResponse response;
response.setMimeType(mimeType);
- if (base64) {
+ if (isBase64) {
data = decodeURLEscapeSequences(data);
response.setTextEncodingName(charset);
client->didReceiveResponse(handle, response);
@@ -269,7 +416,7 @@ static gboolean parseDataUrl(gpointer callback_data)
client->didFinishLoading(handle);
- return FALSE;
+ return false;
}
bool ResourceHandle::startData(String urlString)
@@ -282,30 +429,44 @@ bool ResourceHandle::startData(String urlString)
return true;
}
-bool ResourceHandle::startHttp(String urlString)
+static SoupSession* createSoupSession()
{
- if (!session) {
- session = soup_session_async_new();
+ return soup_session_async_new();
+}
- soup_session_add_feature(session, SOUP_SESSION_FEATURE(getCookieJar()));
+static void ensureSessionIsInitialized(SoupSession* session)
+{
+ if (g_object_get_data(G_OBJECT(session), "webkit-init"))
+ return;
- const char* soup_debug = g_getenv("WEBKIT_SOUP_LOGGING");
- if (soup_debug) {
- int soup_debug_level = atoi(soup_debug);
+ SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
+ if (!jar)
+ soup_session_add_feature(session, SOUP_SESSION_FEATURE(defaultCookieJar()));
+ else
+ setDefaultCookieJar(jar);
- SoupLogger* logger = soup_logger_new(static_cast<SoupLoggerLogLevel>(soup_debug_level), -1);
- soup_logger_attach(logger, session);
- g_object_unref(logger);
- }
+ if (!soup_session_get_feature(session, SOUP_TYPE_LOGGER) && LogNetwork.state == WTFLogChannelOn) {
+ SoupLogger* logger = soup_logger_new(static_cast<SoupLoggerLogLevel>(SOUP_LOGGER_LOG_BODY), -1);
+ soup_logger_attach(logger, session);
+ g_object_unref(logger);
}
+ g_object_set_data(G_OBJECT(session), "webkit-init", reinterpret_cast<void*>(0xdeadbeef));
+}
+
+bool ResourceHandle::startHttp(String urlString)
+{
+ SoupSession* session = defaultSession();
+ ensureSessionIsInitialized(session);
+
SoupMessage* msg;
msg = soup_message_new(request().httpMethod().utf8().data(), urlString.utf8().data());
g_signal_connect(msg, "restarted", G_CALLBACK(restartedCallback), this);
-
g_signal_connect(msg, "got-headers", G_CALLBACK(gotHeadersCallback), this);
g_signal_connect(msg, "got-chunk", G_CALLBACK(gotChunkCallback), this);
+ g_object_set_data(G_OBJECT(msg), "resourceHandle", reinterpret_cast<void*>(this));
+
HTTPHeaderMap customHeaders = d->m_request.httpHeaderFields();
if (!customHeaders.isEmpty()) {
HTTPHeaderMap::const_iterator end = customHeaders.end();
@@ -315,68 +476,130 @@ bool ResourceHandle::startHttp(String urlString)
FormData* httpBody = d->m_request.httpBody();
if (httpBody && !httpBody->isEmpty()) {
- // Making a copy of the request body isn't the most efficient way to
- // serialize it, but by far the most simple. Dealing with individual
- // FormData elements and shared buffers should be more memory
- // efficient.
- //
- // This possibly isn't handling file uploads/attachments, for which
- // shared buffers or streaming should definitely be used.
- Vector<char> body;
- httpBody->flatten(body);
- soup_message_set_request(msg, d->m_request.httpContentType().utf8().data(),
- SOUP_MEMORY_COPY, body.data(), body.size());
+ size_t numElements = httpBody->elements().size();
+
+ // handle the most common case (i.e. no file upload)
+ if (numElements < 2) {
+ Vector<char> body;
+ httpBody->flatten(body);
+ soup_message_set_request(msg, d->m_request.httpContentType().utf8().data(),
+ SOUP_MEMORY_COPY, body.data(), body.size());
+ } else {
+ /*
+ * we have more than one element to upload, and some may
+ * be (big) files, which we will want to mmap instead of
+ * copying into memory; TODO: support upload of non-local
+ * (think sftp://) files by using GIO?
+ */
+ soup_message_body_set_accumulate(msg->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(msg->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;
+ gchar* fileName = filenameFromString(element.m_filename);
+ GMappedFile* fileMapping = g_mapped_file_new(fileName, false, &error);
+
+ g_free(fileName);
+
+ if (error) {
+ ResourceError resourceError("webkit-network-error", ERROR_UNABLE_TO_OPEN_FILE, urlString, error->message);
+ g_error_free(error);
+
+ d->client()->didFail(this, resourceError);
+
+ g_object_unref(msg);
+ return false;
+ }
+
+ SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping),
+ g_mapped_file_get_length(fileMapping),
+ fileMapping, reinterpret_cast<GDestroyNotify>(g_mapped_file_free));
+ soup_message_body_append_buffer(msg->request_body, soupBuffer);
+ soup_buffer_free(soupBuffer);
+ }
+ }
+ }
}
d->m_msg = static_cast<SoupMessage*>(g_object_ref(msg));
+ // balanced by a deref() in finishedCallback, which should always run
+ ref();
+
soup_session_queue_message(session, d->m_msg, finishedCallback, this);
return true;
}
+static gboolean reportUnknownProtocolError(gpointer callback_data)
+{
+ ResourceHandle* handle = static_cast<ResourceHandle*>(callback_data);
+ ResourceHandleInternal* d = handle->getInternal();
+ ResourceHandleClient* client = handle->client();
+
+ if (d->m_cancelled || !client) {
+ handle->deref();
+ return false;
+ }
+
+ KURL url = handle->request().url();
+ ResourceError error("webkit-network-error", ERROR_UNKNOWN_PROTOCOL, url.string(), url.protocol());
+ client->didFail(handle, error);
+
+ handle->deref();
+ return false;
+}
+
bool ResourceHandle::start(Frame* frame)
{
ASSERT(!d->m_msg);
- // If we are no longer attached to a Page, this must be an attempted load from an
- // onUnload handler, so let's just block it.
- if (!frame->page())
+
+ // The frame could be null if the ResourceHandle is not associated to any
+ // Frame, e.g. if we are downloading a file.
+ // If the frame is not null but the page is null this must be an attempted
+ // load from an onUnload handler, so let's just block it.
+ if (frame && !frame->page())
return false;
KURL url = request().url();
String urlString = url.string();
String protocol = url.protocol();
+ // Used to set the authentication dialog toplevel; may be NULL
+ d->m_frame = frame;
+
if (equalIgnoringCase(protocol, "data"))
return startData(urlString);
- else if ((equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) && SOUP_URI_VALID_FOR_HTTP(soup_uri_new(urlString.utf8().data())))
+
+ if ((equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) && SOUP_URI_VALID_FOR_HTTP(soup_uri_new(urlString.utf8().data())))
return startHttp(urlString);
- else if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps"))
+
+ if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps"))
// FIXME: should we be doing any other protocols here?
- return startGio(urlString);
- else {
- // If we don't call didFail the job is not complete for webkit even false is returned.
- if (d->client()) {
- ResourceError error("webkit-network-error", ERROR_UNKNOWN_PROTOCOL, urlString, protocol);
- d->client()->didFail(this, error);
- }
- return false;
- }
+ return startGio(url);
+
+ // Error must not be reported immediately, but through an idle function.
+ // Despite error, we should return true so a proper handle is created,
+ // to which this failure can be reported.
+ ref();
+ d->m_idleHandler = g_idle_add(reportUnknownProtocolError, this);
+ return true;
}
void ResourceHandle::cancel()
{
d->m_cancelled = true;
- if (d->m_msg) {
- soup_session_cancel_message(session, d->m_msg, SOUP_STATUS_CANCELLED);
- // For re-entrancy troubles we call didFinishLoading when the message hasn't been handled yet.
- if (client())
- client()->didFinishLoading(this);
- } else if (d->m_cancellable) {
+ if (d->m_msg)
+ soup_session_cancel_message(defaultSession(), d->m_msg, SOUP_STATUS_CANCELLED);
+ else if (d->m_cancellable)
g_cancellable_cancel(d->m_cancellable);
- if (client())
- client()->didFinishLoading(this);
- }
}
PassRefPtr<SharedBuffer> ResourceHandle::bufferedData()
@@ -409,9 +632,13 @@ bool ResourceHandle::willLoadFromCache(ResourceRequest&)
return false;
}
-void ResourceHandle::loadResourceSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>&, Frame*)
+void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame)
{
- notImplemented();
+ WebCoreSynchronousLoader syncLoader(error, response, data);
+ ResourceHandle handle(request, &syncLoader, true, false, true);
+
+ handle.start(frame);
+ syncLoader.run();
}
// GIO-based loader
@@ -420,7 +647,7 @@ static inline ResourceError networkErrorForFile(GFile* file, GError* error)
{
// FIXME: Map gio errors to a more detailed error code when we have it in WebKit.
gchar* uri = g_file_get_uri(file);
- ResourceError resourceError("webkit-network-error", ERROR_TRANSPORT, uri, String::fromUTF8(error->message));
+ ResourceError resourceError("webkit-network-error", ERROR_TRANSPORT, uri, error ? String::fromUTF8(error->message) : String());
g_free(uri);
return resourceError;
}
@@ -430,20 +657,23 @@ static void cleanupGioOperation(ResourceHandleInternal* d)
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 = NULL;
+ d->m_gfile = 0;
}
+
if (d->m_cancellable) {
g_object_unref(d->m_cancellable);
- d->m_cancellable = NULL;
+ d->m_cancellable = 0;
}
- if (d->m_input_stream) {
- g_object_set_data(G_OBJECT(d->m_input_stream), "webkit-resource", 0);
- g_object_unref(d->m_input_stream);
- d->m_input_stream = NULL;
+
+ 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 = NULL;
+ d->m_buffer = 0;
}
}
@@ -456,14 +686,15 @@ static void closeCallback(GObject* source, GAsyncResult* res, gpointer)
ResourceHandleInternal* d = handle->getInternal();
ResourceHandleClient* client = handle->client();
- g_input_stream_close_finish(d->m_input_stream, res, NULL);
+ g_input_stream_close_finish(d->m_inputStream, res, 0);
cleanupGioOperation(d);
client->didFinishLoading(handle);
}
static void readCallback(GObject* source, GAsyncResult* res, gpointer)
{
- ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));
+ // didReceiveData may cancel the load, which may release the last reference.
+ RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));
if (!handle)
return;
@@ -475,27 +706,34 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer)
return;
}
- gssize nread;
GError *error = 0;
- nread = g_input_stream_read_finish(d->m_input_stream, res, &error);
+ gssize bytesRead = g_input_stream_read_finish(d->m_inputStream, res, &error);
if (error) {
ResourceError resourceError = networkErrorForFile(d->m_gfile, error);
+ g_error_free(error);
cleanupGioOperation(d);
- client->didFail(handle, resourceError);
+ client->didFail(handle.get(), resourceError);
return;
- } else if (!nread) {
- g_input_stream_close_async(d->m_input_stream, G_PRIORITY_DEFAULT,
- NULL, closeCallback, NULL);
+ }
+
+ if (!bytesRead) {
+ g_input_stream_close_async(d->m_inputStream, G_PRIORITY_DEFAULT,
+ 0, closeCallback, 0);
return;
}
- d->m_total += nread;
- client->didReceiveData(handle, d->m_buffer, nread, d->m_total);
+ d->m_total += bytesRead;
+ client->didReceiveData(handle.get(), d->m_buffer, bytesRead, d->m_total);
- g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize,
+ if (d->m_cancelled) {
+ cleanupGioOperation(d);
+ return;
+ }
+
+ g_input_stream_read_async(d->m_inputStream, d->m_buffer, d->m_bufferSize,
G_PRIORITY_DEFAULT, d->m_cancellable,
- readCallback, NULL);
+ readCallback, 0);
}
static void openCallback(GObject* source, GAsyncResult* res, gpointer)
@@ -512,24 +750,24 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer)
return;
}
- GFileInputStream* in;
- GError *error = NULL;
- in = g_file_read_finish(G_FILE(source), res, &error);
+ GError *error = 0;
+ GFileInputStream* in = g_file_read_finish(G_FILE(source), res, &error);
if (error) {
ResourceError resourceError = networkErrorForFile(d->m_gfile, error);
+ g_error_free(error);
cleanupGioOperation(d);
client->didFail(handle, resourceError);
return;
}
- d->m_input_stream = G_INPUT_STREAM(in);
- d->m_bufsize = 8192;
- d->m_buffer = static_cast<char*>(g_malloc(d->m_bufsize));
+ 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_input_stream), "webkit-resource", handle);
- g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize,
+ g_object_set_data(G_OBJECT(d->m_inputStream), "webkit-resource", handle);
+ g_input_stream_read_async(d->m_inputStream, d->m_buffer, d->m_bufferSize,
G_PRIORITY_DEFAULT, d->m_cancellable,
- readCallback, NULL);
+ readCallback, 0);
}
static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer)
@@ -549,10 +787,10 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer)
ResourceResponse response;
char* uri = g_file_get_uri(d->m_gfile);
- response.setUrl(KURL(uri));
+ response.setURL(KURL(KURL(), uri));
g_free(uri);
- GError *error = NULL;
+ GError *error = 0;
GFileInfo* info = g_file_query_info_finish(d->m_gfile, res, &error);
if (error) {
@@ -564,6 +802,7 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer)
// for a while).
ResourceError resourceError = networkErrorForFile(d->m_gfile, error);
+ g_error_free(error);
cleanupGioOperation(d);
client->didFail(handle, resourceError);
return;
@@ -573,7 +812,7 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer)
// FIXME: what if the URI points to a directory? Should we
// generate a listing? How? What do other backends do here?
- ResourceError resourceError = networkErrorForFile(d->m_gfile, error);
+ ResourceError resourceError = networkErrorForFile(d->m_gfile, 0);
cleanupGioOperation(d);
client->didFail(handle, resourceError);
return;
@@ -581,7 +820,6 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer)
response.setMimeType(g_file_info_get_content_type(info));
response.setExpectedContentLength(g_file_info_get_size(info));
- response.setHTTPStatusCode(SOUP_STATUS_OK);
GTimeVal tv;
g_file_info_get_modification_time(info, &tv);
@@ -590,23 +828,31 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer)
client->didReceiveResponse(handle, response);
g_file_read_async(d->m_gfile, G_PRIORITY_DEFAULT, d->m_cancellable,
- openCallback, NULL);
+ openCallback, 0);
}
-bool ResourceHandle::startGio(String urlString)
+bool ResourceHandle::startGio(KURL url)
{
- if (request().httpMethod() != "GET") {
- ResourceError error("webkit-network-error", ERROR_BAD_NON_HTTP_METHOD, urlString, request().httpMethod());
+ if (request().httpMethod() != "GET" && request().httpMethod() != "POST") {
+ ResourceError error("webkit-network-error", ERROR_BAD_NON_HTTP_METHOD, url.string(), request().httpMethod());
d->client()->didFail(this, error);
return false;
}
- // Remove the fragment part of the URL since the file backend doesn't deal with it
- int fragPos;
- if ((fragPos = urlString.find("#")) != -1)
- urlString = urlString.left(fragPos);
-
- d->m_gfile = g_file_new_for_uri(urlString.utf8().data());
+ // 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.removeRef();
+ url.setQuery(String());
+ url.setPort(0);
+
+ // 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
+ d->m_gfile = g_file_new_for_uri(url.string().utf8().data());
g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", this);
d->m_cancellable = g_cancellable_new();
g_file_query_info_async(d->m_gfile,
@@ -615,9 +861,16 @@ bool ResourceHandle::startGio(String urlString)
G_FILE_ATTRIBUTE_STANDARD_SIZE,
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_DEFAULT, d->m_cancellable,
- queryInfoCallback, NULL);
+ queryInfoCallback, 0);
return true;
}
+SoupSession* ResourceHandle::defaultSession()
+{
+ static SoupSession* session = createSoupSession();;
+
+ return session;
+}
+
}
diff --git a/WebCore/platform/network/win/CookieJarCFNetWin.cpp b/WebCore/platform/network/win/CookieJarCFNetWin.cpp
index 56d7265..7e64813 100644
--- a/WebCore/platform/network/win/CookieJarCFNetWin.cpp
+++ b/WebCore/platform/network/win/CookieJarCFNetWin.cpp
@@ -41,28 +41,6 @@ namespace WebCore {
static const CFStringRef s_setCookieKeyCF = CFSTR("Set-Cookie");
static const CFStringRef s_cookieCF = CFSTR("Cookie");
-typedef Boolean (*IsHTTPOnlyFunction)(CFHTTPCookieRef);
-
-static HMODULE findCFNetworkModule()
-{
- if (HMODULE module = GetModuleHandleA("CFNetwork"))
- return module;
- return GetModuleHandleA("CFNetwork_debug");
-}
-
-static IsHTTPOnlyFunction findIsHTTPOnlyFunction()
-{
- return reinterpret_cast<IsHTTPOnlyFunction>(GetProcAddress(findCFNetworkModule(), "CFHTTPCookieIsHTTPOnly"));
-}
-
-static bool isHTTPOnly(CFHTTPCookieRef cookie)
-{
- // Once we require a newer version of CFNetwork with the CFHTTPCookieIsHTTPOnly function,
- // we can change this to be a normal function call and eliminate findIsHTTPOnlyFunction.
- static IsHTTPOnlyFunction function = findIsHTTPOnlyFunction();
- return function && function(cookie);
-}
-
static RetainPtr<CFArrayRef> filterCookies(CFArrayRef unfilteredCookies)
{
CFIndex count = CFArrayGetCount(unfilteredCookies);
@@ -77,7 +55,7 @@ static RetainPtr<CFArrayRef> filterCookies(CFArrayRef unfilteredCookies)
if (!CFStringGetLength(CFHTTPCookieGetName(cookie)))
continue;
- if (isHTTPOnly(cookie))
+ if (CFHTTPCookieIsHTTPOnly(cookie))
continue;
CFArrayAppendValue(filteredCookies.get(), cookie);
diff --git a/WebCore/platform/qt/CookieJarQt.cpp b/WebCore/platform/qt/CookieJarQt.cpp
index 0d24c7e..4077407 100644
--- a/WebCore/platform/qt/CookieJarQt.cpp
+++ b/WebCore/platform/qt/CookieJarQt.cpp
@@ -80,7 +80,7 @@ void setCookies(Document* document, const KURL& url, const KURL& policyURL, cons
++it;
}
#endif
- jar->setCookiesFromUrl(cookies, p);
+ jar->setCookiesFromUrl(cookies, u);
#else
QCookieJar::cookieJar()->setCookies(u, p, (QString)value);
#endif
diff --git a/WebCore/platform/qt/FileSystemQt.cpp b/WebCore/platform/qt/FileSystemQt.cpp
index 6dbe464..8a272c1 100644
--- a/WebCore/platform/qt/FileSystemQt.cpp
+++ b/WebCore/platform/qt/FileSystemQt.cpp
@@ -124,7 +124,7 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
return String(temp->fileName()).utf8();
}
handle = invalidPlatformFileHandle;
- return 0;
+ return CString();
}
void closeFile(PlatformFileHandle& handle)
@@ -143,32 +143,24 @@ int writeToFile(PlatformFileHandle handle, const char* data, int length)
return 0;
}
-#if defined(Q_WS_X11) || defined(Q_WS_QWS)
bool unloadModule(PlatformModule module)
{
+#if defined(Q_WS_MAC)
+ CFRelease(module);
+ return true;
+
+#elif defined(Q_OS_WIN)
+ return ::FreeLibrary(module);
+
+#else
if (module->unload()) {
delete module;
return true;
}
-
+
return false;
-}
-#endif
-
-#if defined(Q_WS_MAC)
-bool unloadModule(PlatformModule module)
-{
- CFRelease(module);
- return true;
-}
#endif
-
-#if defined(Q_OS_WIN)
-bool unloadModule(PlatformModule module)
-{
- return ::FreeLibrary(module);
}
-#endif
}
diff --git a/WebCore/platform/qt/KURLQt.cpp b/WebCore/platform/qt/KURLQt.cpp
index cdc4f48..0763fe0 100644
--- a/WebCore/platform/qt/KURLQt.cpp
+++ b/WebCore/platform/qt/KURLQt.cpp
@@ -20,6 +20,7 @@
#include "config.h"
#include "KURL.h"
#include "CString.h"
+#include "TextEncoding.h"
#include "NotImplemented.h"
#include "qurl.h"
@@ -36,7 +37,7 @@ static inline char toHex(char c)
KURL::KURL(const QUrl& url)
{
- *this = KURL(url.toEncoded().constData());
+ *this = KURL(KURL(), url.toEncoded().constData(), UTF8Encoding());
}
KURL::operator QUrl() const
diff --git a/WebCore/platform/qt/PlatformKeyboardEventQt.cpp b/WebCore/platform/qt/PlatformKeyboardEventQt.cpp
index 76342ab..88cca5a 100644
--- a/WebCore/platform/qt/PlatformKeyboardEventQt.cpp
+++ b/WebCore/platform/qt/PlatformKeyboardEventQt.cpp
@@ -192,6 +192,55 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode)
case Qt::Key_Alt:
return VK_MENU; // (12) ALT key
+ case Qt::Key_F1:
+ return VK_F1;
+ case Qt::Key_F2:
+ return VK_F2;
+ case Qt::Key_F3:
+ return VK_F3;
+ case Qt::Key_F4:
+ return VK_F4;
+ case Qt::Key_F5:
+ return VK_F5;
+ case Qt::Key_F6:
+ return VK_F6;
+ case Qt::Key_F7:
+ return VK_F7;
+ case Qt::Key_F8:
+ return VK_F8;
+ case Qt::Key_F9:
+ return VK_F9;
+ case Qt::Key_F10:
+ return VK_F11;
+ case Qt::Key_F11:
+ return VK_F11;
+ case Qt::Key_F12:
+ return VK_F12;
+ case Qt::Key_F13:
+ return VK_F13;
+ case Qt::Key_F14:
+ return VK_F14;
+ case Qt::Key_F15:
+ return VK_F15;
+ case Qt::Key_F16:
+ return VK_F16;
+ case Qt::Key_F17:
+ return VK_F17;
+ case Qt::Key_F18:
+ return VK_F18;
+ case Qt::Key_F19:
+ return VK_F19;
+ case Qt::Key_F20:
+ return VK_F20;
+ case Qt::Key_F21:
+ return VK_F21;
+ case Qt::Key_F22:
+ return VK_F22;
+ case Qt::Key_F23:
+ return VK_F23;
+ case Qt::Key_F24:
+ return VK_F24;
+
case Qt::Key_Pause:
return VK_PAUSE; // (13) PAUSE key
case Qt::Key_CapsLock:
diff --git a/WebCore/platform/qt/QWebPopup.cpp b/WebCore/platform/qt/QWebPopup.cpp
index d463ddf..4d57c9b 100644
--- a/WebCore/platform/qt/QWebPopup.cpp
+++ b/WebCore/platform/qt/QWebPopup.cpp
@@ -22,7 +22,9 @@
#include "QWebPopup.h"
#include "PopupMenuStyle.h"
-#include <QCoreApplication>
+#include <QAbstractItemView>
+#include <QApplication>
+#include <QInputContext>
#include <QMouseEvent>
namespace WebCore {
@@ -54,6 +56,16 @@ void QWebPopup::showPopup()
void QWebPopup::hidePopup()
{
+ QWidget* activeFocus = QApplication::focusWidget();
+ if (activeFocus && activeFocus == view()
+ && activeFocus->testAttribute(Qt::WA_InputMethodEnabled)) {
+ QInputContext* qic = activeFocus->inputContext();
+ if (qic) {
+ qic->reset();
+ qic->setFocusWidget(0);
+ }
+ }
+
QComboBox::hidePopup();
if (!m_popupVisible)
return;
diff --git a/WebCore/platform/qt/RenderThemeQt.cpp b/WebCore/platform/qt/RenderThemeQt.cpp
index eee8c86..942e95b 100644
--- a/WebCore/platform/qt/RenderThemeQt.cpp
+++ b/WebCore/platform/qt/RenderThemeQt.cpp
@@ -796,7 +796,7 @@ private:
HTMLMediaElement* RenderThemeQt::getMediaElementFromRenderObject(RenderObject* o) const
{
- Node* node = o->element();
+ Node* node = o->node();
Node* mediaNode = node ? node->shadowAncestorNode() : 0;
if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
return 0;
@@ -815,7 +815,7 @@ void RenderThemeQt::paintMediaBackground(QPainter* painter, const IntRect& r) co
QColor RenderThemeQt::getMediaControlForegroundColor(RenderObject* o) const
{
QColor fgColor = platformActiveSelectionBackgroundColor();
- if (o && o->element()->active())
+ if (o && o->node()->active())
fgColor = fgColor.lighter();
return fgColor;
}
diff --git a/WebCore/platform/qt/RenderThemeQt.h b/WebCore/platform/qt/RenderThemeQt.h
index 9a6cf0b..b4a5064 100644
--- a/WebCore/platform/qt/RenderThemeQt.h
+++ b/WebCore/platform/qt/RenderThemeQt.h
@@ -1,7 +1,7 @@
/*
* This file is part of the theme implementation for form controls in WebCore.
*
- * Copyright (C) 2007 Trolltech
+ * 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
diff --git a/WebCore/platform/qt/WheelEventQt.cpp b/WebCore/platform/qt/WheelEventQt.cpp
index cc8acd2..9534f20 100644
--- a/WebCore/platform/qt/WheelEventQt.cpp
+++ b/WebCore/platform/qt/WheelEventQt.cpp
@@ -21,7 +21,9 @@
#include "PlatformWheelEvent.h"
#include "PlatformMouseEvent.h"
+#include "Scrollbar.h"
+#include <qapplication.h>
#include <QWheelEvent>
namespace WebCore {
@@ -35,11 +37,7 @@ PlatformWheelEvent::PlatformWheelEvent(QWheelEvent* e)
#else
: m_position(e->pos())
, m_globalPosition(e->globalPos())
-#ifdef QT_MAC_USE_COCOA
, m_granularity(ScrollByPixelWheelEvent)
-#else
- , m_granularity(ScrollByLineWheelEvent)
-#endif
, m_isAccepted(false)
, m_shiftKey(e->modifiers() & Qt::ShiftModifier)
, m_ctrlKey(e->modifiers() & Qt::ControlModifier)
@@ -53,10 +51,14 @@ PlatformWheelEvent::PlatformWheelEvent(QWheelEvent* e)
m_deltaX = 0;
m_deltaY = (e->delta() / 120);
}
+ m_wheelTicksX = m_deltaX;
+ m_wheelTicksY = m_deltaY;
- // FIXME: retrieve the user setting for the number of lines to scroll on each wheel event
- m_deltaX *= horizontalLineMultiplier();
- m_deltaY *= verticalLineMultiplier();
+ // use the same single scroll step as QTextEdit (in
+ // QTextEditPrivate::init [h,v]bar->setSingleStep )
+ static const float cDefaultQtScrollStep = 20.f;
+ m_deltaX *= QApplication::wheelScrollLines() * cDefaultQtScrollStep;
+ m_deltaY *= QApplication::wheelScrollLines() * cDefaultQtScrollStep;
}
#endif // QT_NO_WHEELEVENT
diff --git a/WebCore/platform/text/AtomicString.cpp b/WebCore/platform/text/AtomicString.cpp
index 5f9abfd..d85f5ee 100644
--- a/WebCore/platform/text/AtomicString.cpp
+++ b/WebCore/platform/text/AtomicString.cpp
@@ -101,7 +101,7 @@ static inline bool equal(StringImpl* string, const UChar* characters, unsigned l
if (string->length() != length)
return false;
-#if PLATFORM(ARM)
+#if PLATFORM(ARM) || PLATFORM(SH4)
const UChar* stringCharacters = string->characters();
for (unsigned i = 0; i != length; ++i) {
if (*stringCharacters++ != *characters++)
diff --git a/WebCore/platform/text/Base64.cpp b/WebCore/platform/text/Base64.cpp
index 920fa89..be19164 100644
--- a/WebCore/platform/text/Base64.cpp
+++ b/WebCore/platform/text/Base64.cpp
@@ -97,8 +97,8 @@ void base64Encode(const Vector<char>& in, Vector<char>& out, bool insertLFs)
count += 4;
}
out[didx++] = base64EncMap[(data[sidx] >> 2) & 077];
- out[didx++] = base64EncMap[(data[sidx + 1] >> 4) & 017 | (data[sidx] << 4) & 077];
- out[didx++] = base64EncMap[(data[sidx + 2] >> 6) & 003 | (data[sidx + 1] << 2) & 077];
+ out[didx++] = base64EncMap[((data[sidx + 1] >> 4) & 017) | ((data[sidx] << 4) & 077)];
+ out[didx++] = base64EncMap[((data[sidx + 2] >> 6) & 003) | ((data[sidx + 1] << 2) & 077)];
out[didx++] = base64EncMap[data[sidx + 2] & 077];
sidx += 3;
}
@@ -110,7 +110,7 @@ void base64Encode(const Vector<char>& in, Vector<char>& out, bool insertLFs)
out[didx++] = base64EncMap[(data[sidx] >> 2) & 077];
if (sidx < len - 1) {
- out[didx++] = base64EncMap[(data[sidx + 1] >> 4) & 017 | (data[sidx] << 4) & 077];
+ out[didx++] = base64EncMap[((data[sidx + 1] >> 4) & 017) | ((data[sidx] << 4) & 077)];
out[didx++] = base64EncMap[(data[sidx + 1] << 2) & 077];
} else
out[didx++] = base64EncMap[(data[sidx] << 4) & 077];
diff --git a/WebCore/platform/text/BidiResolver.h b/WebCore/platform/text/BidiResolver.h
index ffd3d51..8288be4 100644
--- a/WebCore/platform/text/BidiResolver.h
+++ b/WebCore/platform/text/BidiResolver.h
@@ -254,7 +254,16 @@ template <class Iterator, class Run>
void BidiResolver<Iterator, Run>::appendRun()
{
if (!emptyRun && !eor.atEnd()) {
- addRun(new Run(sor.offset(), eor.offset() + 1, context(), m_direction));
+ unsigned startOffset = sor.offset();
+ unsigned endOffset = eor.offset();
+
+ if (!endOfLine.atEnd() && endOffset >= endOfLine.offset()) {
+ reachedEndOfLine = true;
+ endOffset = endOfLine.offset();
+ }
+
+ if (endOffset >= startOffset)
+ addRun(new Run(startOffset, endOffset + 1, context(), m_direction));
eor.increment();
sor = eor;
@@ -352,8 +361,8 @@ void BidiResolver<Iterator, Run>::raiseExplicitEmbeddingLevel(WTF::Unicode::Dire
m_direction = LeftToRight;
}
} else if (m_status.eor == ArabicNumber
- || m_status.eor == EuropeanNumber && (m_status.lastStrong != LeftToRight || from == RightToLeft)
- || m_status.eor != EuropeanNumber && m_status.lastStrong == LeftToRight && from == RightToLeft) {
+ || (m_status.eor == EuropeanNumber && (m_status.lastStrong != LeftToRight || from == RightToLeft))
+ || (m_status.eor != EuropeanNumber && m_status.lastStrong == LeftToRight && from == RightToLeft)) {
appendRun();
m_direction = RightToLeft;
}
@@ -722,8 +731,8 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, boo
case WhiteSpaceNeutral:
case OtherNeutral:
if (m_status.eor == ArabicNumber
- || m_status.eor == EuropeanNumber && (m_status.lastStrong == RightToLeft || context()->dir() == RightToLeft)
- || m_status.eor != EuropeanNumber && m_status.lastStrong == LeftToRight && context()->dir() == RightToLeft) {
+ || (m_status.eor == EuropeanNumber && (m_status.lastStrong == RightToLeft || context()->dir() == RightToLeft))
+ || (m_status.eor != EuropeanNumber && m_status.lastStrong == LeftToRight && context()->dir() == RightToLeft)) {
// Terminate the run before the neutrals.
appendRun();
// Begin an R run for the neutrals.
diff --git a/WebCore/platform/text/CString.cpp b/WebCore/platform/text/CString.cpp
index 8e68628..90990f8 100644
--- a/WebCore/platform/text/CString.cpp
+++ b/WebCore/platform/text/CString.cpp
@@ -47,8 +47,8 @@ void CString::init(const char* str, unsigned length)
return;
m_buffer = CStringBuffer::create(length + 1);
- memcpy(m_buffer->data(), str, length);
- m_buffer->data()[length] = '\0';
+ memcpy(m_buffer->mutableData(), str, length);
+ m_buffer->mutableData()[length] = '\0';
}
const char* CString::data() const
@@ -61,7 +61,7 @@ char* CString::mutableData()
copyBufferIfNeeded();
if (!m_buffer)
return 0;
- return m_buffer->data();
+ return m_buffer->mutableData();
}
unsigned CString::length() const
@@ -73,7 +73,7 @@ CString CString::newUninitialized(size_t length, char*& characterBuffer)
{
CString result;
result.m_buffer = CStringBuffer::create(length + 1);
- char* bytes = result.m_buffer->data();
+ char* bytes = result.m_buffer->mutableData();
bytes[length] = '\0';
characterBuffer = bytes;
return result;
@@ -87,7 +87,7 @@ void CString::copyBufferIfNeeded()
int len = m_buffer->length();
RefPtr<CStringBuffer> m_temp = m_buffer;
m_buffer = CStringBuffer::create(len);
- memcpy(m_buffer->data(), m_temp->data(), len);
+ memcpy(m_buffer->mutableData(), m_temp->data(), len);
}
bool operator==(const CString& a, const CString& b)
@@ -99,17 +99,4 @@ bool operator==(const CString& a, const CString& b)
return !strncmp(a.data(), b.data(), min(a.length(), b.length()));
}
-PassRefPtr<SharedBuffer> CString::releaseBuffer()
-{
- if (!m_buffer)
- return 0;
-
- copyBufferIfNeeded();
-
- RefPtr<SharedBuffer> result = m_buffer->releaseBuffer();
- m_buffer = 0;
- return result.release();
-}
-
-
-}
+} // namespace WebCore
diff --git a/WebCore/platform/text/CString.h b/WebCore/platform/text/CString.h
index 09f112f..f084ddf 100644
--- a/WebCore/platform/text/CString.h
+++ b/WebCore/platform/text/CString.h
@@ -36,15 +36,15 @@ namespace WebCore {
class CStringBuffer : public RefCounted<CStringBuffer> {
public:
- static PassRefPtr<CStringBuffer> create(unsigned length) { return adoptRef(new CStringBuffer(length)); }
-
- char* data() { return m_vector.data(); }
- size_t length() const { return m_vector.size(); }
+ const char* data() { return m_vector.data(); }
+ size_t length() { return m_vector.size(); }
- PassRefPtr<SharedBuffer> releaseBuffer() { return SharedBuffer::adoptVector(m_vector); }
-
private:
+ friend class CString;
+
+ static PassRefPtr<CStringBuffer> create(unsigned length) { return adoptRef(new CStringBuffer(length)); }
CStringBuffer(unsigned length) : m_vector(length) { }
+ char* mutableData() { return m_vector.data(); }
Vector<char> m_vector;
};
@@ -56,6 +56,7 @@ namespace WebCore {
CString() { }
CString(const char*);
CString(const char*, unsigned length);
+ CString(CStringBuffer* buffer) : m_buffer(buffer) { }
static CString newUninitialized(size_t length, char*& characterBuffer);
const char* data() const;
@@ -63,8 +64,8 @@ namespace WebCore {
unsigned length() const;
bool isNull() const { return !m_buffer; }
-
- PassRefPtr<SharedBuffer> releaseBuffer();
+
+ CStringBuffer* buffer() const { return m_buffer.get(); }
private:
void copyBufferIfNeeded();
diff --git a/WebCore/platform/text/PlatformString.h b/WebCore/platform/text/PlatformString.h
index 35d3079..a1541d2 100644
--- a/WebCore/platform/text/PlatformString.h
+++ b/WebCore/platform/text/PlatformString.h
@@ -27,15 +27,18 @@
#include "StringImpl.h"
-#include <wtf/PassRefPtr.h>
+#ifdef __OBJC__
+#include <objc/objc.h>
+#endif
#if USE(JSC)
#include <runtime/Identifier.h>
#else
-// runtime/Identifier.h includes HashMap.h and HashSet.h. We explicitly include
-// them in the case of non-JSC builds to keep things consistent.
+// runtime/Identifier.h brings in a variety of wtf headers. We explicitly
+// include them in the case of non-JSC builds to keep things consistent.
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
#endif
#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN))
@@ -228,6 +231,9 @@ public:
static String fromUTF8(const char*, size_t);
static String fromUTF8(const char*);
+ // Tries to convert the passed in string to UTF-8, but will fall back to Latin-1 if the string is not valid UTF-8.
+ static String fromUTF8WithLatin1Fallback(const char*, size_t);
+
// Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3.
WTF::Unicode::Direction defaultWritingDirection() const { return m_impl ? m_impl->defaultWritingDirection() : WTF::Unicode::LeftToRight; }
diff --git a/WebCore/platform/text/String.cpp b/WebCore/platform/text/String.cpp
index 638e45f..733b661 100644
--- a/WebCore/platform/text/String.cpp
+++ b/WebCore/platform/text/String.cpp
@@ -623,6 +623,15 @@ String String::fromUTF8(const char* string)
return UTF8Encoding().decode(string, strlen(string));
}
+String String::fromUTF8WithLatin1Fallback(const char* string, size_t size)
+{
+ String result = fromUTF8(string, size);
+ if (!result)
+ result = String(string, size);
+
+ return result;
+}
+
#if USE(JSC)
String::String(const Identifier& str)
{
diff --git a/WebCore/platform/text/StringImpl.cpp b/WebCore/platform/text/StringImpl.cpp
index 0556f8e..6bba990 100644
--- a/WebCore/platform/text/StringImpl.cpp
+++ b/WebCore/platform/text/StringImpl.cpp
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller ( mueller@kde.org )
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
*
* This library is free software; you can redistribute it and/or
@@ -54,6 +54,27 @@ static inline void deleteUCharVector(const UChar* p)
fastFree(const_cast<UChar*>(p));
}
+// Some of the factory methods create buffers using fastMalloc.
+// We must ensure that ll allocations of StringImpl are allocated using
+// fastMalloc so that we don't have mis-matched frees. We accomplish
+// this by overriding the new and delete operators.
+void* StringImpl::operator new(size_t size, void* address)
+{
+ if (address)
+ return address; // Allocating using an internal buffer
+ return fastMalloc(size);
+}
+
+void* StringImpl::operator new(size_t size)
+{
+ return fastMalloc(size);
+}
+
+void StringImpl::operator delete(void* address)
+{
+ fastFree(address);
+}
+
// This constructor is used only to create the empty string.
StringImpl::StringImpl()
: m_length(0)
@@ -61,6 +82,7 @@ StringImpl::StringImpl()
, m_hash(0)
, m_inTable(false)
, m_hasTerminatingNullCharacter(false)
+ , m_bufferIsInternal(false)
{
// Ensure that the hash is computed so that AtomicStringHash can call existingHash()
// with impunity. The empty string is special because it is never entered into
@@ -76,6 +98,7 @@ inline StringImpl::StringImpl(const UChar* characters, unsigned length)
, m_hash(0)
, m_inTable(false)
, m_hasTerminatingNullCharacter(false)
+ , m_bufferIsInternal(false)
{
UChar* data = newUCharVector(length);
memcpy(data, characters, length * sizeof(UChar));
@@ -87,6 +110,7 @@ inline StringImpl::StringImpl(const StringImpl& str, WithTerminatingNullCharacte
, m_hash(str.m_hash)
, m_inTable(false)
, m_hasTerminatingNullCharacter(true)
+ , m_bufferIsInternal(false)
{
UChar* data = newUCharVector(str.m_length + 1);
memcpy(data, str.m_data, str.m_length * sizeof(UChar));
@@ -99,6 +123,7 @@ inline StringImpl::StringImpl(const char* characters, unsigned length)
, m_hash(0)
, m_inTable(false)
, m_hasTerminatingNullCharacter(false)
+ , m_bufferIsInternal(false)
{
ASSERT(characters);
ASSERT(length);
@@ -117,6 +142,7 @@ inline StringImpl::StringImpl(UChar* characters, unsigned length, AdoptBuffer)
, m_hash(0)
, m_inTable(false)
, m_hasTerminatingNullCharacter(false)
+ , m_bufferIsInternal(false)
{
ASSERT(characters);
ASSERT(length);
@@ -128,6 +154,7 @@ StringImpl::StringImpl(const UChar* characters, unsigned length, unsigned hash)
, m_hash(hash)
, m_inTable(true)
, m_hasTerminatingNullCharacter(false)
+ , m_bufferIsInternal(false)
{
ASSERT(hash);
ASSERT(characters);
@@ -144,6 +171,7 @@ StringImpl::StringImpl(const char* characters, unsigned length, unsigned hash)
, m_hash(hash)
, m_inTable(true)
, m_hasTerminatingNullCharacter(false)
+ , m_bufferIsInternal(false)
{
ASSERT(hash);
ASSERT(characters);
@@ -161,7 +189,8 @@ StringImpl::~StringImpl()
{
if (m_inTable)
AtomicString::remove(this);
- deleteUCharVector(m_data);
+ if (!m_bufferIsInternal)
+ deleteUCharVector(m_data);
}
StringImpl* StringImpl::empty()
@@ -907,26 +936,8 @@ WTF::Unicode::Direction StringImpl::defaultWritingDirection()
}
// This is a hot function because it's used when parsing HTML.
-PassRefPtr<StringImpl> StringImpl::createStrippingNullCharacters(const UChar* characters, unsigned length)
+PassRefPtr<StringImpl> StringImpl::createStrippingNullCharactersSlowCase(const UChar* characters, unsigned length)
{
- ASSERT(characters);
- ASSERT(length);
-
- // Optimize for the case where there are no Null characters by quickly
- // searching for nulls, and then using StringImpl::create, which will
- // memcpy the whole buffer. This is faster than assigning character by
- // character during the loop.
-
- // Fast case.
- int foundNull = 0;
- for (unsigned i = 0; !foundNull && i < length; i++) {
- int c = characters[i]; // more efficient than using UChar here (at least on Intel Mac OS)
- foundNull |= !c;
- }
- if (!foundNull)
- return StringImpl::create(characters, length);
-
- // Slow case.
StringBuffer strippedCopy(length);
unsigned strippedLength = 0;
for (unsigned i = 0; i < length; i++) {
@@ -958,24 +969,44 @@ PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned leng
{
if (!characters || !length)
return empty();
- return adoptRef(new StringImpl(characters, length));
+
+ // Allocate a single buffer large enough to contain the StringImpl
+ // struct as well as the data which it contains. This removes one
+ // heap allocation from this call.
+ size_t size = sizeof(StringImpl) + length * sizeof(UChar);
+ char* buffer = static_cast<char*>(fastMalloc(size));
+ UChar* data = reinterpret_cast<UChar*>(buffer + sizeof(StringImpl));
+ memcpy(data, characters, length * sizeof(UChar));
+ StringImpl* string = new (buffer) StringImpl(data, length, AdoptBuffer());
+ string->m_bufferIsInternal = true;
+ return adoptRef(string);
}
PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned length)
{
if (!characters || !length)
return empty();
- return adoptRef(new StringImpl(characters, length));
+
+ // Allocate a single buffer large enough to contain the StringImpl
+ // struct as well as the data which it contains. This removes one
+ // heap allocation from this call.
+ size_t size = sizeof(StringImpl) + length * sizeof(UChar);
+ char* buffer = static_cast<char*>(fastMalloc(size));
+ UChar* data = reinterpret_cast<UChar*>(buffer + sizeof(StringImpl));
+ for (unsigned i = 0; i != length; ++i) {
+ unsigned char c = characters[i];
+ data[i] = c;
+ }
+ StringImpl* string = new (buffer) StringImpl(data, length, AdoptBuffer());
+ string->m_bufferIsInternal = true;
+ return adoptRef(string);
}
PassRefPtr<StringImpl> StringImpl::create(const char* string)
{
if (!string)
return empty();
- unsigned length = strlen(string);
- if (!length)
- return empty();
- return adoptRef(new StringImpl(string, length));
+ return create(string, strlen(string));
}
PassRefPtr<StringImpl> StringImpl::createWithTerminatingNullCharacter(const StringImpl& string)
@@ -985,7 +1016,7 @@ PassRefPtr<StringImpl> StringImpl::createWithTerminatingNullCharacter(const Stri
PassRefPtr<StringImpl> StringImpl::copy()
{
- return adoptRef(new StringImpl(m_data, m_length));
+ return create(m_data, m_length);
}
} // namespace WebCore
diff --git a/WebCore/platform/text/StringImpl.h b/WebCore/platform/text/StringImpl.h
index 281aa37..1242f27 100644
--- a/WebCore/platform/text/StringImpl.h
+++ b/WebCore/platform/text/StringImpl.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,7 +24,7 @@
#include <limits.h>
#include <wtf/ASCIICType.h>
-#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
#include <wtf/unicode/Unicode.h>
@@ -166,12 +166,25 @@ public:
operator NSString*();
#endif
+ void operator delete(void*);
+
private:
+ // Allocation from a custom buffer is only allowed internally to avoid
+ // mismatched allocators. Callers should use create().
+ void* operator new(size_t size);
+ void* operator new(size_t size, void* address);
+
+ static PassRefPtr<StringImpl> createStrippingNullCharactersSlowCase(const UChar*, unsigned length);
+
unsigned m_length;
const UChar* m_data;
mutable unsigned m_hash;
bool m_inTable;
bool m_hasTerminatingNullCharacter;
+ // In some cases, we allocate the StringImpl struct and its data
+ // within a single heap buffer. In this case, the m_data pointer
+ // is an "internal buffer", and does not need to be deallocated.
+ bool m_bufferIsInternal;
};
bool equal(StringImpl*, StringImpl*);
@@ -274,6 +287,29 @@ static inline bool isSpaceOrNewline(UChar c)
return c <= 0x7F ? WTF::isASCIISpace(c) : WTF::Unicode::direction(c) == WTF::Unicode::WhiteSpaceNeutral;
}
+// This is a hot function because it's used when parsing HTML.
+inline PassRefPtr<StringImpl> StringImpl::createStrippingNullCharacters(const UChar* characters, unsigned length)
+{
+ ASSERT(characters);
+ ASSERT(length);
+
+ // Optimize for the case where there are no Null characters by quickly
+ // searching for nulls, and then using StringImpl::create, which will
+ // memcpy the whole buffer. This is faster than assigning character by
+ // character during the loop.
+
+ // Fast case.
+ int foundNull = 0;
+ for (unsigned i = 0; !foundNull && i < length; i++) {
+ int c = characters[i]; // more efficient than using UChar here (at least on Intel Mac OS)
+ foundNull |= !c;
+ }
+ if (!foundNull)
+ return StringImpl::create(characters, length);
+
+ return StringImpl::createStrippingNullCharactersSlowCase(characters, length);
+}
+
}
namespace WTF {
diff --git a/WebCore/platform/text/TextBreakIterator.h b/WebCore/platform/text/TextBreakIterator.h
index 64717a4..7b3b963 100644
--- a/WebCore/platform/text/TextBreakIterator.h
+++ b/WebCore/platform/text/TextBreakIterator.h
@@ -29,7 +29,19 @@ namespace WebCore {
class TextBreakIterator;
// Note: The returned iterator is good only until you get another iterator.
+
+ // Iterates over "extended grapheme clusters", as defined in UAX #29.
+ // Note that platform implementations may be less sophisticated - e.g. ICU prior to
+ // version 4.0 only supports "legacy grapheme clusters".
+ // Use this for general text processing, e.g. string truncation.
TextBreakIterator* characterBreakIterator(const UChar*, int length);
+
+ // This is similar to character break iterator in most cases, but is subject to
+ // platform UI conventions. One notable example where this can be different
+ // from character break iterator is Thai prepend characters, see bug 24342.
+ // Use this for insertion point and selection manipulations.
+ TextBreakIterator* cursorMovementIterator(const UChar*, int length);
+
TextBreakIterator* wordBreakIterator(const UChar*, int length);
TextBreakIterator* lineBreakIterator(const UChar*, int length);
TextBreakIterator* sentenceBreakIterator(const UChar*, int length);
diff --git a/WebCore/platform/text/TextBreakIteratorICU.cpp b/WebCore/platform/text/TextBreakIteratorICU.cpp
index 9941f58..c4fc1b0 100644
--- a/WebCore/platform/text/TextBreakIteratorICU.cpp
+++ b/WebCore/platform/text/TextBreakIteratorICU.cpp
@@ -22,6 +22,7 @@
#include "config.h"
#include "TextBreakIterator.h"
+#include "PlatformString.h"
#include "TextBreakIteratorInternalICU.h"
#include <unicode/ubrk.h>
@@ -114,4 +115,119 @@ bool isTextBreak(TextBreakIterator* bi, int pos)
return ubrk_isBoundary(bi, pos);
}
+#ifndef BUILDING_ON_TIGER
+static TextBreakIterator* setUpIteratorWithRules(bool& createdIterator, TextBreakIterator*& iterator,
+ const char* breakRules, const UChar* string, int length)
+{
+ if (!string)
+ return 0;
+
+ if (!createdIterator) {
+ UParseError parseStatus;
+ UErrorCode openStatus = U_ZERO_ERROR;
+ String rules(breakRules);
+ iterator = static_cast<TextBreakIterator*>(ubrk_openRules(rules.characters(), rules.length(), 0, 0, &parseStatus, &openStatus));
+ createdIterator = true;
+ ASSERT_WITH_MESSAGE(U_SUCCESS(openStatus), "ICU could not open a break iterator: %s (%d)", u_errorName(openStatus), openStatus);
+ }
+ if (!iterator)
+ return 0;
+
+ UErrorCode setTextStatus = U_ZERO_ERROR;
+ ubrk_setText(iterator, string, length, &setTextStatus);
+ if (U_FAILURE(setTextStatus))
+ return 0;
+
+ return iterator;
+}
+#endif // BUILDING_ON_TIGER
+
+TextBreakIterator* cursorMovementIterator(const UChar* string, int length)
+{
+#ifdef BUILDING_ON_TIGER
+ // ICU 3.2 cannot compile the below rules.
+ return characterBreakIterator(string, length);
+#else
+ // This rule set is based on character-break iterator rules of ICU 4.0
+ // <http://source.icu-project.org/repos/icu/icu/tags/release-4-0/source/data/brkitr/char.txt>.
+ // The major differences from the original ones are listed below:
+ // * Replaced '[\p{Grapheme_Cluster_Break = SpacingMark}]' with '[\p{General_Category = Spacing Mark} - $Extend]' for ICU 3.8 or earlier;
+ // * Removed rules that prevent a cursor from moving after prepend characters (Bug 24342);
+ // * Added rules that prevent a cursor from moving after virama signs of Indic languages except Tamil (Bug 15790), and;
+ // * Added rules that prevent a cursor from moving before Japanese half-width katakara voiced marks.
+ static const char* kRules =
+ "$CR = [\\p{Grapheme_Cluster_Break = CR}];"
+ "$LF = [\\p{Grapheme_Cluster_Break = LF}];"
+ "$Control = [\\p{Grapheme_Cluster_Break = Control}];"
+ "$VoiceMarks = [\\uFF9E\\uFF9F];" // Japanese half-width katakana voiced marks
+ "$Extend = [\\p{Grapheme_Cluster_Break = Extend} $VoiceMarks];"
+ "$SpacingMark = [[\\p{General_Category = Spacing Mark}] - $Extend];"
+ "$L = [\\p{Grapheme_Cluster_Break = L}];"
+ "$V = [\\p{Grapheme_Cluster_Break = V}];"
+ "$T = [\\p{Grapheme_Cluster_Break = T}];"
+ "$LV = [\\p{Grapheme_Cluster_Break = LV}];"
+ "$LVT = [\\p{Grapheme_Cluster_Break = LVT}];"
+ "$Hin0 = [\\u0905-\\u0939];" // Devanagari Letter A,...,Ha
+ "$HinV = \\u094D;" // Devanagari Sign Virama
+ "$Hin1 = [\\u0915-\\u0939];" // Devanagari Letter Ka,...,Ha
+ "$Ben0 = [\\u0985-\\u09B9];" // Bengali Letter A,...,Ha
+ "$BenV = \\u09CD;" // Bengali Sign Virama
+ "$Ben1 = [\\u0995-\\u09B9];" // Bengali Letter Ka,...,Ha
+ "$Pan0 = [\\u0A05-\\u0A39];" // Gurmukhi Letter A,...,Ha
+ "$PanV = \\u0A4D;" // Gurmukhi Sign Virama
+ "$Pan1 = [\\u0A15-\\u0A39];" // Gurmukhi Letter Ka,...,Ha
+ "$Guj0 = [\\u0A85-\\u0AB9];" // Gujarati Letter A,...,Ha
+ "$GujV = \\u0ACD;" // Gujarati Sign Virama
+ "$Guj1 = [\\u0A95-\\u0AB9];" // Gujarati Letter Ka,...,Ha
+ "$Ori0 = [\\u0B05-\\u0B39];" // Oriya Letter A,...,Ha
+ "$OriV = \\u0B4D;" // Oriya Sign Virama
+ "$Ori1 = [\\u0B15-\\u0B39];" // Oriya Letter Ka,...,Ha
+ "$Tel0 = [\\u0C05-\\u0C39];" // Telugu Letter A,...,Ha
+ "$TelV = \\u0C4D;" // Telugu Sign Virama
+ "$Tel1 = [\\u0C14-\\u0C39];" // Telugu Letter Ka,...,Ha
+ "$Kan0 = [\\u0C85-\\u0CB9];" // Kannada Letter A,...,Ha
+ "$KanV = \\u0CCD;" // Kannada Sign Virama
+ "$Kan1 = [\\u0C95-\\u0CB9];" // Kannada Letter A,...,Ha
+ "$Mal0 = [\\u0D05-\\u0D39];" // Malayalam Letter A,...,Ha
+ "$MalV = \\u0D4D;" // Malayalam Sign Virama
+ "$Mal1 = [\\u0D15-\\u0D39];" // Malayalam Letter A,...,Ha
+ "!!chain;"
+ "!!forward;"
+ "$CR $LF;"
+ "$L ($L | $V | $LV | $LVT);"
+ "($LV | $V) ($V | $T);"
+ "($LVT | $T) $T;"
+ "[^$Control $CR $LF] $Extend;"
+ "[^$Control $CR $LF] $SpacingMark;"
+ "$Hin0 $HinV $Hin1;" // Devanagari Virama (forward)
+ "$Ben0 $BenV $Ben1;" // Bengali Virama (forward)
+ "$Pan0 $PanV $Pan1;" // Gurmukhi Virama (forward)
+ "$Guj0 $GujV $Guj1;" // Gujarati Virama (forward)
+ "$Ori0 $OriV $Ori1;" // Oriya Virama (forward)
+ "$Tel0 $TelV $Tel1;" // Telugu Virama (forward)
+ "$Kan0 $KanV $Kan1;" // Kannada Virama (forward)
+ "$Mal0 $MalV $Mal1;" // Malayalam Virama (forward)
+ "!!reverse;"
+ "$LF $CR;"
+ "($L | $V | $LV | $LVT) $L;"
+ "($V | $T) ($LV | $V);"
+ "$T ($LVT | $T);"
+ "$Extend [^$Control $CR $LF];"
+ "$SpacingMark [^$Control $CR $LF];"
+ "$Hin1 $HinV $Hin0;" // Devanagari Virama (backward)
+ "$Ben1 $BenV $Ben0;" // Bengali Virama (backward)
+ "$Pan1 $PanV $Pan0;" // Gurmukhi Virama (backward)
+ "$Guj1 $GujV $Guj0;" // Gujarati Virama (backward)
+ "$Ori1 $OriV $Ori0;" // Gujarati Virama (backward)
+ "$Tel1 $TelV $Tel0;" // Telugu Virama (backward)
+ "$Kan1 $KanV $Kan0;" // Kannada Virama (backward)
+ "$Mal1 $MalV $Mal0;" // Malayalam Virama (backward)
+ "!!safe_reverse;"
+ "!!safe_forward;";
+ static bool createdCursorMovementIterator = false;
+ static TextBreakIterator* staticCursorMovementIterator;
+ return setUpIteratorWithRules(createdCursorMovementIterator, staticCursorMovementIterator, kRules, string, length);
+#endif // BUILDING_ON_TIGER
+}
+
}
diff --git a/WebCore/platform/text/TextCodecICU.cpp b/WebCore/platform/text/TextCodecICU.cpp
index 72d45ad..72054fa 100644
--- a/WebCore/platform/text/TextCodecICU.cpp
+++ b/WebCore/platform/text/TextCodecICU.cpp
@@ -334,7 +334,7 @@ String TextCodecICU::decode(const char* bytes, size_t length, bool flush, bool s
// <http://bugs.webkit.org/show_bug.cgi?id=17014>
// Simplified Chinese pages use the code A3A0 to mean "full-width space", but ICU decodes it as U+E5E5.
- if (m_encoding == "GBK" || m_encoding == "gb18030")
+ if (strcmp(m_encoding.name(), "GBK") == 0 || strcasecmp(m_encoding.name(), "gb18030") == 0)
resultString.replace(0xE5E5, ideographicSpace);
return resultString;
diff --git a/WebCore/platform/text/TextDecoder.cpp b/WebCore/platform/text/TextDecoder.cpp
deleted file mode 100644
index e39a6b7..0000000
--- a/WebCore/platform/text/TextDecoder.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "TextDecoder.h"
-
-#include "TextEncodingRegistry.h"
-
-// FIXME: Would be nice to also handle BOM for UTF-7 and UTF-32.
-
-namespace WebCore {
-
-TextDecoder::TextDecoder(const TextEncoding& encoding)
- : m_encoding(encoding)
- , m_checkedForBOM(false)
- , m_numBufferedBytes(0)
-{
-}
-
-void TextDecoder::reset(const TextEncoding& encoding)
-{
- m_encoding = encoding;
- m_codec.clear();
- m_checkedForBOM = false;
- m_numBufferedBytes = 0;
-}
-
-String TextDecoder::checkForBOM(const char* data, size_t length, bool flush, bool stopOnError, bool& sawError)
-{
- ASSERT(!m_checkedForBOM);
-
- // Check to see if we found a BOM.
- size_t numBufferedBytes = m_numBufferedBytes;
- size_t buf1Len = numBufferedBytes;
- size_t buf2Len = length;
- const unsigned char* buf1 = m_bufferedBytes;
- const unsigned char* buf2 = reinterpret_cast<const unsigned char*>(data);
- unsigned char c1 = buf1Len ? (--buf1Len, *buf1++) : buf2Len ? (--buf2Len, *buf2++) : 0;
- unsigned char c2 = buf1Len ? (--buf1Len, *buf1++) : buf2Len ? (--buf2Len, *buf2++) : 0;
- unsigned char c3 = buf1Len ? (--buf1Len, *buf1++) : buf2Len ? (--buf2Len, *buf2++) : 0;
- unsigned char c4 = buf2Len ? (--buf2Len, *buf2++) : 0;
-
- const TextEncoding* encodingConsideringBOM = &m_encoding;
- bool foundBOM = true;
- size_t lengthOfBOM = 0;
- if (c1 == 0xFF && c2 == 0xFE) {
- if (c3 != 0 || c4 != 0) {
- encodingConsideringBOM = &UTF16LittleEndianEncoding();
- lengthOfBOM = 2;
- } else if (numBufferedBytes + length > sizeof(m_bufferedBytes)) {
- encodingConsideringBOM = &UTF32LittleEndianEncoding();
- lengthOfBOM = 4;
- } else
- foundBOM = false;
- } else if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) {
- encodingConsideringBOM = &UTF8Encoding();
- lengthOfBOM = 3;
- } else if (c1 == 0xFE && c2 == 0xFF) {
- encodingConsideringBOM = &UTF16BigEndianEncoding();
- lengthOfBOM = 2;
- } else if (c1 == 0 && c2 == 0 && c3 == 0xFE && c4 == 0xFF) {
- encodingConsideringBOM = &UTF32BigEndianEncoding();
- lengthOfBOM = 4;
- } else
- foundBOM = false;
-
- if (!foundBOM && numBufferedBytes + length <= sizeof(m_bufferedBytes) && !flush) {
- // Continue to look for the BOM.
- memcpy(&m_bufferedBytes[numBufferedBytes], data, length);
- m_numBufferedBytes += length;
- return "";
- }
-
- // Done checking for BOM.
- m_codec.set(newTextCodec(*encodingConsideringBOM).release());
- if (!m_codec)
- return String();
- m_checkedForBOM = true;
-
- // Skip the BOM.
- if (foundBOM) {
- ASSERT(numBufferedBytes < lengthOfBOM);
- size_t numUnbufferedBOMBytes = lengthOfBOM - numBufferedBytes;
- ASSERT(numUnbufferedBOMBytes <= length);
-
- data += numUnbufferedBOMBytes;
- length -= numUnbufferedBOMBytes;
- numBufferedBytes = 0;
- m_numBufferedBytes = 0;
- }
-
- // Handle case where we have some buffered bytes to deal with.
- if (numBufferedBytes) {
- char bufferedBytes[sizeof(m_bufferedBytes)];
- memcpy(bufferedBytes, m_bufferedBytes, numBufferedBytes);
- m_numBufferedBytes = 0;
-
- String bufferedResult = m_codec->decode(bufferedBytes, numBufferedBytes, false, stopOnError, sawError);
- if (stopOnError && sawError)
- return bufferedResult;
- return bufferedResult + m_codec->decode(data, length, flush, stopOnError, sawError);
- }
-
- return m_codec->decode(data, length, flush, stopOnError, sawError);
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/text/TextEncoding.cpp b/WebCore/platform/text/TextEncoding.cpp
index 063d96b..ed58412 100644
--- a/WebCore/platform/text/TextEncoding.cpp
+++ b/WebCore/platform/text/TextEncoding.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,6 @@
#include "CString.h"
#include "PlatformString.h"
#include "TextCodec.h"
-#include "TextDecoder.h"
#include "TextEncodingRegistry.h"
#if USE(ICU_UNICODE)
#include <unicode/unorm.h>
@@ -73,7 +72,7 @@ String TextEncoding::decode(const char* data, size_t length, bool stopOnError, b
if (!m_name)
return String();
- return TextDecoder(*this).decode(data, length, true, stopOnError, sawError);
+ return newTextCodec(*this)->decode(data, length, true, stopOnError, sawError);
}
CString TextEncoding::encode(const UChar* characters, size_t length, UnencodableHandling handling) const
@@ -165,10 +164,23 @@ UChar TextEncoding::backslashAsCurrencySymbol() const
bool TextEncoding::isNonByteBasedEncoding() const
{
+ if (noExtendedTextEncodingNameUsed()) {
+ return *this == UTF16LittleEndianEncoding()
+ || *this == UTF16BigEndianEncoding();
+ }
+
return *this == UTF16LittleEndianEncoding()
- || *this == UTF16BigEndianEncoding()
- || *this == UTF32BigEndianEncoding()
- || *this == UTF32LittleEndianEncoding();
+ || *this == UTF16BigEndianEncoding()
+ || *this == UTF32BigEndianEncoding()
+ || *this == UTF32LittleEndianEncoding();
+}
+
+bool TextEncoding::isUTF7Encoding() const
+{
+ if (noExtendedTextEncodingNameUsed())
+ return false;
+
+ return *this == UTF7Encoding();
}
const TextEncoding& TextEncoding::closestByteBasedEquivalent() const
@@ -185,7 +197,7 @@ const TextEncoding& TextEncoding::closestByteBasedEquivalent() const
// but it's fraught with problems and we'd rather steer clear of it.
const TextEncoding& TextEncoding::encodingForFormSubmission() const
{
- if (isNonByteBasedEncoding() || *this == UTF7Encoding())
+ if (isNonByteBasedEncoding() || isUTF7Encoding())
return UTF8Encoding();
return *this;
}
diff --git a/WebCore/platform/text/TextEncoding.h b/WebCore/platform/text/TextEncoding.h
index b2bb816..b3909f7 100644
--- a/WebCore/platform/text/TextEncoding.h
+++ b/WebCore/platform/text/TextEncoding.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -45,12 +45,14 @@ namespace WebCore {
bool usesVisualOrdering() const;
bool isJapanese() const;
- PassRefPtr<StringImpl> displayString(PassRefPtr<StringImpl> str) const {
+ PassRefPtr<StringImpl> displayString(PassRefPtr<StringImpl> str) const
+ {
if (m_backslashAsCurrencySymbol == '\\' || !str)
return str;
return str->replace('\\', m_backslashAsCurrencySymbol);
}
- void displayBuffer(UChar* characters, unsigned len) const {
+ void displayBuffer(UChar* characters, unsigned len) const
+ {
if (m_backslashAsCurrencySymbol == '\\')
return;
for (unsigned i = 0; i < len; ++i) {
@@ -72,10 +74,11 @@ namespace WebCore {
private:
UChar backslashAsCurrencySymbol() const;
+ bool isNonByteBasedEncoding() const;
+ bool isUTF7Encoding() const;
const char* m_name;
UChar m_backslashAsCurrencySymbol;
- bool isNonByteBasedEncoding() const;
};
inline bool operator==(const TextEncoding& a, const TextEncoding& b) { return a.name() == b.name(); }
diff --git a/WebCore/platform/text/TextEncodingDetector.h b/WebCore/platform/text/TextEncodingDetector.h
new file mode 100644
index 0000000..9f16ab0
--- /dev/null
+++ b/WebCore/platform/text/TextEncodingDetector.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TextEncodingDetector_h
+#define TextEncodingDetector_h
+
+namespace WebCore {
+
+ class TextEncoding;
+
+ // Given a sequence of bytes in |data| of length |len| and an optional
+ // hintEncodingName, detect the most likely character encoding.
+ // The way hintEncodingName is used is up to an implementation.
+ // Currently, the only caller sets it to the parent frame encoding.
+ bool detectTextEncoding(const char* data, size_t len,
+ const char* hintEncodingName,
+ TextEncoding* detectedEncoding);
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/text/TextEncodingDetectorICU.cpp b/WebCore/platform/text/TextEncodingDetectorICU.cpp
new file mode 100644
index 0000000..26c997e
--- /dev/null
+++ b/WebCore/platform/text/TextEncodingDetectorICU.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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 "TextEncodingDetector.h"
+
+#include "TextEncoding.h"
+#include "UnusedParam.h"
+
+#ifndef BUILDING_ON_TIGER
+#include "unicode/ucnv.h"
+#include "unicode/ucsdet.h"
+#endif
+
+namespace WebCore {
+
+bool detectTextEncoding(const char* data, size_t len,
+ const char* hintEncodingName,
+ TextEncoding* detectedEncoding)
+{
+ *detectedEncoding = TextEncoding();
+#ifdef BUILDING_ON_TIGER
+ // Tiger came with ICU 3.2 and does not have the encoding detector.
+ UNUSED_PARAM(data);
+ UNUSED_PARAM(len);
+ UNUSED_PARAM(hintEncodingName);
+ return false;
+#else
+ int matchesCount = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ UCharsetDetector* detector = ucsdet_open(&status);
+ if (U_FAILURE(status))
+ return false;
+ ucsdet_enableInputFilter(detector, true);
+ ucsdet_setText(detector, data, static_cast<int32_t>(len), &status);
+ if (U_FAILURE(status))
+ return false;
+
+ // FIXME: A few things we can do other than improving
+ // the ICU detector itself.
+ // 1. Use ucsdet_detectAll and pick the most likely one given
+ // "the context" (parent-encoding, referrer encoding, etc).
+ // 2. 'Emulate' Firefox/IE's non-Universal detectors (e.g.
+ // Chinese, Japanese, Russian, Korean and Hebrew) by picking the
+ // encoding with a highest confidence among the detetctor-specific
+ // limited set of candidate encodings.
+ // Below is a partial implementation of the first part of what's outlined
+ // above.
+ const UCharsetMatch** matches = ucsdet_detectAll(detector, &matchesCount, &status);
+ if (U_FAILURE(status)) {
+ ucsdet_close(detector);
+ return false;
+ }
+
+ const char* encoding = 0;
+ if (hintEncodingName) {
+ TextEncoding hintEncoding(hintEncodingName);
+ // 10 is the minimum confidence value consistent with the codepoint
+ // allocation in a given encoding. The size of a chunk passed to
+ // us varies even for the same html file (apparently depending on
+ // the network load). When we're given a rather short chunk, we
+ // don't have a sufficiently reliable signal other than the fact that
+ // the chunk is consistent with a set of encodings. So, instead of
+ // setting an arbitrary threshold, we have to scan all the encodings
+ // consistent with the data.
+ const int32_t kThresold = 10;
+ for (int i = 0; i < matchesCount; ++i) {
+ int32_t confidence = ucsdet_getConfidence(matches[i], &status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ if (confidence < kThresold)
+ break;
+ const char* matchEncoding = ucsdet_getName(matches[i], &status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ if (TextEncoding(matchEncoding) == hintEncoding) {
+ encoding = hintEncodingName;
+ break;
+ }
+ }
+ }
+ // If no match is found so far, just pick the top match.
+ // This can happen, say, when a parent frame in EUC-JP refers to
+ // a child frame in Shift_JIS and both frames do NOT specify the encoding
+ // making us resort to auto-detection (when it IS turned on).
+ if (!encoding && matchesCount > 0)
+ encoding = ucsdet_getName(matches[0], &status);
+ if (U_SUCCESS(status)) {
+ *detectedEncoding = TextEncoding(encoding);
+ ucsdet_close(detector);
+ return true;
+ }
+ ucsdet_close(detector);
+ return false;
+#endif
+}
+
+}
diff --git a/WebCore/platform/text/TextEncodingDetectorNone.cpp b/WebCore/platform/text/TextEncodingDetectorNone.cpp
new file mode 100644
index 0000000..2655f08
--- /dev/null
+++ b/WebCore/platform/text/TextEncodingDetectorNone.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextEncodingDetector.h"
+
+#include "TextEncoding.h"
+#include "UnusedParam.h"
+
+namespace WebCore {
+
+bool detectTextEncoding(const char* data, size_t len,
+ const char* hintEncodingName,
+ TextEncoding* detectedEncoding)
+{
+ UNUSED_PARAM(data)
+ UNUSED_PARAM(len)
+ UNUSED_PARAM(hintEncodingName)
+
+ *detectedEncoding = TextEncoding();
+ return false;
+}
+
+}
diff --git a/WebCore/platform/text/TextEncodingRegistry.h b/WebCore/platform/text/TextEncodingRegistry.h
index 5ca2039..d204734 100644
--- a/WebCore/platform/text/TextEncodingRegistry.h
+++ b/WebCore/platform/text/TextEncodingRegistry.h
@@ -34,11 +34,8 @@ namespace WebCore {
class TextCodec;
class TextEncoding;
- // Only TextEncoding and TextDecoder should use this function directly.
- // - Use TextDecoder::decode to decode, since it handles BOMs.
- // - Use TextEncoding::decode to decode if you have all the data at once.
- // It's implemented by calling TextDecoder::decode so works just as well.
- // - Use TextEncoding::encode to encode, since it takes care of normalization.
+ // Use TextResourceDecoder::decode to decode resources, since it handles BOMs.
+ // Use TextEncoding::encode to encode, since it takes care of normalization.
std::auto_ptr<TextCodec> newTextCodec(const TextEncoding&);
// Only TextEncoding should use this function directly.
diff --git a/WebCore/platform/android/TextBreakIteratorInternalICU.cpp b/WebCore/platform/text/android/TextBreakIteratorInternalICU.cpp
index 9bebe74..9bebe74 100644
--- a/WebCore/platform/android/TextBreakIteratorInternalICU.cpp
+++ b/WebCore/platform/text/android/TextBreakIteratorInternalICU.cpp
diff --git a/WebCore/platform/text/cf/StringImplCF.cpp b/WebCore/platform/text/cf/StringImplCF.cpp
index ff595a5..8a2ae79 100644
--- a/WebCore/platform/text/cf/StringImplCF.cpp
+++ b/WebCore/platform/text/cf/StringImplCF.cpp
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2006 Apple Computer, Inc.
+/*
+ * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,14 +24,139 @@
#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN))
#include <CoreFoundation/CoreFoundation.h>
+#include <wtf/MainThread.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER)
+#include <objc/objc-auto.h>
+#endif
namespace WebCore {
+namespace StringWrapperCFAllocator {
+
+ static StringImpl* currentString;
+
+ static const void* retain(const void* info)
+ {
+ return info;
+ }
+
+ static void release(const void*)
+ {
+ ASSERT_NOT_REACHED();
+ }
+
+ static CFStringRef copyDescription(const void*)
+ {
+ return CFSTR("WebCore::String-based allocator");
+ }
+
+ static void* allocate(CFIndex size, CFOptionFlags, void*)
+ {
+ StringImpl* underlyingString = 0;
+ if (isMainThread()) {
+ underlyingString = currentString;
+ if (underlyingString) {
+ currentString = 0;
+ underlyingString->ref(); // Balanced by call to deref in deallocate below.
+ }
+ }
+ StringImpl** header = static_cast<StringImpl**>(fastMalloc(sizeof(StringImpl*) + size));
+ *header = underlyingString;
+ return header + 1;
+ }
+
+ static void* reallocate(void* pointer, CFIndex newSize, CFOptionFlags, void*)
+ {
+ size_t newAllocationSize = sizeof(StringImpl*) + newSize;
+ StringImpl** header = static_cast<StringImpl**>(pointer) - 1;
+ ASSERT(!*header);
+ header = static_cast<StringImpl**>(fastRealloc(header, newAllocationSize));
+ return header + 1;
+ }
+
+ static void deallocateOnMainThread(void* headerPointer)
+ {
+ StringImpl** header = static_cast<StringImpl**>(headerPointer);
+ StringImpl* underlyingString = *header;
+ ASSERT(underlyingString);
+ underlyingString->deref(); // Balanced by call to ref in allocate above.
+ fastFree(header);
+ }
+
+ static void deallocate(void* pointer, void*)
+ {
+ StringImpl** header = static_cast<StringImpl**>(pointer) - 1;
+ StringImpl* underlyingString = *header;
+ if (!underlyingString)
+ fastFree(header);
+ else {
+ if (!isMainThread())
+ callOnMainThread(deallocateOnMainThread, header);
+ else {
+ underlyingString->deref(); // Balanced by call to ref in allocate above.
+ fastFree(header);
+ }
+ }
+ }
+
+ static CFIndex preferredSize(CFIndex size, CFOptionFlags, void*)
+ {
+ // FIXME: If FastMalloc provided a "good size" callback, we'd want to use it here.
+ // Note that this optimization would help performance for strings created with the
+ // allocator that are mutable, and those typically are only created by callers who
+ // make a new string using the old string's allocator, such as some of the call
+ // sites in CFURL.
+ return size;
+ }
+
+ static CFAllocatorRef create()
+ {
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER)
+ // Since garbage collection isn't compatible with custom allocators, don't use this at all when garbage collection is active.
+ if (objc_collectingEnabled())
+ return 0;
+#endif
+ CFAllocatorContext context = { 0, 0, retain, release, copyDescription, allocate, reallocate, deallocate, preferredSize };
+ return CFAllocatorCreate(0, &context);
+ }
+
+ static CFAllocatorRef allocator()
+ {
+ static CFAllocatorRef allocator = create();
+ return allocator;
+ }
+
+}
+
CFStringRef StringImpl::createCFString()
{
- return CFStringCreateWithCharacters(NULL, reinterpret_cast<const UniChar*>(m_data), m_length);
+ CFAllocatorRef allocator = (m_length && isMainThread()) ? StringWrapperCFAllocator::allocator() : 0;
+ if (!allocator)
+ return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(m_data), m_length);
+
+ // Put pointer to the StringImpl in a global so the allocator can store it with the CFString.
+ ASSERT(!StringWrapperCFAllocator::currentString);
+ StringWrapperCFAllocator::currentString = this;
+
+ CFStringRef string = CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast<const UniChar*>(m_data), m_length, kCFAllocatorNull);
+
+ // The allocator cleared the global when it read it, but also clear it here just in case.
+ ASSERT(!StringWrapperCFAllocator::currentString);
+ StringWrapperCFAllocator::currentString = 0;
+
+ return string;
}
+// On StringImpl creation we could check if the allocator is the StringWrapperCFAllocator.
+// If it is, then we could find the original StringImpl and just return that. But to
+// do that we'd have to compute the offset from CFStringRef to the allocated block;
+// the CFStringRef is *not* at the start of an allocated block. Testing shows 1000x
+// more calls to createCFString than calls to the create functions with the appropriate
+// allocator, so it's probably not urgent optimize that case.
+
}
#endif // PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN))
diff --git a/WebCore/platform/text/mac/ShapeArabic.c b/WebCore/platform/text/mac/ShapeArabic.c
index 1e0d91b..dd61ce5 100644
--- a/WebCore/platform/text/mac/ShapeArabic.c
+++ b/WebCore/platform/text/mac/ShapeArabic.c
@@ -36,6 +36,8 @@
#include "ShapeArabic.h"
+#include <stdbool.h>
+#include <string.h>
#include <unicode/utypes.h>
#include <unicode/uchar.h>
#include <unicode/ustring.h>
diff --git a/WebCore/platform/text/mac/StringImplMac.mm b/WebCore/platform/text/mac/StringImplMac.mm
index 3e0731c..d14c6d8 100644
--- a/WebCore/platform/text/mac/StringImplMac.mm
+++ b/WebCore/platform/text/mac/StringImplMac.mm
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2006 Apple Computer, Inc.
+/*
+ * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,13 +21,13 @@
#include "config.h"
#include "StringImpl.h"
-#include <Foundation/Foundation.h>
+#include "FoundationExtras.h"
namespace WebCore {
StringImpl::operator NSString *()
{
- return [NSString stringWithCharacters:m_data length:m_length];
+ return HardAutorelease(createCFString());
}
}
diff --git a/WebCore/platform/text/mac/StringMac.mm b/WebCore/platform/text/mac/StringMac.mm
index 77942ea..758ae1d 100644
--- a/WebCore/platform/text/mac/StringMac.mm
+++ b/WebCore/platform/text/mac/StringMac.mm
@@ -20,6 +20,7 @@
#include "config.h"
#include "PlatformString.h"
+#include <CoreFoundation/CFString.h>
namespace WebCore {
diff --git a/WebCore/platform/text/qt/TextBreakIteratorQt.cpp b/WebCore/platform/text/qt/TextBreakIteratorQt.cpp
index 88b9680..4dc23ee 100644
--- a/WebCore/platform/text/qt/TextBreakIteratorQt.cpp
+++ b/WebCore/platform/text/qt/TextBreakIteratorQt.cpp
@@ -63,6 +63,11 @@ namespace WebCore {
return static_cast<TextBreakIterator*>(iterator);
}
+ TextBreakIterator* cursorMovementIterator(const UChar* string, int length)
+ {
+ return characterBreakIterator(string, length);
+ }
+
TextBreakIterator* lineBreakIterator(const UChar* string, int length)
{
static QTextBoundaryFinder *iterator = 0;
@@ -250,6 +255,11 @@ TextBreakIterator* characterBreakIterator(const UChar* string, int length)
return iterator;
}
+TextBreakIterator* cursorMovementIterator(const UChar* string, int length)
+{
+ return characterBreakIterator(string, length);
+}
+
TextBreakIterator* lineBreakIterator(const UChar*, int)
{
// not yet implemented
diff --git a/WebCore/platform/win/FileSystemWin.cpp b/WebCore/platform/win/FileSystemWin.cpp
index 5671462..746fceb 100644
--- a/WebCore/platform/win/FileSystemWin.cpp
+++ b/WebCore/platform/win/FileSystemWin.cpp
@@ -191,11 +191,11 @@ CString openTemporaryFile(const char*, PlatformFileHandle& handle)
char tempPath[MAX_PATH];
int tempPathLength = ::GetTempPathA(_countof(tempPath), tempPath);
if (tempPathLength <= 0 || tempPathLength > _countof(tempPath))
- return 0;
+ return CString();
HCRYPTPROV hCryptProv = 0;
if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
- return 0;
+ return CString();
char proposedPath[MAX_PATH];
while (1) {
@@ -226,7 +226,7 @@ CString openTemporaryFile(const char*, PlatformFileHandle& handle)
CryptReleaseContext(hCryptProv, 0);
if (!isHandleValid(handle))
- return 0;
+ return CString();
return proposedPath;
}
diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp
index 59ea563..52f2eb9 100644
--- a/WebCore/platform/win/PopupMenuWin.cpp
+++ b/WebCore/platform/win/PopupMenuWin.cpp
@@ -527,6 +527,8 @@ void PopupMenu::paint(const IntRect& damageRect, HDC hdc)
// Draw the item text
if (itemStyle.isVisible()) {
int textX = max(0, client()->clientPaddingLeft() - client()->clientInsetLeft());
+ if (theme()->popupOptionSupportsTextIndent() && itemStyle.textDirection() == LTR)
+ textX += itemStyle.textIndent().calcMinValue(itemRect.width());
int textY = itemRect.y() + itemFont.ascent() + (itemRect.height() - itemFont.height()) / 2;
context.drawBidiText(itemFont, textRun, IntPoint(textX, textY));
}
@@ -683,6 +685,9 @@ static LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT message, WPARAM wParam, LPA
::SendMessage(popup->client()->hostWindow()->platformWindow(), message, wParam, lParam);
popup->client()->hidePopup();
break;
+ case VK_ESCAPE:
+ popup->client()->hidePopup();
+ break;
default:
if (isASCIIPrintable(wParam))
// Send the keydown to the WebView so it can be used for type-to-select.
diff --git a/WebCore/platform/win/WheelEventWin.cpp b/WebCore/platform/win/WheelEventWin.cpp
index d272ba7..e6670a4 100644
--- a/WebCore/platform/win/WheelEventWin.cpp
+++ b/WebCore/platform/win/WheelEventWin.cpp
@@ -46,23 +46,23 @@ static IntPoint globalPositionForEvent(HWND hWnd, LPARAM lParam)
return point;
}
-int PlatformWheelEvent::horizontalLineMultiplier() const
+static int horizontalScrollChars()
{
static ULONG scrollChars;
if (!scrollChars && !SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0))
- scrollChars = cLineMultiplier;
+ scrollChars = 1;
return scrollChars;
}
-int PlatformWheelEvent::verticalLineMultiplier() const
+static int verticalScrollLines()
{
static ULONG scrollLines;
if (!scrollLines && !SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0))
- scrollLines = cLineMultiplier;
+ scrollLines = 3;
return scrollLines;
}
-
-PlatformWheelEvent::PlatformWheelEvent(HWND hWnd, WPARAM wParam, LPARAM lParam, bool isHorizontal)
+
+PlatformWheelEvent::PlatformWheelEvent(HWND hWnd, WPARAM wParam, LPARAM lParam, bool isMouseHWheel)
: m_position(positionForEvent(hWnd, lParam))
, m_globalPosition(globalPositionForEvent(hWnd, lParam))
, m_isAccepted(false)
@@ -71,23 +71,40 @@ PlatformWheelEvent::PlatformWheelEvent(HWND hWnd, WPARAM wParam, LPARAM lParam,
, m_altKey(GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
, m_metaKey(m_altKey) // FIXME: We'll have to test other browsers
{
- static ULONG scrollLines, scrollChars;
- float delta = GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
- if (isHorizontal) {
- // Windows sends a positive delta for scrolling right, while AppKit
- // sends a negative delta. EventHandler expects the AppKit values,
- // so we have to negate our horizontal delta to match.
- m_deltaX = -delta * horizontalLineMultiplier();
+ // How many pixels should we scroll per line? Gecko uses the height of the
+ // current line, which means scroll distance changes as you go through the
+ // page or go to different pages. IE 7 is ~50 px/line, although the value
+ // seems to vary slightly by page and zoom level. Since IE 7 has a
+ // smoothing algorithm on scrolling, it can get away with slightly larger
+ // scroll values without feeling jerky. Here we use 100 px per three lines
+ // (the default scroll amount on Windows is three lines per wheel tick).
+ static const float cScrollbarPixelsPerLine = 100.0f / 3.0f;
+ float delta = GET_WHEEL_DELTA_WPARAM(wParam) / static_cast<float>(WHEEL_DELTA);
+ if (isMouseHWheel) {
+ // Windows is <-- -/+ -->, WebKit wants <-- +/- -->, so we negate
+ // |delta| after saving the original value on the wheel tick member.
+ m_wheelTicksX = delta;
+ m_wheelTicksY = 0;
+ delta = -delta;
+ } else {
+ // Even though we use shift + vertical wheel to scroll horizontally in
+ // WebKit, we still note it as a vertical scroll on the wheel tick
+ // member, so that the DOM event we later construct will match the real
+ // hardware event better.
+ m_wheelTicksX = 0;
+ m_wheelTicksY = delta;
+ }
+ if (isMouseHWheel || m_shiftKey) {
+ m_deltaX = delta * static_cast<float>(horizontalScrollChars()) * cScrollbarPixelsPerLine;
m_deltaY = 0;
- m_granularity = ScrollByLineWheelEvent;
+ m_granularity = ScrollByPixelWheelEvent;
} else {
m_deltaX = 0;
m_deltaY = delta;
- int verticalMultiplier = verticalLineMultiplier();
- // A multiplier of -1 is used to mean that vertical wheel scrolling should be done by page.
- m_granularity = (verticalMultiplier == -1) ? ScrollByPageWheelEvent : ScrollByLineWheelEvent;
- if (m_granularity == ScrollByLineWheelEvent)
- m_deltaY *= verticalMultiplier;
+ int verticalMultiplier = verticalScrollLines();
+ m_granularity = (verticalMultiplier == WHEEL_PAGESCROLL) ? ScrollByPageWheelEvent : ScrollByPixelWheelEvent;
+ if (m_granularity == ScrollByPixelWheelEvent)
+ m_deltaY *= static_cast<float>(verticalMultiplier) * cScrollbarPixelsPerLine;
}
}
diff --git a/WebCore/platform/wx/MouseWheelEventWx.cpp b/WebCore/platform/wx/MouseWheelEventWx.cpp
index 154a710..9f3923d 100644
--- a/WebCore/platform/wx/MouseWheelEventWx.cpp
+++ b/WebCore/platform/wx/MouseWheelEventWx.cpp
@@ -25,6 +25,7 @@
#include "config.h"
#include "PlatformWheelEvent.h"
+#include "Scrollbar.h"
#include <wx/defs.h>
#include <wx/event.h>
@@ -34,17 +35,19 @@ namespace WebCore {
PlatformWheelEvent::PlatformWheelEvent(const wxMouseEvent& event, const wxPoint& globalPoint)
: m_position(event.GetPosition())
, m_globalPosition(globalPoint)
- , m_granularity(ScrollByLineWheelEvent)
+ , m_granularity(ScrollByPixelWheelEvent)
, m_shiftKey(event.ShiftDown())
, m_ctrlKey(event.ControlDown())
, m_altKey(event.AltDown())
, m_metaKey(event.MetaDown()) // FIXME: We'll have to test other browsers
, m_deltaX(0) // wx doesn't support horizontal mouse wheel scrolling
, m_deltaY(event.GetWheelRotation() / event.GetWheelDelta())
+ , m_wheelTicksX(m_deltaX)
+ , m_wheelTicksY(m_deltaY)
, m_isAccepted(false)
{
// FIXME: retrieve the user setting for the number of lines to scroll on each wheel event
- m_deltaY *= horizontalLineMultiplier();
+ m_deltaY *= static_cast<float>(cScrollbarPixelsPerLineStep);
}
}
diff --git a/WebCore/platform/wx/TemporaryLinkStubs.cpp b/WebCore/platform/wx/TemporaryLinkStubs.cpp
index d8c6046..d8c6046 100755..100644
--- a/WebCore/platform/wx/TemporaryLinkStubs.cpp
+++ b/WebCore/platform/wx/TemporaryLinkStubs.cpp
diff --git a/WebCore/platform/wx/WidgetWx.cpp b/WebCore/platform/wx/WidgetWx.cpp
index 37097fe..37097fe 100755..100644
--- a/WebCore/platform/wx/WidgetWx.cpp
+++ b/WebCore/platform/wx/WidgetWx.cpp
diff --git a/WebCore/platform/wx/wxcode/fontprops.h b/WebCore/platform/wx/wxcode/fontprops.h
index e6f0b16..7f38bcf 100644
--- a/WebCore/platform/wx/wxcode/fontprops.h
+++ b/WebCore/platform/wx/wxcode/fontprops.h
@@ -46,4 +46,5 @@ private:
float m_lineSpacing;
float m_xHeight;
-}; \ No newline at end of file
+};
+
diff --git a/WebCore/platform/wx/wxcode/gtk/fontprops.cpp b/WebCore/platform/wx/wxcode/gtk/fontprops.cpp
index 369fcc5..df14812 100644
--- a/WebCore/platform/wx/wxcode/gtk/fontprops.cpp
+++ b/WebCore/platform/wx/wxcode/gtk/fontprops.cpp
@@ -23,17 +23,42 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "config.h"
+
#include <wx/defs.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/fontutil.h>
#include "fontprops.h"
+#include "non-kerned-drawing.h"
#include <gdk/gdk.h>
+#include <cairo.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
wxFontProperties::wxFontProperties(wxFont* font):
m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0)
{
+ ASSERT(font && font->Ok());
+
+#if USE(WXGC)
+ cairo_font_extents_t font_extents;
+ cairo_text_extents_t text_extents;
+ cairo_scaled_font_t* scaled_font = WebCore::createScaledFontForFont(font);
+
+ cairo_scaled_font_extents(scaled_font, &font_extents);
+ m_ascent = static_cast<int>(font_extents.ascent);
+ m_descent = static_cast<int>(font_extents.descent);
+ m_lineSpacing = static_cast<int>(font_extents.height);
+ cairo_scaled_font_text_extents(scaled_font, "x", &text_extents);
+ m_xHeight = text_extents.height;
+ cairo_scaled_font_text_extents(scaled_font, " ", &text_extents);
+ m_lineGap = m_lineSpacing - m_ascent - m_descent;
+
+ cairo_scaled_font_destroy(scaled_font);
+#else
PangoContext* context = gdk_pango_context_get_for_screen( gdk_screen_get_default() );
PangoLayout* layout = pango_layout_new(context);
// and use it if it's valid
@@ -64,6 +89,7 @@ m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0)
m_lineSpacing = m_ascent + m_descent;
pango_font_metrics_unref(metrics);
+#endif
}
void GetTextExtent( const wxFont& font, const wxString& str, wxCoord *width, wxCoord *height,
@@ -80,16 +106,34 @@ void GetTextExtent( const wxFont& font, const wxString& str, wxCoord *width, wxC
if (str.empty())
return;
-
+
+// FIXME: Doesn't support height, descent or external leading, though we don't need this for WebKit
+// it will need to be implemented before merging into wx unless we craft a new API.
+#if USE(WXGC)
+ PangoFont* pangoFont = WebCore::createPangoFontForFont(&font);
+ PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(WebCore::pangoFontMap()));
+ PangoGlyph pangoGlyph = WebCore::pango_font_get_glyph(pangoFont, pangoContext, (gunichar)g_utf8_get_char(str.ToUTF8()));
+ cairo_glyph_t cglyph = { pangoGlyph, 0, 0 };
+ cairo_text_extents_t extents;
+ cairo_scaled_font_t* scaled_font = WebCore::createScaledFontForFont(&font);
+ cairo_scaled_font_glyph_extents(scaled_font, &cglyph, 1, &extents);
+
+ if (cairo_scaled_font_status(scaled_font) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0)
+ *width = (wxCoord)extents.x_advance;
+
+ cairo_scaled_font_destroy(scaled_font);
+ g_object_unref(pangoContext);
+ g_object_unref(pangoFont);
+#else
PangoContext* context = gdk_pango_context_get_for_screen( gdk_screen_get_default() );
PangoLayout* m_layout = pango_layout_new(context);
// and use it if it's valid
- if ( font != wxNullFont )
+ if ( font && font->IsOk() )
{
pango_layout_set_font_description
(
m_layout,
- font.GetNativeFontInfo()->description
+ font->GetNativeFontInfo()->description
);
}
@@ -103,24 +147,19 @@ void GetTextExtent( const wxFont& font, const wxString& str, wxCoord *width, wxC
pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) );
+ int h = 0;
+ pango_layout_get_pixel_size( m_layout, width, &h );
+
if (descent)
{
- int h;
- pango_layout_get_pixel_size( m_layout, width, &h );
PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
int baseline = pango_layout_iter_get_baseline(iter);
pango_layout_iter_free(iter);
*descent = h - PANGO_PIXELS(baseline);
-
- if (height)
- *height = (wxCoord) h;
- }
- else
- {
- pango_layout_get_pixel_size( m_layout, width, height );
}
- // Reset old font description
- //if (font != wxNullFont)
- // pango_layout_set_font_description( m_layout, m_fontdesc );
-} \ No newline at end of file
+ if (height)
+ *height = (wxCoord) h;
+#endif
+}
+
diff --git a/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp
index ed8fb09..bf745e0 100644
--- a/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp
+++ b/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp
@@ -28,25 +28,201 @@
#include "GraphicsContext.h"
#include "SimpleFontData.h"
+#include <wx/dc.h>
#include <wx/dcgraph.h>
#include <wx/defs.h>
#include <wx/dcclient.h>
#include <wx/gdicmn.h>
#include <vector>
+#if USE(WXGC)
+#include <cairo.h>
+#include <assert.h>
+
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
+// Use cairo-ft if a recent enough Pango version isn't available
+#if !PANGO_VERSION_CHECK(1,18,0)
+#include <cairo-ft.h>
+#include <pango/pangofc-fontmap.h>
+#endif
+
+#endif
+
+#include <gtk/gtk.h>
+
namespace WebCore {
+#if USE(WXGC)
+static PangoFontMap* g_fontMap;
+
+PangoFontMap* pangoFontMap()
+{
+ if (!g_fontMap)
+ g_fontMap = pango_cairo_font_map_get_default();
+
+ return g_fontMap;
+}
+
+PangoFont* createPangoFontForFont(const wxFont* wxfont)
+{
+ ASSERT(wxfont && wxfont->Ok());
+
+ const char* face = wxfont->GetFaceName().mb_str(wxConvUTF8);
+ char const* families[] = {
+ face,
+ 0
+ };
+
+ switch (wxfont->GetFamily()) {
+ case wxFONTFAMILY_ROMAN:
+ families[1] = "serif";
+ break;
+ case wxFONTFAMILY_SWISS:
+ families[1] = "sans";
+ break;
+ case wxFONTFAMILY_MODERN:
+ families[1] = "monospace";
+ break;
+ default:
+ families[1] = "sans";
+ }
+
+ PangoFontDescription* description = pango_font_description_new();
+ pango_font_description_set_absolute_size(description, wxfont->GetPointSize() * PANGO_SCALE);
+
+ PangoFont* pangoFont = 0;
+ PangoContext* pangoContext = 0;
+
+ switch (wxfont->GetWeight()) {
+ case wxFONTWEIGHT_LIGHT:
+ pango_font_description_set_weight(description, PANGO_WEIGHT_LIGHT);
+ break;
+ case wxFONTWEIGHT_NORMAL:
+ pango_font_description_set_weight(description, PANGO_WEIGHT_NORMAL);
+ break;
+ case wxFONTWEIGHT_BOLD:
+ pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD);
+ break;
+ }
+
+ switch (wxfont->GetStyle()) {
+ case wxFONTSTYLE_NORMAL:
+ pango_font_description_set_style(description, PANGO_STYLE_NORMAL);
+ break;
+ case wxFONTSTYLE_ITALIC:
+ pango_font_description_set_style(description, PANGO_STYLE_ITALIC);
+ break;
+ case wxFONTSTYLE_SLANT:
+ pango_font_description_set_style(description, PANGO_STYLE_OBLIQUE);
+ break;
+ }
+
+ PangoFontMap* fontMap = pangoFontMap();
+
+ pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(fontMap));
+ for (unsigned i = 0; !pangoFont && i < G_N_ELEMENTS(families); i++) {
+ pango_font_description_set_family(description, families[i]);
+ pango_context_set_font_description(pangoContext, description);
+ pangoFont = pango_font_map_load_font(fontMap, pangoContext, description);
+ }
+ pango_font_description_free(description);
+
+ return pangoFont;
+}
+
+cairo_scaled_font_t* createScaledFontForFont(const wxFont* wxfont)
+{
+ ASSERT(wxfont && wxfont->Ok());
+
+ cairo_scaled_font_t* scaledFont = NULL;
+ PangoFont* pangoFont = createPangoFontForFont(wxfont);
+
+#if PANGO_VERSION_CHECK(1,18,0)
+ if (pangoFont)
+ scaledFont = cairo_scaled_font_reference(pango_cairo_font_get_scaled_font(PANGO_CAIRO_FONT(pangoFont)));
+#endif
+
+ return scaledFont;
+}
+
+PangoGlyph pango_font_get_glyph(PangoFont* font, PangoContext* context, gunichar wc)
+{
+ PangoGlyph result = 0;
+ gchar buffer[7];
+
+ gint length = g_unichar_to_utf8(wc, buffer);
+ g_return_val_if_fail(length, 0);
+
+ GList* items = pango_itemize(context, buffer, 0, length, NULL, NULL);
+
+ if (g_list_length(items) == 1) {
+ PangoItem* item = static_cast<PangoItem*>(items->data);
+ PangoFont* tmpFont = item->analysis.font;
+ item->analysis.font = font;
+
+ PangoGlyphString* glyphs = pango_glyph_string_new();
+ pango_shape(buffer, length, &item->analysis, glyphs);
+
+ item->analysis.font = tmpFont;
+
+ if (glyphs->num_glyphs == 1)
+ result = glyphs->glyphs[0].glyph;
+ else
+ g_warning("didn't get 1 glyph but %d", glyphs->num_glyphs);
+
+ pango_glyph_string_free(glyphs);
+ }
+
+ g_list_foreach(items, (GFunc)pango_item_free, NULL);
+ g_list_free(items);
+
+ return result;
+}
+#endif // USE(WXGC)
+
+
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
{
#if USE(WXGC)
wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
+ wxGraphicsContext* gc = dc->GetGraphicsContext();
+ gc->PushState();
+ cairo_t* cr = (cairo_t*)gc->GetNativeContext();
+
+ wxFont* wxfont = font->getWxFont();
+ PangoFont* pangoFont = createPangoFontForFont(wxfont);
+ PangoFontMap* fontMap = pangoFontMap();
+ PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(fontMap));
+ cairo_scaled_font_t* scaled_font = createScaledFontForFont(wxfont);
+ ASSERT(scaled_font);
+
+ cairo_glyph_t* glyphs = NULL;
+ glyphs = static_cast<cairo_glyph_t*>(malloc(sizeof(cairo_glyph_t) * numGlyphs));
+
+ float offset = point.x();
+
+ for (int i = 0; i < numGlyphs; i++) {
+ glyphs[i].index = pango_font_get_glyph(pangoFont, pangoContext, glyphBuffer.glyphAt(from + i));
+ glyphs[i].x = offset;
+ glyphs[i].y = point.y();
+ offset += glyphBuffer.advanceAt(from + i);
+ }
+
+ cairo_set_source_rgba(cr, color.Red()/255.0, color.Green()/255.0, color.Blue()/255.0, color.Alpha()/255.0);
+ cairo_set_scaled_font(cr, scaled_font);
+
+ cairo_show_glyphs(cr, glyphs, numGlyphs);
+
+ cairo_scaled_font_destroy(scaled_font);
+ gc->PopState();
#else
wxDC* dc = graphicsContext->platformContext();
-#endif
- wxFont wxfont = font->getWxFont();
- if (wxfont.IsOk())
- dc->SetFont(wxfont);
+ wxFont* wxfont = font->getWxFont();
+ if (wxfont && wxfont->IsOk())
+ dc->SetFont(*wxfont);
dc->SetTextForeground(color);
// convert glyphs to wxString
@@ -63,6 +239,7 @@ void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData*
wxCoord ypoint = (wxCoord) (point.y() - height);
dc->DrawText(text, (wxCoord)point.x(), ypoint);
+#endif
}
}
diff --git a/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp b/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp
index b649eb4..447a3d0 100644
--- a/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp
+++ b/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp
@@ -36,14 +36,19 @@ static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x * (c
wxFontProperties::wxFontProperties(wxFont* font):
m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0)
{
- ATSFontRef fontRef;
CGFontRef cgFont;
+
+#ifdef wxOSX_USE_CORE_TEXT && wxOSX_USE_CORE_TEXT
+ cgFont = CTFontCopyGraphicsFont((CTFontRef)font->MacGetCTFont(), NULL);
+#else
+ ATSFontRef fontRef;
fontRef = FMGetATSFontRefFromFont(font->MacGetATSUFontID());
if (fontRef)
cgFont = CGFontCreateWithPlatformFont((void*)&fontRef);
-
+#endif
+
if (cgFont) {
int iAscent;
int iDescent;
@@ -89,7 +94,7 @@ void GetTextExtent( const wxFont& font, const wxString& str, wxCoord *width, wxC
// we need the scale here ...
- Fixed atsuSize = IntToFixed( int( /*m_scaleY*/ 1 * font.MacGetFontSize()) ) ;
+ Fixed atsuSize = IntToFixed( int( /*m_scaleY*/ 1 * font.GetPointSize()) ) ;
//RGBColor atsuColor = MAC_WXCOLORREF( m_textForegroundColor.GetPixel() ) ;
ATSUAttributeTag atsuTags[] =
{
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 126f7ec..6eaa765 100644
--- a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp
+++ b/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp
@@ -30,6 +30,7 @@
#include <wx/defs.h>
#include <wx/dcclient.h>
+#include <wx/dcgraph.h>
#include <wx/gdicmn.h>
#include <vector>
@@ -43,9 +44,9 @@ void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData*
wxDC* dc = graphicsContext->platformContext();
#endif
- wxFont wxfont = font->getWxFont();
- if (wxfont.IsOk())
- dc->SetFont(wxfont);
+ wxFont* wxfont = font->getWxFont();
+ if (wxfont->IsOk())
+ dc->SetFont(*wxfont);
dc->SetTextForeground(color);
// convert glyphs to wxString
diff --git a/WebCore/platform/wx/wxcode/non-kerned-drawing.h b/WebCore/platform/wx/wxcode/non-kerned-drawing.h
index d005985..b995d37 100644
--- a/WebCore/platform/wx/wxcode/non-kerned-drawing.h
+++ b/WebCore/platform/wx/wxcode/non-kerned-drawing.h
@@ -27,10 +27,25 @@
#include "GlyphBuffer.h"
#include <wx/defs.h>
-#include <wx/dcclient.h>
+#include <wx/dcclient.h>
+
+#if __WXGTK__ && USE(WXGC)
+#include <cairo.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+#endif
namespace WebCore {
extern void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point);
-
-}
+
+#if __WXGTK__ && USE(WXGC)
+PangoFontMap* pangoFontMap();
+
+PangoFont* createPangoFontForFont(const wxFont* wxfont);
+cairo_scaled_font_t* createScaledFontForFont(const wxFont* wxfont);
+PangoGlyph pango_font_get_glyph(PangoFont* font, PangoContext* context, gunichar wc);
+
+#endif
+}
+
diff --git a/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp
index f05923a..7d1e924 100644
--- a/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp
+++ b/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp
@@ -101,7 +101,9 @@ void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData*
for (unsigned i = 0; i < numGlyphs; ++i)
spacing[i] = advances[i].width();
- ::SelectObject(hdc, GetHfontOf(font->getWxFont()));
+ wxFont* wxfont = font->getWxFont();
+ if (wxfont && wxfont->IsOk())
+ ::SelectObject(hdc, GetHfontOf(*wxfont));
if (color.Ok())
::SetTextColor(hdc, color.GetPixel());