Bug 1758968 - Clip drawing in DrawTargetD2D1::DrawSurfaceWithShadow. r=gfx-reviewers,nical

DrawSurfaceWithShadow is supposed to ignore transforms but still support clipping.
It appears that DrawTargetD2D1 for some reason never actually implemented clipping.

The DrawImage calls on the DC just need to happen within the bounds of PrepareForDrawing
and FinalizeDrawing. Since PrepareForDrawing handles the overriding of the blend mode
via SetPrimitiveBlend, we need to use DrawImage with D2D1_COMPOSITE_MODE_SOURCE_OVER
so that it will blend appropriately.

Differential Revision: https://phabricator.services.mozilla.com/D140798
This commit is contained in:
Lee Salzman 2022-03-11 10:02:07 +00:00
Родитель cd456428c5
Коммит a1ba0b4ade
4 изменённых файлов: 59 добавлений и 21 удалений

Просмотреть файл

@ -0,0 +1,13 @@
<div style="width: 100px; height: 100px;"><canvas id="canvas" width="100" height="50"></canvas></div>
<script>
var can = document.getElementById('canvas');
var ctx = can.getContext('2d');
ctx.shadowOffsetX = 24;
ctx.shadowOffsetY = 24;
ctx.shadowColor = 'blue';
ctx.shadowBlur = 20;
ctx.fillStyle = 'black';
ctx.fillRect(0,0,40,40);
</script>

Просмотреть файл

@ -0,0 +1,16 @@
<canvas id="canvas" width="100" height="100"></canvas>
<script>
var can = document.getElementById('canvas');
var ctx = can.getContext('2d');
ctx.shadowOffsetX = 24;
ctx.shadowOffsetY = 24;
ctx.shadowColor = 'blue';
ctx.shadowBlur = 20;
ctx.rect(0,0,100,50);
ctx.clip();
ctx.fillStyle = 'black';
ctx.fillRect(0,0,40,40);
</script>

Просмотреть файл

@ -250,3 +250,5 @@ skip-if(Android) == visible-occluded.html visible-occluded-ref.html
== 1719886-1.html 1719886-1-ref.html
skip-if(isDebugBuild) == draw-large-image.html draw-large-image-ref.html
== 1758968-1.html 1758968-1-ref.html

Просмотреть файл

@ -312,8 +312,6 @@ void DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface* aSurface,
return;
}
MarkChanged();
mDC->SetTransform(D2D1::IdentityMatrix());
mTransformDirty = true;
Matrix mat;
RefPtr<ID2D1Image> image =
@ -331,35 +329,44 @@ void DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface* aSurface,
return;
}
// Step 1, create the shadow effect.
if (!PrepareForDrawing(aOperator, ColorPattern(aColor))) {
return;
}
mDC->SetTransform(D2D1::IdentityMatrix());
mTransformDirty = true;
RefPtr<ID2D1Effect> shadowEffect;
HRESULT hr = mDC->CreateEffect(
mFormat == SurfaceFormat::A8 ? CLSID_D2D1GaussianBlur : CLSID_D2D1Shadow,
getter_AddRefs(shadowEffect));
if (FAILED(hr) || !shadowEffect) {
gfxWarning() << "Failed to create shadow effect. Code: " << hexa(hr);
return;
}
shadowEffect->SetInput(0, image);
if (mFormat == SurfaceFormat::A8) {
shadowEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, aSigma);
shadowEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_BORDER_MODE,
D2D1_BORDER_MODE_HARD);
} else {
shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, aSigma);
D2D1_VECTOR_4F color = {aColor.r, aColor.g, aColor.b, aColor.a};
shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, color);
}
if (SUCCEEDED(hr) && shadowEffect) {
shadowEffect->SetInput(0, image);
if (mFormat == SurfaceFormat::A8) {
shadowEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, aSigma);
shadowEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_BORDER_MODE,
D2D1_BORDER_MODE_HARD);
} else {
shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, aSigma);
D2D1_VECTOR_4F color = {aColor.r, aColor.g, aColor.b, aColor.a};
shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, color);
}
D2D1_POINT_2F shadowPoint = D2DPoint(aDest + aOffset);
mDC->DrawImage(shadowEffect, &shadowPoint, nullptr,
D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
D2D1_POINT_2F shadowPoint = D2DPoint(aDest + aOffset);
mDC->DrawImage(shadowEffect, &shadowPoint, nullptr,
D2D1_INTERPOLATION_MODE_LINEAR,
D2D1_COMPOSITE_MODE_SOURCE_OVER);
} else {
gfxWarning() << "Failed to create shadow effect. Code: " << hexa(hr);
}
if (aSurface->GetFormat() != SurfaceFormat::A8) {
D2D1_POINT_2F imgPoint = D2DPoint(aDest);
mDC->DrawImage(image, &imgPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR,
D2DCompositionMode(aOperator));
D2D1_COMPOSITE_MODE_SOURCE_OVER);
}
FinalizeDrawing(aOperator, ColorPattern(aColor));
}
void DrawTargetD2D1::ClearRect(const Rect& aRect) {