Log Message
[FTW] Correct compositing, shadow, and radial gradient implementations https://bugs.webkit.org/show_bug.cgi?id=202177
Reviewed by Fujii Hironori. This patch corrects a number of implementation errors in basic Canvas drawing operations. Tested by canvas/philip/tests * platform/graphics/win/Direct2DOperations.cpp: (WebCore::Direct2D::State::setCompositeOperation): Initialize blend and composite modes to correct defaults. (WebCore::Direct2D::drawWithShadowHelper): Correct value used for blur standard deviation to more closely match other browser output. * platform/graphics/win/Direct2DUtilities.cpp: (WebCore::Direct2D::createBitmapCopyFromContext): Added helper function. * platform/graphics/win/Direct2DUtilities.h: * platform/graphics/win/GradientDirect2D.cpp: (WebCore::Gradient::generateGradient): Properly handle the case of a non-zero initial gradient radius. Properly compute the final radius. * platform/graphics/win/ImageBufferDataDirect2D.cpp: (WebCore::ImageBufferData::readDataFromBitmapIfNeeded const): Update to use ID2D1DeviceContext from platformContext, rather than searching for it each time. (WebCore::ImageBufferData::compatibleBitmap): Ditto. * platform/graphics/win/PlatformContextDirect2D.cpp: (WebCore::PlatformContextDirect2D::PlatformContextDirect2D): Grab the ID2D1DeviceContext for the RenderTarget at construction time. (WebCore::PlatformContextDirect2D::setRenderTarget): Ditto. (WebCore::PlatformContextDirect2D::endDraw): Perform compositing operations when needed. (WebCore::PlatformContextDirect2D::compositeIfNeeded): Added. (WebCore::PlatformContextDirect2D::setBlendAndCompositeMode): Update to properly set the blend and compositing mode (depending on global value set for the canvas.) * platform/graphics/win/PlatformContextDirect2D.h: (WebCore::PlatformContextDirect2D::deviceContext): (WebCore::PlatformContextDirect2D::setRenderTarget): Deleted. (WebCore::PlatformContextDirect2D::setBlendMode): Deleted. (WebCore::PlatformContextDirect2D::setCompositeMode): Deleted.
Modified Paths
- trunk/Source/WebCore/ChangeLog
- trunk/Source/WebCore/platform/graphics/Path.h
- trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.cpp
- trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.h
- trunk/Source/WebCore/platform/graphics/win/Direct2DUtilities.cpp
- trunk/Source/WebCore/platform/graphics/win/Direct2DUtilities.h
- trunk/Source/WebCore/platform/graphics/win/GradientDirect2D.cpp
- trunk/Source/WebCore/platform/graphics/win/ImageBufferDataDirect2D.cpp
- trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp
- trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.cpp
- trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.h
Diff
Modified: trunk/Source/WebCore/ChangeLog (250491 => 250492)
--- trunk/Source/WebCore/ChangeLog 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/ChangeLog 2019-09-29 19:33:37 UTC (rev 250492)
@@ -1,3 +1,44 @@
+2019-09-28 Brent Fulgham <bfulg...@apple.com>
+
+ [FTW] Correct compositing, shadow, and radial gradient implementations
+ https://bugs.webkit.org/show_bug.cgi?id=202177
+
+ Reviewed by Fujii Hironori.
+
+ This patch corrects a number of implementation errors in basic Canvas
+ drawing operations.
+
+ Tested by canvas/philip/tests
+
+ * platform/graphics/win/Direct2DOperations.cpp:
+ (WebCore::Direct2D::State::setCompositeOperation): Initialize blend and
+ composite modes to correct defaults.
+ (WebCore::Direct2D::drawWithShadowHelper): Correct value used for blur
+ standard deviation to more closely match other browser output.
+ * platform/graphics/win/Direct2DUtilities.cpp:
+ (WebCore::Direct2D::createBitmapCopyFromContext): Added helper function.
+ * platform/graphics/win/Direct2DUtilities.h:
+ * platform/graphics/win/GradientDirect2D.cpp:
+ (WebCore::Gradient::generateGradient): Properly handle the case of a non-zero
+ initial gradient radius. Properly compute the final radius.
+ * platform/graphics/win/ImageBufferDataDirect2D.cpp:
+ (WebCore::ImageBufferData::readDataFromBitmapIfNeeded const): Update to use ID2D1DeviceContext
+ from platformContext, rather than searching for it each time.
+ (WebCore::ImageBufferData::compatibleBitmap): Ditto.
+ * platform/graphics/win/PlatformContextDirect2D.cpp:
+ (WebCore::PlatformContextDirect2D::PlatformContextDirect2D): Grab the ID2D1DeviceContext for
+ the RenderTarget at construction time.
+ (WebCore::PlatformContextDirect2D::setRenderTarget): Ditto.
+ (WebCore::PlatformContextDirect2D::endDraw): Perform compositing operations when needed.
+ (WebCore::PlatformContextDirect2D::compositeIfNeeded): Added.
+ (WebCore::PlatformContextDirect2D::setBlendAndCompositeMode): Update to properly set the
+ blend and compositing mode (depending on global value set for the canvas.)
+ * platform/graphics/win/PlatformContextDirect2D.h:
+ (WebCore::PlatformContextDirect2D::deviceContext):
+ (WebCore::PlatformContextDirect2D::setRenderTarget): Deleted.
+ (WebCore::PlatformContextDirect2D::setBlendMode): Deleted.
+ (WebCore::PlatformContextDirect2D::setCompositeMode): Deleted.
+
2019-09-29 Zan Dobersek <zdober...@igalia.com>
Tighten up LayerRepresentation operators
Modified: trunk/Source/WebCore/platform/graphics/Path.h (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/Path.h 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/Path.h 2019-09-29 19:33:37 UTC (rev 250492)
@@ -50,6 +50,10 @@
typedef ID2D1GeometryGroup PlatformPath;
+namespace WebCore {
+class PlatformContextDirect2D;
+}
+
#elif USE(CAIRO)
namespace WebCore {
@@ -170,6 +174,7 @@
// To keep Path() cheap, it does not allocate a PlatformPath immediately
// meaning Path::platformPath() can return null.
#if USE(DIRECT2D)
+ FloatRect fastBoundingRectForStroke(const PlatformContextDirect2D&) const;
PlatformPathPtr platformPath() const { return m_path.get(); }
#else
PlatformPathPtr platformPath() const { return m_path; }
Modified: trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.cpp (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.cpp 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.cpp 2019-09-29 19:33:37 UTC (rev 250492)
@@ -127,9 +127,10 @@
void setCompositeOperation(PlatformContextDirect2D& platformContext, CompositeOperator compositeOperation, BlendMode blendMode)
{
- D2D1_BLEND_MODE targetBlendMode = D2D1_BLEND_MODE_SCREEN;
- D2D1_COMPOSITE_MODE targetCompositeMode = D2D1_COMPOSITE_MODE_SOURCE_ATOP;
+ D2D1_BLEND_MODE targetBlendMode = D2D1_BLEND_MODE_MULTIPLY;
+ D2D1_COMPOSITE_MODE targetCompositeMode = D2D1_COMPOSITE_MODE_FORCE_DWORD;
+
if (blendMode != BlendMode::Normal) {
switch (blendMode) {
case BlendMode::Multiply:
@@ -192,10 +193,10 @@
// FIXME: targetBlendMode = D2D1_BLEND_MODE_CLEAR;
break;
case CompositeCopy:
- // FIXME: targetBlendMode = D2D1_BLEND_MODE_COPY;
+ targetCompositeMode = D2D1_COMPOSITE_MODE_SOURCE_COPY;
break;
case CompositeSourceOver:
- // FIXME: kCGBlendModeNormal
+ targetCompositeMode = D2D1_COMPOSITE_MODE_SOURCE_OVER;
break;
case CompositeSourceIn:
targetCompositeMode = D2D1_COMPOSITE_MODE_SOURCE_IN;
@@ -222,10 +223,10 @@
targetCompositeMode = D2D1_COMPOSITE_MODE_XOR;
break;
case CompositePlusDarker:
- targetBlendMode = D2D1_BLEND_MODE_DARKER_COLOR;
+ targetBlendMode = D2D1_BLEND_MODE_DARKEN;
break;
case CompositePlusLighter:
- targetBlendMode = D2D1_BLEND_MODE_LIGHTER_COLOR;
+ targetBlendMode = D2D1_BLEND_MODE_LIGHTEN;
break;
case CompositeDifference:
targetBlendMode = D2D1_BLEND_MODE_DIFFERENCE;
@@ -233,8 +234,7 @@
}
}
- platformContext.setBlendMode(targetBlendMode);
- platformContext.setCompositeMode(targetCompositeMode);
+ platformContext.setBlendAndCompositeMode(targetBlendMode, targetCompositeMode);
}
void setShouldAntialias(PlatformContextDirect2D& platformContext, bool enable)
@@ -411,15 +411,10 @@
auto context = platformContext.renderTarget();
platformContext.setTags(1, __LINE__);
- Function<void(ID2D1RenderTarget*)> drawFunction = [&platformContext, rect, &fillSource](ID2D1RenderTarget* renderTarget) {
+ drawWithShadow(platformContext, rect, shadowState, [&platformContext, rect, &fillSource](ID2D1RenderTarget* renderTarget) {
const D2D1_RECT_F d2dRect = rect;
renderTarget->FillRectangle(&d2dRect, fillSource.brush.get());
- };
-
- if (shadowState.isVisible())
- drawWithShadow(platformContext, rect, shadowState, drawFunction);
- else
- drawWithoutShadow(platformContext, rect, drawFunction);
+ });
}
void fillRect(PlatformContextDirect2D& platformContext, const FloatRect& rect, const Color& color, const ShadowState& shadowState)
@@ -427,15 +422,10 @@
auto context = platformContext.renderTarget();
platformContext.setTags(1, __LINE__);
- Function<void(ID2D1RenderTarget*)> drawFunction = [&platformContext, color, rect](ID2D1RenderTarget* renderTarget) {
+ drawWithShadow(platformContext, rect, shadowState, [&platformContext, color, rect](ID2D1RenderTarget* renderTarget) {
const D2D1_RECT_F d2dRect = rect;
renderTarget->FillRectangle(&d2dRect, platformContext.brushWithColor(color).get());
- };
-
- if (shadowState.isVisible())
- drawWithShadow(platformContext, rect, shadowState, drawFunction);
- else
- drawWithoutShadow(platformContext, rect, drawFunction);
+ });
}
void fillRoundedRect(PlatformContextDirect2D& platformContext, const FloatRoundedRect& rect, const Color& color, const ShadowState& shadowState)
@@ -450,15 +440,10 @@
bool equalHeights = (radii.topLeft().height() == radii.bottomLeft().height() && radii.bottomLeft().height() == radii.topRight().height() && radii.topRight().height() == radii.bottomRight().height());
bool hasCustomFill = false; // FIXME: Why isn't a FillSource passed to this function?
if (!hasCustomFill && equalWidths && equalHeights && radii.topLeft().width() * 2 == r.width() && radii.topLeft().height() * 2 == r.height()) {
- Function<void(ID2D1RenderTarget*)> drawFunction = [&platformContext, color, rect, radii, r](ID2D1RenderTarget* renderTarget) {
+ drawWithShadow(platformContext, r, shadowState, [&platformContext, color, rect, radii, r](ID2D1RenderTarget* renderTarget) {
auto roundedRect = D2D1::RoundedRect(r, radii.topLeft().width(), radii.topLeft().height());
renderTarget->FillRoundedRectangle(&roundedRect, platformContext.brushWithColor(color).get());
- };
-
- if (shadowState.isVisible())
- drawWithShadow(platformContext, r, shadowState, drawFunction);
- else
- drawWithoutShadow(platformContext, r, drawFunction);
+ });
} else {
Path path;
path.addRoundedRect(rect);
@@ -488,15 +473,11 @@
void fillRectWithGradient(PlatformContextDirect2D& platformContext, const FloatRect& rect, ID2D1Brush* gradient)
{
- auto context = platformContext.renderTarget();
-
platformContext.setTags(1, __LINE__);
- Function<void(ID2D1RenderTarget*)> drawFunction = [&platformContext, rect, &gradient](ID2D1RenderTarget* renderTarget) {
+ drawWithoutShadow(platformContext, [&platformContext, rect, &gradient](ID2D1RenderTarget* renderTarget) {
const D2D1_RECT_F d2dRect = rect;
renderTarget->FillRectangle(&d2dRect, gradient);
- };
-
- drawWithoutShadow(platformContext, rect, drawFunction);
+ });
}
void fillPath(PlatformContextDirect2D& platformContext, const Path& path, const FillSource& fillSource, const ShadowState& shadowState)
@@ -517,11 +498,9 @@
if (shadowState.isVisible()) {
FloatRect boundingRect = path.fastBoundingRect();
- drawWithShadow(platformContext, boundingRect, shadowState, drawFunction);
- } else {
- FloatRect contextRect(FloatPoint(), context->GetSize());
- drawWithoutShadow(platformContext, contextRect, drawFunction);
- }
+ drawWithShadow(platformContext, boundingRect, shadowState, WTFMove(drawFunction));
+ } else
+ drawWithoutShadow(platformContext, WTFMove(drawFunction));
}
void fillPath(PlatformContextDirect2D& platformContext, const Path& path, const Color& color, const ShadowState& shadowState)
@@ -541,25 +520,18 @@
if (shadowState.isVisible()) {
FloatRect boundingRect = path.fastBoundingRect();
- drawWithShadow(platformContext, boundingRect, shadowState, drawFunction);
- } else {
- FloatRect contextRect(FloatPoint(), context->GetSize());
- drawWithoutShadow(platformContext, contextRect, drawFunction);
- }
+ drawWithShadow(platformContext, boundingRect, shadowState, WTFMove(drawFunction));
+ } else
+ drawWithoutShadow(platformContext, WTFMove(drawFunction));
}
void strokeRect(PlatformContextDirect2D& platformContext, const FloatRect& rect, float lineWidth, const StrokeSource& strokeSource, const ShadowState& shadowState)
{
- Function<void(ID2D1RenderTarget*)> drawFunction = [&platformContext, &strokeSource, rect, lineWidth](ID2D1RenderTarget* renderTarget) {
+ drawWithShadow(platformContext, rect, shadowState, [&platformContext, &strokeSource, rect, lineWidth](ID2D1RenderTarget* renderTarget) {
platformContext.setTags(1, __LINE__);
const D2D1_RECT_F d2dRect = rect;
renderTarget->DrawRectangle(&d2dRect, strokeSource.brush.get(), lineWidth, platformContext.strokeStyle());
- };
-
- if (shadowState.isVisible())
- drawWithShadow(platformContext, rect, shadowState, drawFunction);
- else
- drawWithoutShadow(platformContext, rect, drawFunction);
+ });
}
void strokePath(PlatformContextDirect2D& platformContext, const Path& path, const StrokeSource& strokeSource, const ShadowState& shadowState)
@@ -568,15 +540,15 @@
platformContext.setTags(1, __LINE__);
- auto boundingRect = path.fastBoundingRect();
Function<void(ID2D1RenderTarget*)> drawFunction = [&platformContext, &path, &strokeSource](ID2D1RenderTarget* renderTarget) {
renderTarget->DrawGeometry(path.platformPath(), strokeSource.brush.get(), strokeSource.thickness, platformContext.strokeStyle());
};
- if (shadowState.isVisible())
- drawWithShadow(platformContext, boundingRect, shadowState, drawFunction);
- else
- drawWithoutShadow(platformContext, boundingRect, drawFunction);
+ if (shadowState.isVisible()) {
+ auto boundingRect = path.fastBoundingRectForStroke(platformContext);
+ drawWithShadow(platformContext, boundingRect, shadowState, WTFMove(drawFunction));
+ } else
+ drawWithoutShadow(platformContext, WTFMove(drawFunction));
}
void drawPath(PlatformContextDirect2D& platformContext, const Path& path, const StrokeSource& strokeSource, const ShadowState&)
@@ -587,8 +559,7 @@
platformContext.setTags(1, __LINE__);
- auto rect = path.fastBoundingRect();
- drawWithoutShadow(platformContext, rect, [&platformContext, &strokeSource, &path](ID2D1RenderTarget* renderTarget) {
+ drawWithoutShadow(platformContext, [&platformContext, &strokeSource, &path](ID2D1RenderTarget* renderTarget) {
renderTarget->DrawGeometry(path.platformPath(), strokeSource.brush.get(), strokeSource.thickness, platformContext.strokeStyle());
});
@@ -595,63 +566,135 @@
flush(platformContext);
}
-void drawWithShadowHelper(ID2D1RenderTarget* context, ID2D1Bitmap* bitmap, const Color& shadowColor, const FloatSize& shadowOffset, float shadowBlur)
+static void drawWithShadowHelper(ID2D1RenderTarget* context, ID2D1BitmapRenderTarget* bitmapTarget, const FloatRect& boundingRect, const Color& shadowColor, const FloatSize& shadowOffset, float shadowBlur)
{
- COMPtr<ID2D1DeviceContext> deviceContext;
- HRESULT hr = context->QueryInterface(&deviceContext);
+ COMPtr<ID2D1Bitmap> currentCanvas = Direct2D::createBitmapCopyFromContext(bitmapTarget);
+ if (!currentCanvas)
+ return;
+
+ COMPtr<ID2D1DeviceContext> shadowDeviceContext;
+ HRESULT hr = bitmapTarget->QueryInterface(&shadowDeviceContext);
RELEASE_ASSERT(SUCCEEDED(hr));
// Create the shadow effect
COMPtr<ID2D1Effect> shadowEffect;
- hr = deviceContext->CreateEffect(CLSID_D2D1Shadow, &shadowEffect);
+ hr = shadowDeviceContext->CreateEffect(CLSID_D2D1Shadow, &shadowEffect);
RELEASE_ASSERT(SUCCEEDED(hr));
- shadowEffect->SetInput(0, bitmap);
+ shadowEffect->SetInput(0, currentCanvas.get());
shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, static_cast<D2D1_VECTOR_4F>(shadowColor));
- shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, shadowBlur);
- COMPtr<ID2D1Effect> transformEffect;
- hr = deviceContext->CreateEffect(CLSID_D2D12DAffineTransform, &transformEffect);
+ float blurDeviation = 0.5 * shadowBlur;
+ shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, blurDeviation);
+
+ COMPtr<ID2D1Effect> shadowTransformEffect;
+ hr = shadowDeviceContext->CreateEffect(CLSID_D2D12DAffineTransform, &shadowTransformEffect);
RELEASE_ASSERT(SUCCEEDED(hr));
- transformEffect->SetInputEffect(0, shadowEffect.get());
+ shadowTransformEffect->SetInputEffect(0, shadowEffect.get());
- auto translation = D2D1::Matrix3x2F::Translation(shadowOffset.width(), shadowOffset.height());
- transformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, translation);
+ // Must flip the axis for the shadow offset, since Direct2D's Y axis is inverted.
+ auto shadowTranslation = D2D1::Matrix3x2F::Translation(shadowOffset.width(), -shadowOffset.height());
+ shadowTransformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, shadowTranslation);
COMPtr<ID2D1Effect> compositor;
- hr = deviceContext->CreateEffect(CLSID_D2D1Composite, &compositor);
+ hr = shadowDeviceContext->CreateEffect(CLSID_D2D1Composite, &compositor);
RELEASE_ASSERT(SUCCEEDED(hr));
- compositor->SetInputEffect(0, transformEffect.get());
- compositor->SetInput(1, bitmap);
+ compositor->SetInputEffect(0, shadowTransformEffect.get());
+ compositor->SetInput(1, currentCanvas.get());
- deviceContext->DrawImage(compositor.get(), D2D1_INTERPOLATION_MODE_LINEAR);
+ shadowDeviceContext->BeginDraw();
+ shadowDeviceContext->Clear(D2D1::ColorF(0, 0, 0, 0));
+ shadowDeviceContext->DrawImage(compositor.get());
+ hr = shadowDeviceContext->EndDraw();
+ RELEASE_ASSERT(SUCCEEDED(hr));
+
+ COMPtr<ID2D1Bitmap> bitmap;
+ hr = bitmapTarget->GetBitmap(&bitmap);
+ RELEASE_ASSERT(SUCCEEDED(hr));
+
+ IntSize pixelSize = context->GetPixelSize();
+ COMPtr<ID2D1Bitmap> cropped = Direct2D::createBitmap(bitmapTarget, pixelSize);
+ if (!cropped)
+ return;
+
+ auto scaleFactor = bitmapResolution(context);
+
+ FloatRect scaledBoundingRect(boundingRect);
+ scaledBoundingRect.scale(scaleFactor.width(), scaleFactor.height());
+
+ // Take the magnitude of the offset. If the origin was outside the drawing context, we stretched to include those points,
+ // and so we need to crop them out. If the origin was inside, we want to honor the offset.
+ int x = clampTo<int>(std::abs(scaledBoundingRect.x()));
+ int y = clampTo<int>(std::abs(scaledBoundingRect.y()));
+ int width = clampTo<int>(scaledBoundingRect.width());
+ int height = clampTo<int>(scaledBoundingRect.height());
+
+ IntRect outputRect(IntPoint(x, y), IntSize(width, height));
+ IntRect destContextRect(IntPoint(), pixelSize);
+ if (outputRect.intersects(destContextRect))
+ outputRect.intersect(destContextRect);
+
+ D2D1_RECT_U cropRect = outputRect;
+ auto targetPoint = D2D1::Point2U();
+ cropped->CopyFromBitmap(&targetPoint, bitmap.get(), &cropRect);
+
+ context->DrawBitmap(cropped.get());
}
-void drawWithShadow(PlatformContextDirect2D& platformContext, const FloatRect& boundingRect, const ShadowState& shadowState, const WTF::Function<void(ID2D1RenderTarget*)>& drawCommands)
+void drawWithShadow(PlatformContextDirect2D& platformContext, FloatRect boundingRect, const ShadowState& shadowState, WTF::Function<void(ID2D1RenderTarget*)>&& drawCommands)
{
+ if (!shadowState.isVisible()) {
+ drawWithoutShadow(platformContext, WTFMove(drawCommands));
+ return;
+ }
+
platformContext.notifyPreDrawObserver();
- auto context = platformContext.renderTarget();
+ auto* context = platformContext.renderTarget();
+ FloatSize renderTargetSize = context->GetSize();
+ const FloatRect contextRect(FloatPoint(), renderTargetSize);
+ FloatRect workingContextRect(contextRect);
+
+ if (boundingRect.isInfinite())
+ boundingRect = workingContextRect;
+
+ if (!contextRect.contains(boundingRect))
+ workingContextRect.unite(boundingRect);
+
+ workingContextRect.expand(std::abs(shadowState.offset.width()) + shadowState.blur, std::abs(shadowState.offset.height()) + shadowState.blur);
+
+ auto scaleFactor = bitmapResolution(context);
+
+ workingContextRect.scale(scaleFactor);
+
+ IntSize pixelDimensions(clampTo<int>(workingContextRect.width()), clampTo<int>(workingContextRect.height()));
+
// Render the current geometry to a bitmap context
- COMPtr<ID2D1BitmapRenderTarget> bitmapTarget = createBitmapRenderTarget(context);
+ COMPtr<ID2D1BitmapRenderTarget> bitmapTarget = createBitmapRenderTargetOfSize(pixelDimensions, context);
+ D2D1_MATRIX_3X2_F currentTransform;
+ bitmapTarget->GetTransform(¤tTransform);
+
+ if (!contextRect.contains(boundingRect.location())) {
+ auto translation = D2D1::Matrix3x2F::Translation(-boundingRect.location().x(), -boundingRect.location().y());
+ bitmapTarget->SetTransform(translation * currentTransform);
+ }
+
bitmapTarget->BeginDraw();
drawCommands(bitmapTarget.get());
HRESULT hr = bitmapTarget->EndDraw();
RELEASE_ASSERT(SUCCEEDED(hr));
- COMPtr<ID2D1Bitmap> bitmap;
- hr = bitmapTarget->GetBitmap(&bitmap);
- RELEASE_ASSERT(SUCCEEDED(hr));
+ bitmapTarget->SetTransform(currentTransform);
- drawWithShadowHelper(context, bitmap.get(), shadowState.color, shadowState.offset, shadowState.blur);
+ drawWithShadowHelper(context, bitmapTarget.get(), boundingRect, shadowState.color, shadowState.offset, shadowState.blur);
platformContext.notifyPostDrawObserver();
}
-void drawWithoutShadow(PlatformContextDirect2D& platformContext, const FloatRect& /*boundingRect*/, const WTF::Function<void(ID2D1RenderTarget*)>& drawCommands)
+void drawWithoutShadow(PlatformContextDirect2D& platformContext, WTF::Function<void(ID2D1RenderTarget*)>&& drawCommands)
{
platformContext.notifyPreDrawObserver();
drawCommands(platformContext.renderTarget());
@@ -660,7 +703,7 @@
void clearRect(PlatformContextDirect2D& platformContext, const FloatRect& rect)
{
- drawWithoutShadow(platformContext, rect, [&platformContext, rect](ID2D1RenderTarget* renderTarget) {
+ drawWithoutShadow(platformContext, [&platformContext, rect](ID2D1RenderTarget* renderTarget) {
FloatRect renderTargetRect(FloatPoint(), renderTarget->GetSize());
FloatRect rectToClear(rect);
@@ -812,15 +855,10 @@
}
platformContext.setTags(1, __LINE__);
- Function<void(ID2D1RenderTarget*)> drawFunction = [image, adjustedDestRect, globalAlpha, srcRect](ID2D1RenderTarget* renderTarget) {
+ drawWithShadow(platformContext, adjustedDestRect, shadowState, [image, adjustedDestRect, globalAlpha, srcRect](ID2D1RenderTarget* renderTarget) {
renderTarget->DrawBitmap(image, adjustedDestRect, globalAlpha, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, srcRect);
- };
+ });
- if (shadowState.isVisible())
- drawWithShadow(platformContext, adjustedDestRect, shadowState, drawFunction);
- else
- drawWithoutShadow(platformContext, adjustedDestRect, drawFunction);
-
if (!stateSaver.didSave())
context->SetTransform(ctm);
}
@@ -869,7 +907,7 @@
if (!SUCCEEDED(hr))
return;
- drawWithoutShadow(platformContext, destRect, [destRect, patternBrush](ID2D1RenderTarget* renderTarget) {
+ drawWithoutShadow(platformContext, [destRect, patternBrush](ID2D1RenderTarget* renderTarget) {
const D2D1_RECT_F d2dRect = destRect;
renderTarget->FillRectangle(&d2dRect, patternBrush.get());
});
@@ -880,10 +918,8 @@
// FIXME: this function does not handle patterns and gradients like drawPath does, it probably should.
ASSERT(!rect.isEmpty());
- auto context = platformContext.renderTarget();
-
platformContext.setTags(1, __LINE__);
- drawWithoutShadow(platformContext, rect, [&platformContext, rect, fillColor, strokeColor, strokeStyle](ID2D1RenderTarget* renderTarget) {
+ drawWithoutShadow(platformContext, [&platformContext, rect, fillColor, strokeColor, strokeStyle](ID2D1RenderTarget* renderTarget) {
const D2D1_RECT_F d2dRect = rect;
auto fillBrush = platformContext.brushWithColor(fillColor);
renderTarget->FillRectangle(&d2dRect, fillBrush.get());
@@ -935,9 +971,7 @@
platformContext.setTags(1, __LINE__);
- FloatRect boundingRect(p1, p2);
-
- drawWithoutShadow(platformContext, boundingRect, [&platformContext, p1, p2, d2dStrokeStyle, strokeColor, strokeThickness](ID2D1RenderTarget* renderTarget) {
+ drawWithoutShadow(platformContext, [&platformContext, p1, p2, d2dStrokeStyle, strokeColor, strokeThickness](ID2D1RenderTarget* renderTarget) {
renderTarget->DrawLine(p1, p2, platformContext.brushWithColor(strokeColor).get(), strokeThickness, d2dStrokeStyle.get());
});
}
@@ -956,10 +990,8 @@
{
auto ellipse = D2D1::Ellipse(rect.center(), 0.5 * rect.width(), 0.5 * rect.height());
- auto context = platformContext.renderTarget();
-
platformContext.setTags(1, __LINE__);
- drawWithoutShadow(platformContext, rect, [&platformContext, ellipse, fillColor, strokeStyle, strokeColor, strokeThickness](ID2D1RenderTarget* renderTarget) {
+ drawWithoutShadow(platformContext, [&platformContext, ellipse, fillColor, strokeStyle, strokeColor, strokeThickness](ID2D1RenderTarget* renderTarget) {
auto fillBrush = platformContext.brushWithColor(fillColor);
renderTarget->FillEllipse(&ellipse, fillBrush.get());
if (strokeStyle != StrokeStyle::NoStroke) {
@@ -976,10 +1008,8 @@
auto ellipse = D2D1::Ellipse(rect.center(), 0.5 * rect.width(), 0.5 * rect.height());
- auto context = platformContext.renderTarget();
-
platformContext.setTags(1, __LINE__);
- drawWithoutShadow(platformContext, rect, [&platformContext, ellipse, strokeColor, strokeThickness](ID2D1RenderTarget* renderTarget) {
+ drawWithoutShadow(platformContext, [&platformContext, ellipse, strokeColor, strokeThickness](ID2D1RenderTarget* renderTarget) {
auto strokeBrush = platformContext.brushWithColor(strokeColor);
renderTarget->DrawEllipse(&ellipse, strokeBrush.get(), strokeThickness, platformContext.strokeStyle());
});
@@ -1099,15 +1129,15 @@
HRESULT hr = renderTarget->EndDraw();
RELEASE_ASSERT(SUCCEEDED(hr));
- COMPtr<ID2D1Bitmap> bitmap;
- hr = renderTarget->GetBitmap(&bitmap);
- RELEASE_ASSERT(SUCCEEDED(hr));
-
auto context = platformContext.renderTarget();
if (currentLayer.hasShadow)
- drawWithShadowHelper(context, bitmap.get(), currentLayer.shadowColor, currentLayer.shadowOffset, currentLayer.shadowBlur);
+ drawWithShadowHelper(context, renderTarget.get(), FloatRect(), currentLayer.shadowColor, currentLayer.shadowOffset, currentLayer.shadowBlur);
else {
+ COMPtr<ID2D1Bitmap> bitmap;
+ hr = renderTarget->GetBitmap(&bitmap);
+ RELEASE_ASSERT(SUCCEEDED(hr));
+
COMPtr<ID2D1BitmapBrush> bitmapBrush;
auto bitmapBrushProperties = D2D1::BitmapBrushProperties();
auto brushProperties = D2D1::BrushProperties();
Modified: trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.h (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.h 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.h 2019-09-29 19:33:37 UTC (rev 250492)
@@ -133,9 +133,8 @@
void drawPath(PlatformContextDirect2D&, const Path&, const StrokeSource&, const ShadowState&);
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);
-void drawWithShadowHelper(ID2D1RenderTarget* context, ID2D1Bitmap*, const Color& shadowColor, const FloatSize& shadowOffset, float shadowBlur);
+void drawWithoutShadow(PlatformContextDirect2D&, WTF::Function<void(ID2D1RenderTarget*)>&& drawCommands);
+void drawWithShadow(PlatformContextDirect2D&, FloatRect boundingRect, const ShadowState&, WTF::Function<void(ID2D1RenderTarget*)>&& drawCommands);
void drawRect(PlatformContextDirect2D&, const FloatRect&, float, const Color&, StrokeStyle, const Color&);
void drawLine(PlatformContextDirect2D&, const FloatPoint&, const FloatPoint&, StrokeStyle, const Color&, float, bool);
Modified: trunk/Source/WebCore/platform/graphics/win/Direct2DUtilities.cpp (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/win/Direct2DUtilities.cpp 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/win/Direct2DUtilities.cpp 2019-09-29 19:33:37 UTC (rev 250492)
@@ -65,9 +65,9 @@
return bitmapSource->GetSize();
}
-FloatPoint bitmapResolution(IWICBitmapSource* bitmapSource)
+FloatSize bitmapResolution(IWICBitmapSource* bitmapSource)
{
- constexpr double dpiBase = 96.0;
+ constexpr double dpiBase = 96;
double dpiX, dpiY;
HRESULT hr = bitmapSource->GetResolution(&dpiX, &dpiY);
@@ -74,24 +74,36 @@
if (!SUCCEEDED(hr))
return { };
- FloatPoint result(dpiX, dpiY);
+ FloatSize result(dpiX, dpiY);
result.scale(1.0 / dpiBase);
return result;
}
-FloatPoint bitmapResolution(ID2D1Bitmap* bitmap)
+FloatSize bitmapResolution(ID2D1Bitmap* bitmap)
{
- constexpr double dpiBase = 96.0;
+ constexpr double dpiBase = 96;
float dpiX, dpiY;
bitmap->GetDpi(&dpiX, &dpiY);
- FloatPoint result(dpiX, dpiY);
+ FloatSize result(dpiX, dpiY);
result.scale(1.0 / dpiBase);
return result;
}
+FloatSize bitmapResolution(ID2D1RenderTarget* target)
+{
+ constexpr double dpiBase = 96;
+
+ float dpiX, dpiY;
+ target->GetDpi(&dpiX, &dpiY);
+
+ FloatSize result(dpiX, dpiY);
+ result.scale(1.0 / dpiBase);
+ return result;
+
+}
unsigned bitsPerPixel(GUID bitmapFormat)
{
COMPtr<IWICComponentInfo> componentInfo;
@@ -472,6 +484,30 @@
return swapChain;
}
+COMPtr<ID2D1Bitmap> createBitmapCopyFromContext(ID2D1BitmapRenderTarget* bitmapTarget)
+{
+ COMPtr<ID2D1Bitmap> currentCanvas;
+ HRESULT hr = bitmapTarget->GetBitmap(¤tCanvas);
+ if (!SUCCEEDED(hr))
+ return nullptr;
+
+ auto bitmapCreateProperties = bitmapProperties();
+
+ COMPtr<ID2D1Bitmap> bitmap;
+ D2D1_SIZE_U bitmapSize = currentCanvas->GetPixelSize();
+ hr = bitmapTarget->CreateBitmap(bitmapSize, bitmapCreateProperties, &bitmap);
+ if (!SUCCEEDED(hr))
+ return nullptr;
+
+ auto targetPos = D2D1::Point2U();
+ D2D1_RECT_U dataRect = D2D1::RectU(0, 0, bitmapSize.width, bitmapSize.height);
+ hr = bitmap->CopyFromBitmap(&targetPos, currentCanvas.get(), &dataRect);
+ if (!SUCCEEDED(hr))
+ return false;
+
+ return bitmap;
+}
+
} // namespace Direct2D
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/win/Direct2DUtilities.h (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/win/Direct2DUtilities.h 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/win/Direct2DUtilities.h 2019-09-29 19:33:37 UTC (rev 250492)
@@ -72,8 +72,9 @@
IntSize bitmapSize(IWICBitmapSource*);
FloatSize bitmapSize(ID2D1Bitmap*);
-FloatPoint bitmapResolution(IWICBitmapSource*);
-FloatPoint bitmapResolution(ID2D1Bitmap*);
+FloatSize bitmapResolution(IWICBitmapSource*);
+FloatSize bitmapResolution(ID2D1Bitmap*);
+FloatSize bitmapResolution(ID2D1RenderTarget*);
unsigned bitsPerPixel(GUID);
COMPtr<ID2D1Bitmap> createBitmap(ID2D1RenderTarget*, const IntSize&);
COMPtr<IWICBitmap> createWicBitmap(const IntSize&);
@@ -84,6 +85,7 @@
COMPtr<ID2D1DCRenderTarget> createGDIRenderTarget();
COMPtr<IDXGISurface1> createDXGISurfaceOfSize(const IntSize&, ID3D11Device1*, bool crossProcess);
COMPtr<ID2D1RenderTarget> createSurfaceRenderTarget(IDXGISurface1*);
+COMPtr<ID2D1Bitmap> createBitmapCopyFromContext(ID2D1BitmapRenderTarget*);
void copyRectFromOneSurfaceToAnother(ID2D1Bitmap* from, ID2D1Bitmap* to, const IntSize& sourceOffset, const IntRect&, const IntSize& destOffset = IntSize());
Modified: trunk/Source/WebCore/platform/graphics/win/GradientDirect2D.cpp (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/win/GradientDirect2D.cpp 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/win/GradientDirect2D.cpp 2019-09-29 19:33:37 UTC (rev 250492)
@@ -30,6 +30,7 @@
#include "GraphicsContext.h"
#include "PlatformContextDirect2D.h"
#include <d2d1.h>
+#include <wtf/MathExtras.h>
#include <wtf/RetainPtr.h>
#define GRADIENT_DRAWING 3
@@ -70,6 +71,35 @@
gradientStops.append(D2D1::GradientStop(stop.offset, D2D1::ColorF(r, g, b, a)));
}
+ WTF::switchOn(m_data,
+ [&] (const LinearData&) {
+ // No action needed.
+ },
+ [&] (const RadialData& data) {
+ if (data.startRadius && data.endRadius) {
+ float startPosition = std::abs(data.startRadius / data.endRadius);
+ if (startPosition > 1.0)
+ startPosition = 1.0 / startPosition;
+ float availableRange = 1.0 - startPosition;
+ RELEASE_ASSERT(availableRange <= 1.0 && availableRange >= 0);
+
+ for (auto& stop : gradientStops) {
+ stop.position *= availableRange;
+ stop.position += startPosition;
+ }
+
+ // Restore the 'start' position
+ auto firstStop = gradientStops.first();
+ firstStop.position = 0;
+
+ gradientStops.insert(0, firstStop);
+ }
+ },
+ [&] (const ConicData&) {
+ // FIXME: Assess whether needed for Conic Gradients.
+ }
+ );
+
COMPtr<ID2D1GradientStopCollection> gradientStopCollection;
HRESULT hr = renderTarget->CreateGradientStopCollection(gradientStops.data(), gradientStops.size(), &gradientStopCollection);
RELEASE_ASSERT(SUCCEEDED(hr));
@@ -90,12 +120,14 @@
m_gradient = linearGradient;
},
[&] (const RadialData& data) {
- FloatSize offset = data.point1 - data.point0;
+ FloatSize offset = data.point0 - data.point1;
+ FloatPoint center = data.point1;
+ float radiusX = data.endRadius;
+ float radiusY = radiusX / data.aspectRatio;
+
ID2D1RadialGradientBrush* radialGradient = nullptr;
- float radiusX = data.endRadius + offset.width();
- float radiusY = radiusX / data.aspectRatio;
hr = renderTarget->CreateRadialGradientBrush(
- D2D1::RadialGradientBrushProperties(data.point0, D2D1::Point2F(offset.width(), offset.height()), radiusX, radiusY),
+ D2D1::RadialGradientBrushProperties(center, D2D1::Point2F(offset.width(), offset.height()), radiusX, radiusY),
D2D1::BrushProperties(), gradientStopCollection.get(),
&radialGradient);
RELEASE_ASSERT(SUCCEEDED(hr));
Modified: trunk/Source/WebCore/platform/graphics/win/ImageBufferDataDirect2D.cpp (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/win/ImageBufferDataDirect2D.cpp 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/win/ImageBufferDataDirect2D.cpp 2019-09-29 19:33:37 UTC (rev 250492)
@@ -304,7 +304,7 @@
context->endDraw();
- COMPtr<ID2D1DeviceContext> d2dDeviceContext(Query, platformContext->renderTarget());
+ COMPtr<ID2D1DeviceContext> d2dDeviceContext = platformContext->deviceContext();
ASSERT(!!d2dDeviceContext);
auto bytesPerRowInData = pixelSize.width() * 4;
@@ -497,6 +497,7 @@
}
auto size = bitmap->GetPixelSize();
+ ASSERT(size.height && size.width);
Checked<unsigned, RecordOverflow> numBytes = size.width * size.height * 4;
if (numBytes.hasOverflowed())
@@ -506,16 +507,13 @@
// We cannot access the data backing an IWICBitmap while an active draw session is open.
context->endDraw();
- COMPtr<ID2D1DeviceContext> sourceDeviceContext;
- HRESULT hr = platformContext->renderTarget()->QueryInterface(__uuidof(ID2D1DeviceContext), reinterpret_cast<void**>(&sourceDeviceContext));
- ASSERT(SUCCEEDED(hr));
-
+ COMPtr<ID2D1DeviceContext> sourceDeviceContext = platformContext->deviceContext();
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);
+ HRESULT hr = sourceDeviceContext->CreateBitmap(bitmap->GetPixelSize(), nullptr, bytesPerRow.unsafeGet(), bitmapProperties, &sourceCPUBitmap);
if (!SUCCEEDED(hr))
return nullptr;
Modified: trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp 2019-09-29 19:33:37 UTC (rev 250492)
@@ -327,6 +327,22 @@
return bounds;
}
+FloatRect Path::fastBoundingRectForStroke(const PlatformContextDirect2D& platformContext) const
+{
+ if (isNull())
+ return FloatRect();
+
+ float tolerance = 10;
+
+ auto* strokeStyle = const_cast<PlatformContextDirect2D&>(platformContext).strokeStyle();
+
+ D2D1_RECT_F bounds = { };
+ if (!SUCCEEDED(m_path->GetWidenedBounds(platformContext.strokeThickness(), strokeStyle, nullptr, tolerance, &bounds)))
+ return FloatRect();
+
+ return bounds;
+}
+
FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const
{
if (isNull())
Modified: trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.cpp (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.cpp 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.cpp 2019-09-29 19:33:37 UTC (rev 250492)
@@ -29,6 +29,7 @@
#if USE(DIRECT2D)
#include "Direct2DOperations.h"
+#include "Direct2DUtilities.h"
#include <d2d1.h>
namespace WebCore {
@@ -51,8 +52,19 @@
{
m_stateStack.append(State());
m_state = &m_stateStack.last();
+
+ m_deviceContext.query(m_renderTarget.get());
+ RELEASE_ASSERT(!!m_deviceContext);
}
+void PlatformContextDirect2D::setRenderTarget(ID2D1RenderTarget* renderTarget)
+{
+ m_renderTarget = renderTarget;
+
+ m_deviceContext.query(m_renderTarget.get());
+ RELEASE_ASSERT(!!m_deviceContext);
+}
+
ID2D1Layer* PlatformContextDirect2D::clipLayer() const
{
return m_state->m_activeLayer.get();
@@ -74,10 +86,7 @@
{
ASSERT(m_renderTarget);
- // There should always be at least one manually saved state if a restore is being called.
- ASSERT(m_stateStack.size() > 1);
-
- // Can't restore if we never called save.
+ // No need to restore if we don't have a saved element on the stack.
if (m_stateStack.size() == 1)
return;
@@ -278,7 +287,7 @@
{
ASSERT(m_renderTarget);
- while (m_stateStack.size() > 1)
+ if (m_stateStack.size() > 1)
restore();
clearClips(m_state->m_clips);
@@ -292,6 +301,8 @@
WTFLogAlways("Failed in PlatformContextDirect2D::endDraw: hr=%xd, first=%ld, second=%ld", hr, first, second);
--beginDrawCount;
+
+ compositeIfNeeded();
}
void PlatformContextDirect2D::setTags(D2D1_TAG tag1, D2D1_TAG tag2)
@@ -319,6 +330,68 @@
m_state->m_clips.append(clipType);
}
+void PlatformContextDirect2D::compositeIfNeeded()
+{
+ if (!m_compositeSource)
+ return;
+
+ COMPtr<ID2D1BitmapRenderTarget> bitmapTarget(Query, m_renderTarget.get());
+ if (!bitmapTarget)
+ return;
+
+ COMPtr<ID2D1Bitmap> currentCanvas = Direct2D::createBitmapCopyFromContext(bitmapTarget.get());
+ if (!currentCanvas)
+ return;
+
+ COMPtr<ID2D1Effect> effect;
+
+ if (m_compositeMode != D2D1_COMPOSITE_MODE_FORCE_DWORD) {
+ m_deviceContext->CreateEffect(CLSID_D2D1Composite, &effect);
+ effect->SetInput(0, m_compositeSource.get());
+ effect->SetInput(1, currentCanvas.get());
+ effect->SetValue(D2D1_COMPOSITE_PROP_MODE, m_compositeMode);
+ } else if (m_blendMode != D2D1_BLEND_MODE_FORCE_DWORD) {
+ m_deviceContext->CreateEffect(CLSID_D2D1Blend, &effect);
+ effect->SetInput(0, currentCanvas.get());
+ effect->SetInput(1, m_compositeSource.get());
+ effect->SetValue(D2D1_BLEND_PROP_MODE, m_blendMode);
+ }
+
+ if (effect) {
+ m_deviceContext->BeginDraw();
+ m_deviceContext->Clear(D2D1::ColorF(0, 0, 0, 0));
+ m_deviceContext->DrawImage(effect.get());
+ m_deviceContext->EndDraw();
+ }
+
+ m_compositeSource = nullptr;
+}
+
+void PlatformContextDirect2D::setBlendAndCompositeMode(D2D1_BLEND_MODE blend, D2D1_COMPOSITE_MODE mode)
+{
+ if (mode == m_compositeMode && blend == m_blendMode)
+ return;
+
+ // Direct2D handles compositing based on bitmaps. If we are changing the
+ // compositing mode, we need to capture the current state of the rendering
+ // in a bitmap, perform drawing operations until we finish, then handle
+ // the composting of the two layers.
+ COMPtr<ID2D1BitmapRenderTarget> bitmapTarget(Query, m_renderTarget.get());
+ if (!bitmapTarget)
+ return;
+
+ endDraw();
+
+ m_compositeMode = mode;
+ m_blendMode = blend;
+
+ m_compositeSource = Direct2D::createBitmapCopyFromContext(bitmapTarget.get());
+
+ beginDraw();
+
+ m_deviceContext->Clear(D2D1::ColorF(0, 0, 0, 0));
+}
+
} // namespace WebCore
#endif // USE(DIRECT2D)
Modified: trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.h (250491 => 250492)
--- trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.h 2019-09-29 17:25:43 UTC (rev 250491)
+++ trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.h 2019-09-29 19:33:37 UTC (rev 250492)
@@ -53,8 +53,10 @@
~PlatformContextDirect2D();
ID2D1RenderTarget* renderTarget() { return m_renderTarget.get(); }
- void setRenderTarget(ID2D1RenderTarget* renderTarget) { m_renderTarget = renderTarget; }
+ void setRenderTarget(ID2D1RenderTarget*);
+ ID2D1DeviceContext* deviceContext() { return m_deviceContext.get(); }
+
ID3D11Device1* d3dDevice() const { return m_d3dDevice.get(); }
void setD3DDevice(ID3D11Device1* device) { m_d3dDevice = device; }
@@ -103,8 +105,7 @@
void setStrokeThickness(float);
void setDashes(const DashArray&);
- void setBlendMode(D2D1_BLEND_MODE mode) { m_blendMode = mode; }
- void setCompositeMode(D2D1_COMPOSITE_MODE mode) { m_compositeMode = mode; }
+ void setBlendAndCompositeMode(D2D1_BLEND_MODE, D2D1_COMPOSITE_MODE);
void setTags(D2D1_TAG tag1, D2D1_TAG tag2);
void notifyPreDrawObserver();
@@ -114,10 +115,12 @@
private:
void clearClips(Vector<Direct2DLayerType>&);
+ void compositeIfNeeded();
GraphicsContextPlatformPrivate* m_graphicsContextPrivate { nullptr };
COMPtr<ID2D1RenderTarget> m_renderTarget;
+ COMPtr<ID2D1DeviceContext> m_deviceContext;
COMPtr<ID2D1StrokeStyle> m_d2dStrokeStyle;
HashMap<uint32_t, COMPtr<ID2D1SolidColorBrush>> m_solidColoredBrushCache;
@@ -130,6 +133,8 @@
COMPtr<ID3D11Device1> m_d3dDevice;
+ COMPtr<ID2D1Bitmap> m_compositeSource;
+
WTF::Function<void()> m_preDrawHandler;
WTF::Function<void()> m_postDrawHandler;
_______________________________________________ webkit-changes mailing list webkit-changes@lists.webkit.org https://lists.webkit.org/mailman/listinfo/webkit-changes