[FTW] Go back to ID2D1Bitmap as our NativeImage type
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 26 Aug 2019 19:08:57 +0000 (19:08 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 26 Aug 2019 19:08:57 +0000 (19:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=201122

Reviewed by Alex Christensen.

In Bug 200093 I switched the OS type of NativeImagePtr from ID2D1Bitmap to IWICBitmap.
However, this was an ill-advised approach, because it dramatically harmed performance due
to the heavy use of software rendering.

I originally made this change because I thought this was the only way to get to the backing
bits of the bitmaps, but it turns out that a more recent Direct2D data type (ID2D1Bitmap1)
has the ability to map its memory to CPU-accessible memory, allowing software filter effects.

This patch switches back to the ID2D1Bitap data type, and hooks up the ID2D1Bitmap1 data type
to access the underlying memory of the bitmaps when software filter effects are used.

Source/WebCore:

* platform/graphics/ImageBuffer.h:
* platform/graphics/NativeImage.h:
* platform/graphics/texmap/BitmapTextureGL.cpp:
* platform/graphics/win/Direct2DOperations.cpp:
* platform/graphics/win/Direct2DOperations.h:
* platform/graphics/win/Direct2DUtilities.cpp:
(WebCore::Direct2D::writeDiagnosticPNGToPath):
(WebCore::Direct2D::writeImageToDiskAsPNG): Deleted.
* platform/graphics/win/Direct2DUtilities.h:
* platform/graphics/win/GraphicsContextDirect2D.cpp:
* platform/graphics/win/ImageBufferDataDirect2D.cpp:
* platform/graphics/win/ImageBufferDataDirect2D.h:
* platform/graphics/win/ImageBufferDirect2D.cpp:
* platform/graphics/win/ImageDecoderDirect2D.cpp:
* platform/graphics/win/NativeImageDirect2D.cpp:
* platform/graphics/win/PatternDirect2D.cpp:
* svg/graphics/SVGImage.cpp:

Source/WebKit:

Reviewed by Alex Christensen.

* Shared/ShareableBitmap.h:
* Shared/win/ShareableBitmapDirect2D.cpp:
* UIProcess/win/BackingStoreDirect2D.cpp:
* WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249110 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/Image.cpp
Source/WebCore/platform/graphics/ImageBuffer.h
Source/WebCore/platform/graphics/NativeImage.h
Source/WebCore/platform/graphics/texmap/BitmapTextureGL.cpp
Source/WebCore/platform/graphics/win/Direct2DOperations.cpp
Source/WebCore/platform/graphics/win/Direct2DOperations.h
Source/WebCore/platform/graphics/win/Direct2DUtilities.cpp
Source/WebCore/platform/graphics/win/Direct2DUtilities.h
Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp
Source/WebCore/platform/graphics/win/GraphicsContextImplDirect2D.cpp
Source/WebCore/platform/graphics/win/ImageBufferDataDirect2D.cpp
Source/WebCore/platform/graphics/win/ImageBufferDataDirect2D.h
Source/WebCore/platform/graphics/win/ImageBufferDirect2D.cpp
Source/WebCore/platform/graphics/win/ImageDecoderDirect2D.cpp
Source/WebCore/platform/graphics/win/NativeImageDirect2D.cpp
Source/WebCore/platform/graphics/win/PatternDirect2D.cpp
Source/WebCore/svg/graphics/SVGImage.cpp
Source/WebKit/ChangeLog
Source/WebKit/Shared/ShareableBitmap.h
Source/WebKit/Shared/win/ShareableBitmapDirect2D.cpp
Source/WebKit/UIProcess/win/BackingStoreDirect2D.cpp
Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp

index 2fb87ac..79cfd1b 100644 (file)
@@ -1,3 +1,39 @@
+2019-08-26  Brent Fulgham  <bfulgham@apple.com>
+
+        [FTW] Go back to ID2D1Bitmap as our NativeImage type
+        https://bugs.webkit.org/show_bug.cgi?id=201122
+
+        Reviewed by Alex Christensen.
+
+        In Bug 200093 I switched the OS type of NativeImagePtr from ID2D1Bitmap to IWICBitmap.
+        However, this was an ill-advised approach, because it dramatically harmed performance due
+        to the heavy use of software rendering.
+
+        I originally made this change because I thought this was the only way to get to the backing
+        bits of the bitmaps, but it turns out that a more recent Direct2D data type (ID2D1Bitmap1)
+        has the ability to map its memory to CPU-accessible memory, allowing software filter effects.
+
+        This patch switches back to the ID2D1Bitap data type, and hooks up the ID2D1Bitmap1 data type
+        to access the underlying memory of the bitmaps when software filter effects are used.
+
+        * platform/graphics/ImageBuffer.h:
+        * platform/graphics/NativeImage.h:
+        * platform/graphics/texmap/BitmapTextureGL.cpp:
+        * platform/graphics/win/Direct2DOperations.cpp:
+        * platform/graphics/win/Direct2DOperations.h:
+        * platform/graphics/win/Direct2DUtilities.cpp:
+        (WebCore::Direct2D::writeDiagnosticPNGToPath):
+        (WebCore::Direct2D::writeImageToDiskAsPNG): Deleted.
+        * platform/graphics/win/Direct2DUtilities.h:
+        * platform/graphics/win/GraphicsContextDirect2D.cpp:
+        * platform/graphics/win/ImageBufferDataDirect2D.cpp:
+        * platform/graphics/win/ImageBufferDataDirect2D.h:
+        * platform/graphics/win/ImageBufferDirect2D.cpp:
+        * platform/graphics/win/ImageDecoderDirect2D.cpp:
+        * platform/graphics/win/NativeImageDirect2D.cpp:
+        * platform/graphics/win/PatternDirect2D.cpp:
+        * svg/graphics/SVGImage.cpp:
+
 2019-08-26  Sam Weinig  <weinig@apple.com>
 
         [WHLSL] TypeNamer can be simplified by replacing BaseTypeNameNode with uniqued AST::UnnamedTypes
index 3999672..b6bda30 100644 (file)
@@ -140,7 +140,7 @@ void Image::fillWithSolidColor(GraphicsContext& ctxt, const FloatRect& dstRect,
 void Image::drawPattern(GraphicsContext& ctxt, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform,
     const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode)
 {
-    if (!nativeImageForCurrentFrame())
+    if (!nativeImageForCurrentFrame(&ctxt))
         return;
 
     ctxt.drawPattern(*this, destRect, tileRect, patternTransform, phase, spacing, op, blendMode);
index 3cd4750..8efd58a 100644 (file)
@@ -146,8 +146,8 @@ private:
     static RetainPtr<CGImageRef> sinkIntoNativeImage(std::unique_ptr<ImageBuffer>);
     void flushContext() const;
 #elif USE(DIRECT2D)
-    COMPtr<IWICBitmap> copyNativeImage(BackingStoreCopy = CopyBackingStore) const;
-    static COMPtr<IWICBitmap> sinkIntoNativeImage(std::unique_ptr<ImageBuffer>);
+    COMPtr<ID2D1Bitmap> copyNativeImage(BackingStoreCopy = CopyBackingStore) const;
+    static COMPtr<ID2D1Bitmap> sinkIntoNativeImage(std::unique_ptr<ImageBuffer>);
     void flushContext() const;
 #endif
     
index d0ff67e..5af43aa 100644 (file)
@@ -55,7 +55,7 @@ class GraphicsContext;
 #if USE(CG)
 typedef RetainPtr<CGImageRef> NativeImagePtr;
 #elif USE(DIRECT2D)
-typedef COMPtr<IWICBitmap> NativeImagePtr;
+typedef COMPtr<ID2D1Bitmap> NativeImagePtr;
 #elif USE(CAIRO)
 typedef RefPtr<cairo_surface_t> NativeImagePtr;
 #elif USE(WINGDI)
index 79b0ed5..79b006e 100644 (file)
@@ -163,28 +163,7 @@ void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, co
     imageData = reinterpret_cast<const char*>(cairo_image_surface_get_data(surface));
     bytesPerLine = cairo_image_surface_get_stride(surface);
 #elif USE(DIRECT2D)
-    // We can't access the bitmap's memory when it is in the middle of a BeginDraw/EndDraw
-    WICRect rcLock = { 0, 0, targetRect.width(), targetRect.height() };
-
-    COMPtr<IWICBitmapLock> bitmapData;
-    HRESULT hr = frameImage->Lock(&rcLock, WICBitmapLockRead, &bitmapData);
-    if (!SUCCEEDED(hr))
-        return;
-
-    UINT stride = 0;
-    hr = bitmapData->GetStride(&stride);
-    if (!SUCCEEDED(hr))
-        return;
-
-    bytesPerLine = stride;
-
-    UINT bufferSize = 0;
-    WICInProcPointer dataPtr = nullptr;
-    hr = bitmapData->GetDataPointer(&bufferSize, &dataPtr);
-    if (!SUCCEEDED(hr))
-        return;
-
-    imageData = reinterpret_cast<char*>(dataPtr);
+    notImplemented();
 #endif
 
     updateContents(imageData, targetRect, offset, bytesPerLine);
index d7a0e98..26618e7 100644 (file)
@@ -528,8 +528,6 @@ void fillPath(PlatformContextDirect2D& platformContext, const Path& path, const
         FloatRect contextRect(FloatPoint(), context->GetSize());
         drawWithoutShadow(platformContext, contextRect, drawFunction);
     }
-
-    flush(platformContext);
 }
 
 void fillPath(PlatformContextDirect2D& platformContext, const Path& path, const Color& color, const ShadowState& shadowState)
@@ -554,8 +552,6 @@ void fillPath(PlatformContextDirect2D& platformContext, const Path& path, const
         FloatRect contextRect(FloatPoint(), context->GetSize());
         drawWithoutShadow(platformContext, contextRect, drawFunction);
     }
-
-    flush(platformContext);
 }
 
 void strokeRect(PlatformContextDirect2D& platformContext, const FloatRect& rect, float lineWidth, const StrokeSource& strokeSource, const ShadowState& shadowState)
@@ -588,8 +584,6 @@ void strokePath(PlatformContextDirect2D& platformContext, const Path& path, cons
         drawWithShadow(platformContext, boundingRect, shadowState, drawFunction);
     else
         drawWithoutShadow(platformContext, boundingRect, drawFunction);
-
-    flush(platformContext);
 }
 
 void drawPath(PlatformContextDirect2D& platformContext, const Path& path, const StrokeSource& strokeSource, const ShadowState&)
@@ -640,13 +634,6 @@ void drawWithShadowHelper(ID2D1RenderTarget* context, ID2D1Bitmap* bitmap, const
     compositor->SetInputEffect(0, transformEffect.get());
     compositor->SetInput(1, bitmap);
 
-    // Flip the context
-    D2D1_MATRIX_3X2_F ctm;
-    deviceContext->GetTransform(&ctm);
-    auto translate = D2D1::Matrix3x2F::Translation(0.0f, deviceContext->GetSize().height);
-    auto flip = D2D1::Matrix3x2F::Scale(D2D1::SizeF(1.0f, -1.0f));
-    deviceContext->SetTransform(ctm * flip * translate);
-
     deviceContext->DrawImage(compositor.get(), D2D1_INTERPOLATION_MODE_LINEAR);
 }
 
@@ -655,13 +642,11 @@ void drawWithShadow(PlatformContextDirect2D& platformContext, const FloatRect& b
     auto context = platformContext.renderTarget();
 
     // Render the current geometry to a bitmap context
-    COMPtr<ID2D1BitmapRenderTarget> bitmapTarget;
-    HRESULT hr = context->CreateCompatibleRenderTarget(&bitmapTarget);
-    RELEASE_ASSERT(SUCCEEDED(hr));
+    COMPtr<ID2D1BitmapRenderTarget> bitmapTarget = createBitmapRenderTarget(context);
 
     bitmapTarget->BeginDraw();
     drawCommands(bitmapTarget.get());
-    hr = bitmapTarget->EndDraw();
+    HRESULT hr = bitmapTarget->EndDraw();
     RELEASE_ASSERT(SUCCEEDED(hr));
 
     COMPtr<ID2D1Bitmap> bitmap;
@@ -836,13 +821,11 @@ void drawNativeImage(PlatformContextDirect2D& platformContext, ID2D1Bitmap* imag
     else
         drawWithoutShadow(platformContext, adjustedDestRect, drawFunction);
 
-    flush(platformContext);
-
     if (!stateSaver.didSave())
         context->SetTransform(ctm);
 }
 
-void drawPattern(PlatformContextDirect2D& platformContext, IWICBitmap* tileImage, const IntSize& size, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, CompositeOperator compositeOperator, BlendMode blendMode)
+void drawPattern(PlatformContextDirect2D& platformContext, COMPtr<ID2D1Bitmap>&& tileImage, const IntSize& size, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, CompositeOperator compositeOperator, BlendMode blendMode)
 {
     auto context = platformContext.renderTarget();
     PlatformContextStateSaver stateSaver(platformContext);
@@ -866,8 +849,6 @@ void drawPattern(PlatformContextDirect2D& platformContext, IWICBitmap* tileImage
     // If we only want a subset of the bitmap, we need to create a cropped bitmap image. According to the documentation,
     // this does not allocate new bitmap memory.
     if (size.width() > destRect.width() || size.height() > destRect.height()) {
-        ASSERT(0);
-        /*
         float dpiX = 0;
         float dpiY = 0;
         tileImage->GetDpi(&dpiX, &dpiY);
@@ -880,16 +861,10 @@ void drawPattern(PlatformContextDirect2D& platformContext, IWICBitmap* tileImage
             if (SUCCEEDED(hr))
                 tileImage = subImage;
         }
-        */
     }
 
-    COMPtr<ID2D1Bitmap> bitmap;
-    HRESULT hr = context->CreateBitmapFromWicBitmap(tileImage, nullptr, &bitmap);
-    if (!SUCCEEDED(hr))
-        return;
-
     COMPtr<ID2D1BitmapBrush> patternBrush;
-    hr = context->CreateBitmapBrush(bitmap.get(), &bitmapBrushProperties, &brushProperties, &patternBrush);
+    HRESULT hr = context->CreateBitmapBrush(tileImage.get(), &bitmapBrushProperties, &brushProperties, &patternBrush);
     ASSERT(SUCCEEDED(hr));
     if (!SUCCEEDED(hr))
         return;
@@ -1109,8 +1084,8 @@ void beginTransparencyLayer(PlatformContextDirect2D& platformContext, float opac
     PlatformContextDirect2D::TransparencyLayerState transparencyLayer;
     transparencyLayer.opacity = opacity;
 
-    HRESULT hr = platformContext.renderTarget()->CreateCompatibleRenderTarget(&transparencyLayer.renderTarget);
-    RELEASE_ASSERT(SUCCEEDED(hr));
+    transparencyLayer.renderTarget = createBitmapRenderTarget(platformContext.renderTarget());
+
     platformContext.m_transparencyLayerStack.append(WTFMove(transparencyLayer));
 
     platformContext.m_transparencyLayerStack.last().renderTarget->BeginDraw();
@@ -1222,7 +1197,20 @@ void clipToImageBuffer(PlatformContextDirect2D&, ID2D1RenderTarget*, const Float
     notImplemented();
 }
 
+
+void copyBits(const uint8_t* srcRows, unsigned rowCount, unsigned colCount, unsigned srcStride, unsigned destStride, uint8_t* destRows)
+{
+    for (unsigned y = 0; y < rowCount; ++y) {
+        // Source data may be power-of-two sized, so we need to only copy the bits that
+        // correspond to the rectangle supplied by the caller.
+        const uint32_t* srcRow = reinterpret_cast<const uint32_t*>(srcRows + srcStride * y);
+        uint32_t* destRow = reinterpret_cast<uint32_t*>(destRows + destStride * y);
+        memcpy(destRow, srcRow, colCount);
+    }
+}
+
 } // namespace Direct2D
+
 } // namespace WebCore
 
 #endif // USE(DIRECT2D)
index 06f6561..50d0efd 100644 (file)
@@ -37,6 +37,7 @@
 #include "DashArray.h"
 #include "GraphicsContext.h"
 #include "GraphicsTypes.h"
+#include <JavaScriptCore/Uint8ClampedArray.h>
 #include <d2d1.h>
 
 namespace WebCore {
@@ -130,7 +131,7 @@ void drawGlyphs(PlatformContextDirect2D&, const FillSource&, const StrokeSource&
 void drawNativeImage(PlatformContextDirect2D&, IWICBitmap*, const FloatSize& imageSize, const FloatRect&, const FloatRect&, CompositeOperator, BlendMode, ImageOrientation, InterpolationQuality, float, const ShadowState&);
 void drawNativeImage(PlatformContextDirect2D&, ID2D1Bitmap*, const FloatSize& imageSize, const FloatRect&, const FloatRect&, CompositeOperator, BlendMode, ImageOrientation, InterpolationQuality, float, const ShadowState&);
 void drawPath(PlatformContextDirect2D&, const Path&, const StrokeSource&, const ShadowState&);
-void drawPattern(PlatformContextDirect2D&, IWICBitmap*, const IntSize&, const FloatRect&, const FloatRect&, const AffineTransform&, const FloatPoint&, CompositeOperator, BlendMode);
+void drawPattern(PlatformContextDirect2D&, COMPtr<ID2D1Bitmap>&&, const IntSize&, const FloatRect&, const FloatRect&, const AffineTransform&, const FloatPoint&, CompositeOperator, BlendMode);
 
 void drawWithoutShadow(PlatformContextDirect2D&, const FloatRect& boundingRect, const WTF::Function<void(ID2D1RenderTarget*)>& drawCommands);
 void drawWithShadow(PlatformContextDirect2D&, const FloatRect& boundingRect, const ShadowState&, const WTF::Function<void(ID2D1RenderTarget*)>& drawCommands);
index ba92cc9..80031ea 100644 (file)
@@ -115,7 +115,7 @@ COMPtr<IWICBitmap> createDirect2DImageSurfaceWithData(void* data, const IntSize&
         return nullptr;
 
     COMPtr<IWICBitmap> surface;
-    HRESULT hr = ImageDecoderDirect2D::systemImagingFactory()->CreateBitmapFromMemory(size.width(), size.height(), GUID_WICPixelFormat32bppPBGRA, stride, static_cast<UINT>(numBytes.unsafeGet()), reinterpret_cast<BYTE*>(data), &surface);
+    HRESULT hr = ImageDecoderDirect2D::systemImagingFactory()->CreateBitmapFromMemory(size.width(), size.height(), wicBitmapFormat(), stride, static_cast<UINT>(numBytes.unsafeGet()), reinterpret_cast<BYTE*>(data), &surface);
     if (!SUCCEEDED(hr))
         return nullptr;
 
@@ -125,31 +125,58 @@ COMPtr<IWICBitmap> createDirect2DImageSurfaceWithData(void* data, const IntSize&
 COMPtr<IWICBitmap> createWicBitmap(const IntSize& size)
 {
     COMPtr<IWICBitmap> surface;
-    HRESULT hr = ImageDecoderDirect2D::systemImagingFactory()->CreateBitmap(size.width(), size.height(), GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnDemand, &surface);
+    HRESULT hr = ImageDecoderDirect2D::systemImagingFactory()->CreateBitmap(size.width(), size.height(), wicBitmapFormat(), WICBitmapCacheOnDemand, &surface);
     if (!SUCCEEDED(hr))
         return nullptr;
 
     return surface;
 }
 
+D2D1_PIXEL_FORMAT pixelFormatForSoftwareManipulation()
+{
+    return D2D1::PixelFormat(DXGI_FORMAT_R8G8B8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED);
+}
+
+D2D1_PIXEL_FORMAT pixelFormat()
+{
+    // Since we need to interact with HDC from time-to-time, we are forced to use DXGI_FORMAT_B8G8R8A8_UNORM and D2D1_ALPHA_MODE_PREMULTIPLIED
+    return D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED);
+}
+
+GUID wicBitmapFormat()
+{
+    // This is the WIC format compatible with DXGI_FORMAT_B8G8R8A8_UNORM. It is also supposedly the most efficient in-memory
+    // representation for WIC images.
+    return GUID_WICPixelFormat32bppPBGRA;
+}
+
+D2D1_BITMAP_PROPERTIES bitmapProperties()
+{
+    return D2D1::BitmapProperties(pixelFormat());
+}
+
 COMPtr<ID2D1Bitmap> createBitmap(ID2D1RenderTarget* renderTarget, const IntSize& size)
 {
-    auto bitmapProperties = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED));
+    auto bitmapCreateProperties = bitmapProperties();
 
     COMPtr<ID2D1Bitmap> bitmap;
     D2D1_SIZE_U bitmapSize = size;
-    HRESULT hr = renderTarget->CreateBitmap(bitmapSize, bitmapProperties, &bitmap);
+    HRESULT hr = renderTarget->CreateBitmap(bitmapSize, bitmapCreateProperties, &bitmap);
     if (!SUCCEEDED(hr))
         return nullptr;
 
     return bitmap;
 }
 
+D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties()
+{
+    return D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
+        pixelFormat(), 0, 0, D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE, D2D1_FEATURE_LEVEL_DEFAULT);
+}
+
 COMPtr<ID2D1RenderTarget> createRenderTargetFromWICBitmap(IWICBitmap* bitmapSource)
 {
-    auto targetProperties = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
-        D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
-        0, 0, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT);
+    auto targetProperties = renderTargetProperties();
 
     COMPtr<ID2D1RenderTarget> bitmapContext;
     HRESULT hr = GraphicsContext::systemFactory()->CreateWicBitmapRenderTarget(bitmapSource, &targetProperties, &bitmapContext);
@@ -161,9 +188,7 @@ COMPtr<ID2D1RenderTarget> createRenderTargetFromWICBitmap(IWICBitmap* bitmapSour
 
 COMPtr<ID2D1DCRenderTarget> createGDIRenderTarget()
 {
-    auto targetProperties = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
-        D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
-        0, 0, D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE, D2D1_FEATURE_LEVEL_DEFAULT);
+    auto targetProperties = renderTargetProperties();
 
     COMPtr<ID2D1DCRenderTarget> renderTarget;
     HRESULT hr = GraphicsContext::systemFactory()->CreateDCRenderTarget(&targetProperties, &renderTarget);
@@ -173,6 +198,36 @@ COMPtr<ID2D1DCRenderTarget> createGDIRenderTarget()
     return renderTarget;
 }
 
+COMPtr<ID2D1BitmapRenderTarget> createBitmapRenderTarget(ID2D1RenderTarget* renderTarget)
+{
+    if (!renderTarget)
+        renderTarget = GraphicsContext::defaultRenderTarget();
+
+    COMPtr<ID2D1BitmapRenderTarget> bitmapContext;
+    HRESULT hr = renderTarget->CreateCompatibleRenderTarget(nullptr, nullptr, nullptr, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, &bitmapContext);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    return bitmapContext;
+}
+
+COMPtr<ID2D1BitmapRenderTarget> createBitmapRenderTargetOfSize(const IntSize& size, ID2D1RenderTarget* renderTarget, float deviceScaleFactor)
+{
+    UNUSED_PARAM(deviceScaleFactor);
+
+    if (!renderTarget)
+        renderTarget = GraphicsContext::defaultRenderTarget();
+
+    COMPtr<ID2D1BitmapRenderTarget> bitmapContext;
+    auto desiredSize = D2D1::SizeF(size.width(), size.height());
+    D2D1_SIZE_U pixelSize = size;
+    HRESULT hr = renderTarget->CreateCompatibleRenderTarget(&desiredSize, &pixelSize, nullptr, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, &bitmapContext);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    return bitmapContext;
+}
+
 void copyRectFromOneSurfaceToAnother(ID2D1Bitmap* from, ID2D1Bitmap* to, const IntSize& sourceOffset, const IntRect& rect, const IntSize& destOffset)
 {
     IntSize sourceBitmapSize = from->GetPixelSize();
@@ -199,7 +254,7 @@ void copyRectFromOneSurfaceToAnother(ID2D1Bitmap* from, ID2D1Bitmap* to, const I
     ASSERT(SUCCEEDED(hr));
 }
 
-void writeImageToDiskAsPNG(ID2D1RenderTarget* renderTarget, ID2D1Bitmap* bitmap, LPCWSTR fileName)
+void writeDiagnosticPNGToPath(ID2D1RenderTarget* renderTarget, ID2D1Bitmap* bitmap, LPCWSTR fileName)
 {
     COMPtr<IWICBitmapEncoder> wicBitmapEncoder;
     HRESULT hr = ImageDecoderDirect2D::systemImagingFactory()->CreateEncoder(GUID_ContainerFormatPng, nullptr, &wicBitmapEncoder);
index 4333dfe..c21f65e 100644 (file)
 #include "IntSize.h"
 
 interface ID2D1Bitmap;
+interface ID2D1BitmapRenderTarget;
 interface ID2D1DCRenderTarget;
 interface ID2D1RenderTarget;
 interface IWICBitmapSource;
 interface IWICBitmap;
 
+struct D2D1_BITMAP_PROPERTIES;
+struct D2D1_PIXEL_FORMAT;
+struct D2D1_RENDER_TARGET_PROPERTIES;
+
 namespace WebCore {
 
 class FloatPoint;
@@ -48,6 +53,14 @@ class IntSize;
 
 namespace Direct2D {
 
+GUID wicBitmapFormat();
+D2D1_PIXEL_FORMAT pixelFormat(); // BGRA
+D2D1_PIXEL_FORMAT pixelFormatForSoftwareManipulation(); // RGBA
+D2D1_BITMAP_PROPERTIES bitmapProperties();
+D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties();
+
+void inPlaceSwizzle(uint8_t* byteData, unsigned length, bool applyPremultiplication = false);
+
 IntSize bitmapSize(IWICBitmapSource*);
 FloatSize bitmapSize(ID2D1Bitmap*);
 FloatPoint bitmapResolution(IWICBitmapSource*);
@@ -57,11 +70,13 @@ COMPtr<ID2D1Bitmap> createBitmap(ID2D1RenderTarget*, const IntSize&);
 COMPtr<IWICBitmap> createWicBitmap(const IntSize&);
 COMPtr<IWICBitmap> createDirect2DImageSurfaceWithData(void* data, const IntSize&, unsigned stride);
 COMPtr<ID2D1RenderTarget> createRenderTargetFromWICBitmap(IWICBitmap*);
+COMPtr<ID2D1BitmapRenderTarget> createBitmapRenderTargetOfSize(const IntSize&, ID2D1RenderTarget* = nullptr, float deviceScaleFactor = 1.0);
+COMPtr<ID2D1BitmapRenderTarget> createBitmapRenderTarget(ID2D1RenderTarget* = nullptr);
 COMPtr<ID2D1DCRenderTarget> createGDIRenderTarget();
 
 void copyRectFromOneSurfaceToAnother(ID2D1Bitmap* from, ID2D1Bitmap* to, const IntSize& sourceOffset, const IntRect&, const IntSize& destOffset = IntSize());
 
-void writeImageToDiskAsPNG(ID2D1RenderTarget*, ID2D1Bitmap*, LPCWSTR fileName);
+void writeDiagnosticPNGToPath(ID2D1RenderTarget*, ID2D1Bitmap*, LPCWSTR fileName);
 
 } // namespace Direct2D
 
index d3e477e..6e4fbeb 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "COMPtr.h"
 #include "Direct2DOperations.h"
+#include "Direct2DUtilities.h"
 #include "DisplayListRecorder.h"
 #include "FloatRoundedRect.h"
 #include "GraphicsContextPlatformPrivateDirect2D.h"
@@ -54,9 +55,7 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
 GraphicsContext::GraphicsContext(HDC hdc, ID2D1DCRenderTarget** renderTarget, RECT rect, bool hasAlpha)
 {
     // Create a DC render target.
-    auto targetProperties = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
-        D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
-        0, 0, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT);
+    auto targetProperties = Direct2D::renderTargetProperties();
 
     HRESULT hr = GraphicsContext::systemFactory()->CreateDCRenderTarget(&targetProperties, renderTarget);
     RELEASE_ASSERT(SUCCEEDED(hr));
@@ -99,6 +98,7 @@ ID2D1RenderTarget* GraphicsContext::defaultRenderTarget()
         auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(::GetDesktopWindow(), D2D1::SizeU(10, 10));
         HRESULT hr = systemFactory()->CreateHwndRenderTarget(&renderTargetProperties, &hwndRenderTargetProperties, reinterpret_cast<ID2D1HwndRenderTarget**>(&defaultRenderTarget));
         RELEASE_ASSERT(SUCCEEDED(hr));
+        defaultRenderTarget->AddRef();
     }
 
     return defaultRenderTarget;
@@ -113,8 +113,7 @@ void GraphicsContext::platformInit(HDC hdc, bool hasAlpha)
 
     DIBPixelData pixelData(bitmap);
 
-    auto targetProperties = D2D1::RenderTargetProperties();
-    targetProperties.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED);
+    auto targetProperties = Direct2D::renderTargetProperties();
 
     COMPtr<ID2D1DCRenderTarget> renderTarget;
     HRESULT hr = systemFactory()->CreateDCRenderTarget(&targetProperties, &renderTarget);
@@ -208,7 +207,7 @@ void GraphicsContext::restorePlatformState()
     Direct2D::restore(*platformContext());
 }
 
-void GraphicsContext::drawNativeImage(const COMPtr<IWICBitmap>& image, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOperator, BlendMode blendMode, ImageOrientation orientation)
+void GraphicsContext::drawNativeImage(const COMPtr<ID2D1Bitmap>& image, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOperator, BlendMode blendMode, ImageOrientation orientation)
 {
     if (paintingDisabled())
         return;
@@ -240,7 +239,7 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
     DIBPixelData pixelData(sourceBitmap.get());
     ASSERT(pixelData.bitsPerPixel() == 32);
 
-    auto bitmapProperties = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED));
+    auto bitmapProperties = Direct2D::bitmapProperties();
 
     ASSERT(hasPlatformContext());
     auto& platformContext = *this->platformContext();
@@ -435,8 +434,8 @@ void GraphicsContext::drawPattern(Image& image, const FloatRect& destRect, const
     }
 
     ASSERT(hasPlatformContext());
-    if (auto tileImage = image.nativeImageForCurrentFrame())
-        Direct2D::drawPattern(*platformContext(), tileImage.get(), IntSize(image.size()), destRect, tileRect, patternTransform, phase, compositeOperator, blendMode);
+    if (auto tileImage = image.nativeImageForCurrentFrame(this))
+        Direct2D::drawPattern(*platformContext(), WTFMove(tileImage), IntSize(image.size()), destRect, tileRect, patternTransform, phase, compositeOperator, blendMode);
 }
 
 void GraphicsContext::clipToImageBuffer(ImageBuffer& buffer, const FloatRect& destRect)
index 1ebb5b0..1d1e7e6 100644 (file)
@@ -291,8 +291,9 @@ void GraphicsContextImplDirect2D::drawNativeImage(const NativeImagePtr& image, c
 
 void GraphicsContextImplDirect2D::drawPattern(Image& image, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize&, CompositeOperator compositeOperator, BlendMode blendMode)
 {
-    if (auto surface = image.nativeImageForCurrentFrame())
-        Direct2D::drawPattern(m_platformContext, surface.get(), IntSize(image.size()), destRect, tileRect, patternTransform, phase, compositeOperator, blendMode);
+    auto* context = &graphicsContext();
+    if (auto surface = image.nativeImageForCurrentFrame(context))
+        Direct2D::drawPattern(m_platformContext, WTFMove(surface), IntSize(image.size()), destRect, tileRect, patternTransform, phase, compositeOperator, blendMode);
 }
 
 void GraphicsContextImplDirect2D::drawRect(const FloatRect& rect, float borderThickness)
@@ -421,8 +422,8 @@ void GraphicsContextImplDirect2D::clipToImageBuffer(ImageBuffer& buffer, const F
     if (!image)
         return;
 
-
-    if (auto surface = image->nativeImageForCurrentFrame())
+    auto* context = &graphicsContext();
+    if (auto surface = image->nativeImageForCurrentFrame(context))
         notImplemented();
 }
 
index f324db0..fbf98f6 100644 (file)
 #if USE(DIRECT2D)
 
 #include "BitmapInfo.h"
+#include "Direct2DUtilities.h"
 #include "GraphicsContext.h"
 #include "HWndDC.h"
 #include "IntRect.h"
 #include "NotImplemented.h"
+#include "PlatformContextDirect2D.h"
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/TypedArrayInlines.h>
 #include <JavaScriptCore/Uint8ClampedArray.h>
 
 namespace WebCore {
 
-RefPtr<Uint8ClampedArray> ImageBufferData::getData(AlphaPremultiplication, const IntRect& rect, const IntSize& size, bool /* accelerateRendering */, float /* resolutionScale */) const
+// Swizzle the red and blue bytes of the pixels in a buffer
+template <AlphaPremultiplication desiredFormat>
+void swizzleAndPremultiply(const uint8_t* srcRows, unsigned rowCount, unsigned colCount, unsigned srcStride, unsigned destStride, uint8_t* destRows)
+{
+    for (unsigned y = 0; y < rowCount; ++y) {
+        // Source data may be power-of-two sized, so we need to only copy the bits that
+        // correspond to the rectangle supplied by the caller.
+        const uint32_t* srcRow = reinterpret_cast<const uint32_t*>(srcRows + srcStride * y);
+        uint8_t* destRow = destRows + destStride * y;
+        for (unsigned x = 0; x < colCount; ++x) {
+            unsigned bytePosition = x * 4;
+            const uint32_t* srcPixel = srcRow + x;
+
+            // Software filters expect (P)RGBA bytes. We need to swizzle from Direct2D's PBGRA to be compatible.
+            uint32_t alpha = (*srcPixel & 0xFF000000) >> 24;
+            uint32_t red = (*srcPixel & 0x00FF0000) >> 16;
+            uint32_t green = (*srcPixel & 0x0000FF00) >> 8;
+            uint32_t blue = (*srcPixel & 0x000000FF);
+
+            if (desiredFormat == AlphaPremultiplication::Unpremultiplied) {
+                if (alpha && alpha != 255) {
+                    red = red * 255 / alpha;
+                    green = green * 255 / alpha;
+                    blue = blue * 255 / alpha;
+                }
+            }
+
+            destRow[bytePosition]     = red;
+            destRow[bytePosition + 1] = green;
+            destRow[bytePosition + 2] = blue;
+            destRow[bytePosition + 3] = alpha;
+        }
+    }
+}
+
+RefPtr<Uint8ClampedArray> ImageBufferData::getData(AlphaPremultiplication desiredFormat, const IntRect& rect, const IntSize& size, bool /* accelerateRendering */, float /* resolutionScale */) const
 {
     auto numBytes = rect.area<RecordOverflow>() * 4;
     if (numBytes.hasOverflowed())
@@ -53,29 +90,81 @@ RefPtr<Uint8ClampedArray> ImageBufferData::getData(AlphaPremultiplication, const
     if (!resultData)
         return nullptr;
 
-    WICRect rcLock = { 0, 0, rect.width(), rect.height() };
+    if (!bitmap)
+        return result;
 
-    // We cannot access the data backing an IWICBitmap while an active draw session is open.
     context->endDraw();
 
-    COMPtr<IWICBitmapLock> bitmapDataLock;
-    HRESULT hr = bitmapSource->Lock(&rcLock, WICBitmapLockRead, &bitmapDataLock);
-    if (SUCCEEDED(hr)) {
-        UINT bufferSize = 0;
-        WICInProcPointer dataPtr = nullptr;
-        hr = bitmapDataLock->GetDataPointer(&bufferSize, &dataPtr);
-        if (SUCCEEDED(hr))
-            memcpy(result->data(), reinterpret_cast<char*>(dataPtr), numBytes.unsafeGet());
-    }
+    COMPtr<ID2D1DeviceContext> d2dDeviceContext;
+    HRESULT hr = platformContext->renderTarget()->QueryInterface(__uuidof(ID2D1DeviceContext), reinterpret_cast<void**>(&d2dDeviceContext));
+    ASSERT(SUCCEEDED(hr));
 
-    // Once we are done modifying the data, unlock the bitmap
-    bitmapDataLock = nullptr;
+    auto bytesPerRowInData = size.width() * 4;
+
+    COMPtr<ID2D1Bitmap1> cpuBitmap;
+    D2D1_BITMAP_PROPERTIES1 bitmapProperties2 = D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_CPU_READ | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, Direct2D::pixelFormat());
+    hr = d2dDeviceContext->CreateBitmap(size, nullptr, bytesPerRowInData, bitmapProperties2, &cpuBitmap);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    D2D1_POINT_2U targetPos = D2D1::Point2U();
+    D2D1_RECT_U dataRect = rect;
+    hr = cpuBitmap->CopyFromBitmap(&targetPos, bitmap.get(), &dataRect);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    D2D1_MAPPED_RECT mappedData;
+    hr = cpuBitmap->Map(D2D1_MAP_OPTIONS_READ, &mappedData);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    // Software filters expect RGBA bytes. We need to swizzle from Direct2D's BGRA to be compatible.
+    Checked<int> height = rect.height();
+    Checked<int> width = rect.width();
+
+    if (desiredFormat == AlphaPremultiplication::Unpremultiplied)
+        swizzleAndPremultiply<AlphaPremultiplication::Unpremultiplied>(mappedData.bits, height.unsafeGet(), width.unsafeGet(), mappedData.pitch, bytesPerRowInData, resultData);
+    else
+        swizzleAndPremultiply<AlphaPremultiplication::Premultiplied>(mappedData.bits, height.unsafeGet(), width.unsafeGet(), mappedData.pitch, bytesPerRowInData, resultData);
+
+    hr = cpuBitmap->Unmap();
+    ASSERT(SUCCEEDED(hr));
 
     context->beginDraw();
 
     return result;
 }
 
+// Swizzle the red and blue bytes of the pixels in a buffer
+template <AlphaPremultiplication sourceFormat>
+void inPlaceSwizzle(uint8_t* byteData, unsigned byteCount)
+{
+    size_t pixelCount = byteCount / 4;
+    auto* pixelData = reinterpret_cast<uint32_t*>(byteData);
+
+    for (size_t i = 0; i < pixelCount; ++i) {
+        uint32_t pixel = *pixelData;
+        size_t bytePosition = i * 4;
+
+        uint32_t alpha = (pixel & 0xFF000000) >> 24;
+        uint32_t red = (pixel & 0x00FF0000) >> 16;
+        uint32_t green = (pixel & 0x0000FF00) >> 8;
+        uint32_t blue = (pixel & 0x000000FF);
+
+        // (P)RGBA -> PBGRA
+        if (sourceFormat == AlphaPremultiplication::Unpremultiplied) {
+            if (alpha != 255) {
+                red = (red * alpha + 254) / 255;
+                green = (green * alpha + 254) / 255;
+                blue = (blue * alpha + 254) / 255;
+            }
+        }
+
+        *pixelData = (alpha << 24) | red  << 16 | green  << 8 | blue;
+        ++pixelData;
+    }
+}
+
 void ImageBufferData::putData(const Uint8ClampedArray& source, AlphaPremultiplication sourceFormat, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool /* accelerateRendering */, float resolutionScale)
 {
     ASSERT(sourceRect.width() > 0);
@@ -114,59 +203,99 @@ void ImageBufferData::putData(const Uint8ClampedArray& source, AlphaPremultiplic
     if (width <= 0 || height <= 0)
         return;
 
-    // We cannot access the data backing an IWICBitmap while an active draw session is open.
     context->endDraw();
 
-    WICRect rcLock = { 0, 0, sourceSize.width(), sourceSize.height() };
+    auto pixelSize = bitmap->GetPixelSize();
+    ASSERT(pixelSize.width >= sourceSize.width());
+    ASSERT(pixelSize.width >= size.width());
+    ASSERT(pixelSize.height >= sourceSize.height());
+    ASSERT(pixelSize.height >= size.height());
 
-    COMPtr<IWICBitmapLock> bitmapDataLock;
-    HRESULT hr = bitmapSource->Lock(&rcLock, WICBitmapLockWrite, &bitmapDataLock);
-    if (!SUCCEEDED(hr))
-        return;
+    // Software generated bitmap data is in RGBA. We need to swizzle to premultiplied BGRA to be compatible
+    // with the HWND/HDC render backing we use.
+    if (sourceFormat == AlphaPremultiplication::Unpremultiplied)
+        inPlaceSwizzle<AlphaPremultiplication::Unpremultiplied>(source.data(), source.length()); // RGBA -> PBGRA
+    else
+        inPlaceSwizzle<AlphaPremultiplication::Premultiplied>(source.data(), source.length()); // PRGBA -> PBGRA
 
-    UINT stride = 0;
-    hr = bitmapDataLock->GetStride(&stride);
-    if (!SUCCEEDED(hr))
-        return;
+    COMPtr<ID2D1BitmapRenderTarget> bitmapRenderTarget;
+    HRESULT hr = platformContext->renderTarget()->QueryInterface(__uuidof(ID2D1BitmapRenderTarget), reinterpret_cast<void**>(&bitmapRenderTarget));
+    ASSERT(SUCCEEDED(hr));
+
+    auto bytesPerRowInData = sourceRect.width() * 4;
 
-    UINT bufferSize = 0;
-    WICInProcPointer dataPtr = nullptr;
-    hr = bitmapDataLock->GetDataPointer(&bufferSize, &dataPtr);
+    COMPtr<ID2D1Bitmap> swizzledBitmap;
+    D2D1_BITMAP_PROPERTIES bitmapProperties = D2D1::BitmapProperties(Direct2D::pixelFormat());
+    hr = bitmapRenderTarget->CreateBitmap(sourceSize, source.data(), bytesPerRowInData, bitmapProperties, &swizzledBitmap);
     if (!SUCCEEDED(hr))
         return;
 
-    ASSERT(bufferSize == source.byteLength());
+    D2D1_POINT_2U destPointD2D = destPoint;
+    D2D1_RECT_U srcRect = sourceRect;
+    hr = bitmap->CopyFromMemory(&srcRect, source.data(), bytesPerRowInData);
+    ASSERT(SUCCEEDED(hr));
 
-    unsigned srcBytesPerRow = 4 * sourceSize.width();
+    context->beginDraw();
+}
 
-    ASSERT(srcBytesPerRow == stride);
+COMPtr<ID2D1Bitmap> ImageBufferData::compatibleBitmap(ID2D1RenderTarget* renderTarget)
+{
+    if (!renderTarget)
+        return bitmap;
 
-    const uint8_t* srcRows = source.data() + (originy * srcBytesPerRow + originx * 4).unsafeGet();
+    if (platformContext->renderTarget() == renderTarget)
+        return bitmap;
 
-    auto row = makeUniqueArray<uint8_t>(srcBytesPerRow);
+    auto size = bitmap->GetPixelSize();
 
-    for (int y = 0; y < height.unsafeGet(); ++y) {
-        for (int x = 0; x < width.unsafeGet(); x++) {
-            int basex = x * 4;
-            uint8_t alpha = srcRows[basex + 3];
-            if (sourceFormat == AlphaPremultiplication::Unpremultiplied && alpha != 255) {
-                row[basex] = (srcRows[basex] * alpha + 254) / 255;
-                row[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255;
-                row[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255;
-                row[basex + 3] = alpha;
-            } else
-                reinterpret_cast<uint32_t*>(row.get() + basex)[0] = reinterpret_cast<const uint32_t*>(srcRows + basex)[0];
-        }
+    Checked<unsigned, RecordOverflow> numBytes = size.width * size.height * 4;
+    if (numBytes.hasOverflowed())
+        return nullptr;
 
-        memcpy(reinterpret_cast<char*>(dataPtr + y * srcBytesPerRow), row.get(), srcBytesPerRow);
+    // Copy the bits from current renderTarget to the output target.
+    // We cannot access the data backing an IWICBitmap while an active draw session is open.
+    context->endDraw();
 
-        srcRows += srcBytesPerRow;
-    }
+    COMPtr<ID2D1DeviceContext> sourceDeviceContext;
+    HRESULT hr = platformContext->renderTarget()->QueryInterface(__uuidof(ID2D1DeviceContext), reinterpret_cast<void**>(&sourceDeviceContext));
+    ASSERT(SUCCEEDED(hr));
 
-    // Once we are done modifying the data, unlock the bitmap
-    bitmapDataLock = nullptr;
+    if (!sourceDeviceContext)
+        return nullptr;
+
+    COMPtr<ID2D1Bitmap1> sourceCPUBitmap;
+    D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_CPU_READ | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, Direct2D::pixelFormat());
+    hr = sourceDeviceContext->CreateBitmap(bitmap->GetPixelSize(), nullptr, bytesPerRow.unsafeGet(), bitmapProperties, &sourceCPUBitmap);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    if (!sourceCPUBitmap)
+        return nullptr;
+
+    hr = sourceCPUBitmap->CopyFromBitmap(nullptr, bitmap.get(), nullptr);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    D2D1_MAPPED_RECT mappedSourceData;
+    hr = sourceCPUBitmap->Map(D2D1_MAP_OPTIONS_READ, &mappedSourceData);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    COMPtr<ID2D1DeviceContext> targetDeviceContext;
+    hr = renderTarget->QueryInterface(__uuidof(ID2D1DeviceContext), reinterpret_cast<void**>(&targetDeviceContext));
+    ASSERT(SUCCEEDED(hr));
+
+    COMPtr<ID2D1Bitmap> compatibleBitmap;
+    hr = targetDeviceContext->CreateBitmap(bitmap->GetPixelSize(), mappedSourceData.bits, mappedSourceData.pitch, Direct2D::bitmapProperties(), &compatibleBitmap);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    hr = sourceCPUBitmap->Unmap();
+    ASSERT(SUCCEEDED(hr));
 
     context->beginDraw();
+
+    return compatibleBitmap;
 }
 
 } // namespace WebCore
index 00d399a..2424d06 100644 (file)
@@ -32,6 +32,9 @@
 #include <wtf/RefPtr.h>
 #include <wtf/RetainPtr.h>
 
+interface ID2D1RenderTarget;
+interface ID2D1Bitmap;
+
 namespace WebCore {
 
 class PlatformContextDirect2D;
@@ -44,10 +47,12 @@ struct ImageBufferData {
     Vector<char> data;
     std::unique_ptr<PlatformContextDirect2D> platformContext;
     std::unique_ptr<GraphicsContext> context;
-    COMPtr<IWICBitmap> bitmapSource;
+    COMPtr<ID2D1Bitmap> bitmap;
 
     RefPtr<Uint8ClampedArray> getData(AlphaPremultiplication, const IntRect&, const IntSize&, bool accelerateRendering, float resolutionScale) const;
     void putData(const Uint8ClampedArray& source, AlphaPremultiplication sourceFormat, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize&, bool accelerateRendering, float resolutionScale);
+
+    COMPtr<ID2D1Bitmap> compatibleBitmap(ID2D1RenderTarget*);
 };
 
 } // namespace WebCore
index 35a9ff6..f0bb96e 100644 (file)
@@ -38,7 +38,7 @@
 #include "MIMETypeRegistry.h"
 #include "NotImplemented.h"
 #include "PlatformContextDirect2D.h"
-#include <d2d1.h>
+#include <d2d1_1.h>
 #include <math.h>
 #include <wincodec.h>
 #include <wtf/Assertions.h>
@@ -76,7 +76,7 @@ std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize
     return buffer;
 }
 
-ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpace /*colorSpace*/, RenderingMode renderingMode, const HostWindow*, const GraphicsContext*, bool& success)
+ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpace /*colorSpace*/, RenderingMode renderingMode, const HostWindow*, const GraphicsContext* targetContext, bool& success)
     : m_logicalSize(size)
     , m_resolutionScale(resolutionScale)
 {
@@ -101,17 +101,23 @@ ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpac
     if (numBytes.hasOverflowed())
         return;
 
-    m_data.data = Vector<char>(numBytes.unsafeGet(), 0);
+    auto* platformContext = targetContext ? targetContext->platformContext() : nullptr;
+    auto* renderTarget = platformContext ? platformContext->renderTarget() : nullptr;
 
-    m_data.bitmapSource = Direct2D::createDirect2DImageSurfaceWithData(m_data.data.data(), m_size, m_data.bytesPerRow.unsafeGet());
-    if (!m_data.bitmapSource)
-        return;
+    if (!renderTarget)
+        renderTarget = GraphicsContext::defaultRenderTarget();
+
+    D2D1_SIZE_F desiredSize = FloatSize(m_logicalSize);
+    D2D1_SIZE_U pixelSize = IntSize(m_logicalSize);
 
-    COMPtr<ID2D1RenderTarget> bitmapContext = Direct2D::createRenderTargetFromWICBitmap(m_data.bitmapSource.get());
+    auto bitmapContext = Direct2D::createBitmapRenderTargetOfSize(m_logicalSize, renderTarget);
     if (!bitmapContext)
         return;
 
-    // Note: This places the bitmapcontext into a locked state because of the BeginDraw call in the constructor.
+    HRESULT hr = bitmapContext->GetBitmap(&m_data.bitmap);
+    if (!SUCCEEDED(hr))
+        return;
+
     m_data.platformContext = makeUnique<PlatformContextDirect2D>(bitmapContext.get());
     m_data.context = makeUnique<GraphicsContext>(m_data.platformContext.get(), GraphicsContext::BitmapRenderingContextType::GPUMemory);
 
@@ -140,34 +146,27 @@ void ImageBuffer::flushContext() const
     context().flush();
 }
 
-static COMPtr<IWICBitmap> createCroppedImageIfNecessary(IWICBitmap* image, const IntSize& bounds)
+static COMPtr<ID2D1Bitmap> createCroppedImageIfNecessary(ID2D1BitmapRenderTarget* bitmapTarget, ID2D1Bitmap* image, const IntSize& bounds)
 {
     FloatSize imageSize = image ? nativeImageSize(image) : FloatSize();
 
     if (image && (static_cast<size_t>(imageSize.width()) != static_cast<size_t>(bounds.width()) || static_cast<size_t>(imageSize.height()) != static_cast<size_t>(bounds.height()))) {
-        D2D_POINT_2U origin = { };
-        WICRect croppedDimensions = { 0, 0, bounds.width(), bounds.height() };
-
-        COMPtr<IWICBitmapClipper> bitmapClipper;
-        HRESULT hr = ImageDecoderDirect2D::systemImagingFactory()->CreateBitmapClipper(&bitmapClipper);
-        if (SUCCEEDED(hr)) {
-            hr = bitmapClipper->Initialize(image, &croppedDimensions);
-            if (SUCCEEDED(hr)) {
-                COMPtr<IWICBitmap> croppedBitmap;
-                hr = ImageDecoderDirect2D::systemImagingFactory()->CreateBitmapFromSource(image, WICBitmapNoCache, &croppedBitmap);
-                if (SUCCEEDED(hr))
-                    return croppedBitmap;
-            }
+        COMPtr<ID2D1Bitmap> croppedBitmap = Direct2D::createBitmap(bitmapTarget, bounds);
+        if (croppedBitmap) {
+            auto sourceRect = D2D1::RectU(0, 0, bounds.width(), bounds.height());
+            HRESULT hr = croppedBitmap->CopyFromBitmap(nullptr, image, &sourceRect);
+            if (SUCCEEDED(hr))
+                return croppedBitmap;
         }
     }
 
     return image;
 }
 
-static RefPtr<Image> createBitmapImageAfterScalingIfNeeded(COMPtr<IWICBitmap>&& image, IntSize internalSize, IntSize logicalSize, IntSize backingStoreSize, float resolutionScale, PreserveResolution preserveResolution)
+static RefPtr<Image> createBitmapImageAfterScalingIfNeeded(ID2D1BitmapRenderTarget* bitmapTarget, COMPtr<ID2D1Bitmap>&& image, IntSize internalSize, IntSize logicalSize, IntSize backingStoreSize, float resolutionScale, PreserveResolution preserveResolution)
 {
     if (resolutionScale == 1 || preserveResolution == PreserveResolution::Yes)
-        image = createCroppedImageIfNecessary(image.get(), internalSize);
+        image = createCroppedImageIfNecessary(bitmapTarget, image.get(), internalSize);
     else {
         // FIXME: Need to implement scaled version
         notImplemented();
@@ -181,13 +180,14 @@ static RefPtr<Image> createBitmapImageAfterScalingIfNeeded(COMPtr<IWICBitmap>&&
 
 RefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, PreserveResolution preserveResolution) const
 {
-    COMPtr<IWICBitmap> image;
+    COMPtr<ID2D1Bitmap> image;
     if (m_resolutionScale == 1 || preserveResolution == PreserveResolution::Yes)
         image = copyNativeImage(copyBehavior);
     else
         image = copyNativeImage(DontCopyBackingStore);
 
-    return createBitmapImageAfterScalingIfNeeded(WTFMove(image), internalSize(), logicalSize(), m_data.backingStoreSize, m_resolutionScale, preserveResolution);
+    auto bitmapTarget = reinterpret_cast<ID2D1BitmapRenderTarget*>(context().platformContext());
+    return createBitmapImageAfterScalingIfNeeded(bitmapTarget, WTFMove(image), internalSize(), logicalSize(), m_data.backingStoreSize, m_resolutionScale, preserveResolution);
 }
 
 RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffer, PreserveResolution preserveResolution)
@@ -197,7 +197,8 @@ RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffe
     IntSize backingStoreSize = imageBuffer->m_data.backingStoreSize;
     float resolutionScale = imageBuffer->m_resolutionScale;
 
-    return createBitmapImageAfterScalingIfNeeded(sinkIntoNativeImage(WTFMove(imageBuffer)), internalSize, logicalSize, backingStoreSize, resolutionScale, preserveResolution);
+    auto bitmapTarget = reinterpret_cast<ID2D1BitmapRenderTarget*>(imageBuffer->context().platformContext()->renderTarget());
+    return createBitmapImageAfterScalingIfNeeded(bitmapTarget, sinkIntoNativeImage(WTFMove(imageBuffer)), internalSize, logicalSize, backingStoreSize, resolutionScale, preserveResolution);
 }
 
 BackingStoreCopy ImageBuffer::fastCopyImageMode()
@@ -205,14 +206,20 @@ BackingStoreCopy ImageBuffer::fastCopyImageMode()
     return DontCopyBackingStore;
 }
 
-COMPtr<IWICBitmap> ImageBuffer::sinkIntoNativeImage(std::unique_ptr<ImageBuffer> imageBuffer)
+COMPtr<ID2D1Bitmap> ImageBuffer::sinkIntoNativeImage(std::unique_ptr<ImageBuffer> imageBuffer)
 {
     // FIXME: See if we can reuse the on-hardware image.
     return imageBuffer->copyNativeImage(DontCopyBackingStore);
 }
 
-COMPtr<IWICBitmap> ImageBuffer::copyNativeImage(BackingStoreCopy copyBehavior) const
+COMPtr<ID2D1Bitmap> ImageBuffer::copyNativeImage(BackingStoreCopy copyBehavior) const
 {
+    auto bitmapTarget = reinterpret_cast<ID2D1BitmapRenderTarget*>(context().platformContext());
+
+    COMPtr<ID2D1Bitmap> image;
+    HRESULT hr = bitmapTarget->GetBitmap(&image);
+    ASSERT(SUCCEEDED(hr));
+
     // FIXME: m_data.data is nullptr even when asking to copy backing store leading to test failures.
     if (copyBehavior == CopyBackingStore && m_data.data.isEmpty())
         copyBehavior = DontCopyBackingStore;
@@ -221,15 +228,13 @@ COMPtr<IWICBitmap> ImageBuffer::copyNativeImage(BackingStoreCopy copyBehavior) c
     if (numBytes.hasOverflowed())
         return nullptr;
 
-    HRESULT hr = S_OK;
-    COMPtr<IWICBitmap> image;
     if (!context().isAcceleratedContext()) {
         switch (copyBehavior) {
         case DontCopyBackingStore:
-            hr = ImageDecoderDirect2D::systemImagingFactory()->CreateBitmapFromSource(m_data.bitmapSource.get(), WICBitmapNoCache, &image);
             break;
         case CopyBackingStore:
-            hr = ImageDecoderDirect2D::systemImagingFactory()->CreateBitmapFromSource(m_data.bitmapSource.get(), WICBitmapCacheOnDemand, &image);
+            D2D1_RECT_U backingStoreDimenstions = IntRect(IntPoint(), m_data.backingStoreSize);
+            image->CopyFromMemory(&backingStoreDimenstions, m_data.data.data(), 32);
             break;
         default:
             ASSERT_NOT_REACHED();
@@ -254,16 +259,13 @@ void ImageBuffer::draw(GraphicsContext& destContext, const FloatRect& destRect,
     FloatRect adjustedSrcRect = srcRect;
     adjustedSrcRect.scale(m_resolutionScale, m_resolutionScale);
 
-    FloatSize currentImageSize = nativeImageSize(m_data.bitmapSource);
-
-    // You can't convert a IWICBitmap to a ID2D1Bitmap with an active GraphicsContext attached to it.
-    m_data.context->endDraw();
+    auto compatibleBitmap = m_data.compatibleBitmap(destContext.platformContext()->renderTarget());
 
-    destContext.drawNativeImage(m_data.bitmapSource, currentImageSize, destRect, adjustedSrcRect, op, blendMode);
-
-    m_data.context->beginDraw();
+    FloatSize currentImageSize = nativeImageSize(compatibleBitmap);
+    if (currentImageSize.isZero())
+        return;
 
-    destContext.flush();
+    destContext.drawNativeImage(compatibleBitmap, currentImageSize, destRect, adjustedSrcRect, op, blendMode);
 }
 
 void ImageBuffer::drawPattern(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode)
index 1fe5ac0..be5ae20 100644 (file)
@@ -239,6 +239,9 @@ NativeImagePtr ImageDecoderDirect2D::createFrameImageAtIndex(size_t index, Subsa
     if (!m_nativeDecoder)
         return nullptr;
 
+    if (!m_renderTarget)
+        return nullptr;
+
     COMPtr<IWICBitmapFrameDecode> frame;
     HRESULT hr = m_nativeDecoder->GetFrame(0, &frame);
     if (!SUCCEEDED(hr))
@@ -253,8 +256,13 @@ NativeImagePtr ImageDecoderDirect2D::createFrameImageAtIndex(size_t index, Subsa
     if (!SUCCEEDED(hr))
         return nullptr;
 
-    COMPtr<IWICBitmap> bitmap;
-    hr = systemImagingFactory()->CreateBitmapFromSource(converter.get(), WICBitmapCacheOnDemand, &bitmap);
+    COMPtr<IWICBitmap> wicBitmap;
+    hr = systemImagingFactory()->CreateBitmapFromSource(converter.get(), WICBitmapCacheOnDemand, &wicBitmap);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    COMPtr<ID2D1Bitmap> bitmap;
+    hr = m_renderTarget->CreateBitmapFromWicBitmap(wicBitmap.get(), &bitmap);
     if (!SUCCEEDED(hr))
         return nullptr;
 
@@ -286,6 +294,7 @@ void ImageDecoderDirect2D::setData(SharedBuffer& data, bool allDataReceived)
 
     // Image was valid.
 }
+
 }
 
 #endif
index 4e4d88d..df4c539 100644 (file)
@@ -56,11 +56,7 @@ IntSize nativeImageSize(const NativeImagePtr& image)
     if (!image)
         return { };
 
-    HRESULT hr = image->GetSize(&width, &height);
-    if (!SUCCEEDED(hr))
-        return { };
-
-    return IntSize(width, height);
+    return image->GetPixelSize();
 }
 
 bool nativeImageHasAlpha(const NativeImagePtr& image)
@@ -68,28 +64,8 @@ bool nativeImageHasAlpha(const NativeImagePtr& image)
     if (!image)
         return false;
 
-    WICPixelFormatGUID pixelFormatGUID = { };
-    HRESULT hr = image->GetPixelFormat(&pixelFormatGUID);
-    if (!SUCCEEDED(hr))
-        return false;
-
-    // FIXME: Should we just check the pixelFormatGUID for relevant ID's we use?
-
-    COMPtr<IWICComponentInfo> componentInfo;
-    hr = imagingFactory()->CreateComponentInfo(pixelFormatGUID, &componentInfo);
-    if (!SUCCEEDED(hr))
-        return false;
-
-    COMPtr<IWICPixelFormatInfo> pixelFormatInfo(Query, componentInfo.get());
-    if (!pixelFormatInfo)
-        return false;
-
-    UINT channelCount = 0;
-    hr = pixelFormatInfo->GetChannelCount(&channelCount);
-    if (!SUCCEEDED(hr))
-        return false;
-
-    return channelCount > 3;
+    D2D1_PIXEL_FORMAT pixelFormat = image->GetPixelFormat();
+    return pixelFormat.alphaMode != D2D1_ALPHA_MODE_IGNORE;
 }
 
 Color nativeImageSinglePixelSolidColor(const NativeImagePtr& image)
@@ -116,13 +92,7 @@ void drawNativeImage(const NativeImagePtr& image, GraphicsContext& context, cons
 
     float opacity = 1.0f;
 
-    COMPtr<ID2D1Bitmap> bitmap;
-    HRESULT hr = platformContext->renderTarget()->CreateBitmapFromWicBitmap(image.get(), &bitmap);
-    if (!SUCCEEDED(hr))
-        return;
-
-    platformContext->renderTarget()->DrawBitmap(bitmap.get(), destRect, opacity, D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, adjustedSrcRect);
-    context.flush();
+    platformContext->renderTarget()->DrawBitmap(image.get(), destRect, opacity, D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, adjustedSrcRect);
 }
 
 void clearNativeImageSubimages(const NativeImagePtr& image)
index 328bbcd..b2b018d 100644 (file)
@@ -59,13 +59,8 @@ ID2D1BitmapBrush* Pattern::createPlatformPattern(PlatformGraphicsContext& contex
     auto& patternImage = tileImage();
     auto nativeImage = patternImage.nativeImage(nullptr);
 
-    COMPtr<ID2D1Bitmap> bitmap;
-    HRESULT hr = context.renderTarget()->CreateBitmapFromWicBitmap(nativeImage.get(), &bitmap);
-    if (!SUCCEEDED(hr))
-        return nullptr;
-
     ID2D1BitmapBrush* patternBrush = nullptr;
-    hr = context.renderTarget()->CreateBitmapBrush(bitmap.get(), &bitmapBrushProperties, &brushProperties, &patternBrush);
+    HRESULT hr = context.renderTarget()->CreateBitmapBrush(nativeImage.get(), &bitmapBrushProperties, &brushProperties, &patternBrush);
     ASSERT(SUCCEEDED(hr));
     return patternBrush;
 }
index 5c56b69..6bd9124 100644 (file)
@@ -69,6 +69,7 @@
 #if USE(DIRECT2D)
 #include "COMPtr.h"
 #include "Direct2DUtilities.h"
+#include "GraphicsContext.h"
 #include "ImageDecoderDirect2D.h"
 #include "PlatformContextDirect2D.h"
 #include <d2d1.h>
@@ -235,12 +236,11 @@ NativeImagePtr SVGImage::nativeImage(const GraphicsContext* targetContext)
     if (!m_page || !targetContext)
         return nullptr;
 
-    COMPtr<IWICBitmap> nativeImage;
-    HRESULT hr = ImageDecoderDirect2D::systemImagingFactory()->CreateBitmap(rect().width(), rect().height(), GUID_WICPixelFormat32bppPRGBA, WICBitmapCacheOnLoad, &nativeImage);
-    if (!SUCCEEDED(hr))
-        return nullptr;
+    ASSERT(targetContext->hasPlatformContext());
+    auto* renderTarget = targetContext->platformContext()->renderTarget();
 
-    COMPtr<ID2D1RenderTarget> nativeImageTarget = Direct2D::createRenderTargetFromWICBitmap(nativeImage.get());
+    IntSize bitmapSize(size().width(), size().height());
+    auto nativeImageTarget = Direct2D::createBitmapRenderTargetOfSize(bitmapSize, renderTarget, 1.0);
     if (!nativeImageTarget)
         return nullptr;
 
@@ -249,6 +249,17 @@ NativeImagePtr SVGImage::nativeImage(const GraphicsContext* targetContext)
 
     draw(localContext, rect(), rect(), CompositeSourceOver, BlendMode::Normal, DecodingMode::Synchronous, ImageOrientation::None);
 
+    COMPtr<ID2D1Bitmap> nativeImage;
+    HRESULT hr = nativeImageTarget->GetBitmap(&nativeImage);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+#if !ASSERT_DISABLED
+    auto nativeImageSize = nativeImage->GetPixelSize();
+    ASSERT(nativeImageSize.height = rect().size().height());
+    ASSERT(nativeImageSize.width = rect().size().width());
+#endif
+
     return nativeImage;
 }
 #endif
index 8121fcf..2fe5db5 100644 (file)
@@ -1,3 +1,28 @@
+2019-08-26  Brent Fulgham  <bfulgham@apple.com>
+
+        [FTW] Go back to ID2D1Bitmap as our NativeImage type
+        https://bugs.webkit.org/show_bug.cgi?id=201122
+
+        Reviewed by Alex Christensen.
+
+        In Bug 200093 I switched the OS type of NativeImagePtr from ID2D1Bitmap to IWICBitmap.
+        However, this was an ill-advised approach, because it dramatically harmed performance due
+        to the heavy use of software rendering.
+
+        I originally made this change because I thought this was the only way to get to the backing
+        bits of the bitmaps, but it turns out that a more recent Direct2D data type (ID2D1Bitmap1)
+        has the ability to map its memory to CPU-accessible memory, allowing software filter effects.
+
+        This patch switches back to the ID2D1Bitap data type, and hooks up the ID2D1Bitmap1 data type
+        to access the underlying memory of the bitmaps when software filter effects are used.
+
+        Reviewed by Alex Christensen.
+
+        * Shared/ShareableBitmap.h:
+        * Shared/win/ShareableBitmapDirect2D.cpp:
+        * UIProcess/win/BackingStoreDirect2D.cpp:
+        * WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp:
+
 2019-08-26  Jiewen Tan  <jiewen_tan@apple.com>
 
         [WebAuthn] Support HID authenticators on iOS
index 5820282..fea9ca9 100644 (file)
@@ -40,7 +40,8 @@
 #endif
 
 #if USE(DIRECT2D)
-interface IWICBitmap;
+interface ID2D1Bitmap;
+interface ID2D1RenderTarget;
 
 #include <WebCore/COMPtr.h>
 #endif
@@ -131,7 +132,7 @@ public:
     // This is only safe to use when we know that the contents of the shareable bitmap won't change.
     RefPtr<cairo_surface_t> createCairoSurface();
 #elif USE(DIRECT2D)
-    COMPtr<IWICBitmap> createDirect2DSurface();
+    COMPtr<ID2D1Bitmap> createDirect2DSurface(ID2D1RenderTarget*);
     void sync(WebCore::GraphicsContext&);
 #endif
 
@@ -162,14 +163,14 @@ private:
     Configuration m_configuration;
 
 #if USE(DIRECT2D)
-    COMPtr<IWICBitmap> m_bitmap;
+    COMPtr<ID2D1Bitmap> m_bitmap;
 #endif
 
     // If the shareable bitmap is backed by shared memory, this points to the shared memory object.
     RefPtr<SharedMemory> m_sharedMemory;
 
     // If the shareable bitmap is backed by fastMalloced memory, this points to the data.
-    void* m_data;
+    void* m_data { nullptr };
 };
 
 } // namespace WebKit
index 1fb337d..972215b 100644 (file)
@@ -35,6 +35,7 @@
 #include <WebCore/GraphicsContextImplDirect2D.h>
 #include <WebCore/NotImplemented.h>
 #include <WebCore/PlatformContextDirect2D.h>
+#include <d2d1_1.h>
 #include <wincodec.h>
 #include <wtf/ProcessID.h>
 
 namespace WebKit {
 using namespace WebCore;
 
-static const auto bitmapFormat = GUID_WICPixelFormat32bppPBGRA;
-
 static unsigned strideForWidth(unsigned width)
 {
-    static unsigned bitsPerPixel = Direct2D::bitsPerPixel(bitmapFormat);
+    static unsigned bitsPerPixel = Direct2D::bitsPerPixel(Direct2D::wicBitmapFormat());
     return bitsPerPixel * width / 8;
 }
 
@@ -68,8 +67,12 @@ static inline COMPtr<IWICBitmap> createSurfaceFromData(void* data, const WebCore
 
 std::unique_ptr<GraphicsContext> ShareableBitmap::createGraphicsContext()
 {
-    m_bitmap = createDirect2DSurface();
-    COMPtr<ID2D1RenderTarget> bitmapContext = Direct2D::createRenderTargetFromWICBitmap(m_bitmap.get());
+    auto bitmapContext = Direct2D::createBitmapRenderTargetOfSize(m_size);
+    if (!bitmapContext)
+        return nullptr;
+
+    HRESULT hr = bitmapContext->GetBitmap(&m_bitmap);
+    RELEASE_ASSERT(SUCCEEDED(hr));
     return makeUnique<GraphicsContext>(GraphicsContextImplDirect2D::createFactory(bitmapContext.get()));
 }
 
@@ -80,13 +83,12 @@ void ShareableBitmap::paint(GraphicsContext& context, const IntPoint& dstPoint,
 
 void ShareableBitmap::paint(GraphicsContext& context, float scaleFactor, const IntPoint& dstPoint, const IntRect& srcRect)
 {
-    auto surface = createDirect2DSurface();
+    auto surface = createDirect2DSurface(context.platformContext()->renderTarget());
 
 #ifndef _NDEBUG
-    unsigned width, height;
-    HRESULT hr = surface->GetSize(&width, &height);
-    ASSERT(width == m_size.width());
-    ASSERT(height == m_size.height());
+    auto bitmapSize = surface->GetPixelSize();
+    ASSERT(bitmapSize.width == m_size.width());
+    ASSERT(bitmapSize.height == m_size.height());
 #endif
 
     FloatRect destRect(dstPoint, srcRect.size());
@@ -100,15 +102,22 @@ void ShareableBitmap::paint(GraphicsContext& context, float scaleFactor, const I
     Direct2D::drawNativeImage(platformContext, surface.get(), m_size, destRect, srcRectScaled, state.compositeOperator, state.blendMode, ImageOrientation(), state.imageInterpolationQuality, state.alpha, Direct2D::ShadowState(state));
 }
 
-COMPtr<IWICBitmap> ShareableBitmap::createDirect2DSurface()
+COMPtr<ID2D1Bitmap> ShareableBitmap::createDirect2DSurface(ID2D1RenderTarget* renderTarget)
 {
-    m_bitmap = createSurfaceFromData(data(), m_size);
-    return m_bitmap;
+    auto bitmapProperties = Direct2D::bitmapProperties();
+
+    COMPtr<ID2D1Bitmap> bitmap;
+    uint32_t stride = 4 * m_size.width();
+    HRESULT hr = renderTarget->CreateBitmap(m_size, data(), stride, &bitmapProperties, &bitmap);
+    if (!SUCCEEDED(hr))
+        return nullptr;
+
+    return bitmap;
 }
 
 RefPtr<Image> ShareableBitmap::createImage()
 {
-    auto surface = createDirect2DSurface();
+    auto surface = createDirect2DSurface(GraphicsContext::defaultRenderTarget());
     if (!surface)
         return nullptr;
 
@@ -121,20 +130,50 @@ void ShareableBitmap::sync(GraphicsContext& graphicsContext)
 
     graphicsContext.endDraw();
 
-    WICRect rcLock = { 0, 0, m_size.width(), m_size.height() };
-
-    COMPtr<IWICBitmapLock> bitmapDataLock;
-    HRESULT hr = m_bitmap->Lock(&rcLock, WICBitmapLockRead, &bitmapDataLock);
-    if (SUCCEEDED(hr)) {
-        UINT bufferSize = 0;
-        WICInProcPointer dataPtr = nullptr;
-        hr = bitmapDataLock->GetDataPointer(&bufferSize, &dataPtr);
-        if (SUCCEEDED(hr))
-            memcpy(data(), reinterpret_cast<char*>(dataPtr), bufferSize);
+    COMPtr<ID2D1DeviceContext> d2dDeviceContext;
+    HRESULT hr = graphicsContext.platformContext()->renderTarget()->QueryInterface(__uuidof(ID2D1DeviceContext), reinterpret_cast<void**>(&d2dDeviceContext));
+    ASSERT(SUCCEEDED(hr));
+
+    const unsigned stride = strideForWidth(m_size.width());
+
+    COMPtr<ID2D1Bitmap1> cpuBitmap;
+    D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_CPU_READ | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, Direct2D::pixelFormat());
+    hr = d2dDeviceContext->CreateBitmap(m_size, nullptr, stride, bitmapProperties, &cpuBitmap);
+    if (!SUCCEEDED(hr))
+        return;
+
+    hr = cpuBitmap->CopyFromBitmap(nullptr, m_bitmap.get(), nullptr);
+    if (!SUCCEEDED(hr))
+        return;
+
+    D2D1_MAPPED_RECT mappedData;
+    hr = cpuBitmap->Map(D2D1_MAP_OPTIONS_READ, &mappedData);
+    if (!SUCCEEDED(hr))
+        return;
+
+    if (mappedData.pitch == stride)
+        memcpy(data(), reinterpret_cast<char*>(mappedData.bits), stride * m_size.height());
+    else {
+        // Stride is different, so must do a rowwise copy:
+        Checked<int> height = m_size.height();
+        Checked<int> width = m_size.width();
+
+        const uint8_t* srcRows = mappedData.bits;
+        uint8_t* row = reinterpret_cast<uint8_t*>(data());
+
+        for (int y = 0; y < height.unsafeGet(); ++y) {
+            for (int x = 0; x < width.unsafeGet(); x++) {
+                int basex = x * 4;
+                reinterpret_cast<uint32_t*>(row + basex)[0] = reinterpret_cast<const uint32_t*>(srcRows + basex)[0];
+            }
+
+            srcRows += mappedData.pitch;
+            row += stride;
+        }
     }
 
-    // Once we are done modifying the data, unlock the bitmap
-    bitmapDataLock = nullptr;
+    hr = cpuBitmap->Unmap();
+    ASSERT(SUCCEEDED(hr));
 }
 
 } // namespace WebKit
index 013a7b3..7e5ec91 100644 (file)
@@ -73,20 +73,7 @@ void BackingStore::incorporateUpdate(ShareableBitmap* bitmap, const UpdateInfo&
 
     IntPoint updateRectBoundsLocation = updateInfo.updateRectBounds.location();
 
-    auto updateWICBitmap = bitmap->createDirect2DSurface();
-
-    HRESULT hr = S_OK;
-#ifndef _NDEBUG
-    unsigned width, height;
-    hr = updateWICBitmap->GetSize(&width, &height);
-    ASSERT(width == updateInfo.updateRectBounds.width());
-    ASSERT(height == updateInfo.updateRectBounds.height());
-#endif
-
-    COMPtr<ID2D1Bitmap> deviceUpdateBitmap;
-    hr = m_backend->renderTarget()->CreateBitmapFromWicBitmap(updateWICBitmap.get(), &deviceUpdateBitmap);
-    if (!SUCCEEDED(hr))
-        return;
+    COMPtr<ID2D1Bitmap> deviceUpdateBitmap = bitmap->createDirect2DSurface(m_backend->renderTarget());
 
 #ifndef _NDEBUG
     auto deviceBitmapSize = deviceUpdateBitmap->GetPixelSize();
index b24581c..72e3de5 100644 (file)
@@ -754,7 +754,8 @@ void DrawingAreaCoordinatedGraphics::display(UpdateInfo& updateInfo)
     }
 
 #if USE(DIRECT2D)
-    bitmap->sync(*graphicsContext);
+    if (graphicsContext)
+        bitmap->sync(*graphicsContext);
 #endif
 
     // Layout can trigger more calls to setNeedsDisplay and we don't want to process them