Bug 1399268 - Disable filtering during Draw3DTransformedSurface() when layer was split
MozReview-Commit-ID: KEvmh2sbOY7
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1171,17 +1171,18 @@ public:
/**
* Draw aSurface using the 3D transform aMatrix. The DrawTarget's transform
* and clip are applied after the 3D transform.
*
* If the transform fails (i.e. because aMatrix is singular), false is returned and nothing is drawn.
*/
virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
- const Matrix4x4& aMatrix);
+ const Matrix4x4& aMatrix,
+ const bool aEnableFilter);
/**
* Push a clip to the DrawTarget.
*
* @param aPath The path to clip to
*/
virtual void PushClip(const Path *aPath) = 0;
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -1992,17 +1992,19 @@ GfxMatrixToPixmanTransform(const Matrix4
{ aMatrix._12, aMatrix._22, aMatrix._42 },
{ aMatrix._14, aMatrix._24, aMatrix._44 }
}};
return pixman_transform_from_pixman_f_transform(aResult, &fTransform);
}
#ifndef USE_SKIA
bool
-DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
+DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface,
+ const Matrix4x4& aMatrix,
+ const bool /* aEnableFilter */)
{
// Composite the 3D transform with the DT's transform.
Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
// Transform the surface bounds and clip to this DT.
IntRect xformBounds =
RoundedOut(
fullMat.TransformAndClipBounds(Rect(Point(0, 0), Size(aSurface->GetSize())),
Rect(Point(0, 0), Size(GetSize()))));
@@ -2115,24 +2117,26 @@ SupportsXRender(cairo_surface_t* surface
cairo_device_release(device);
return true;
}
#endif
bool
-DrawTargetCairo::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
+DrawTargetCairo::Draw3DTransformedSurface(SourceSurface* aSurface,
+ const Matrix4x4& aMatrix,
+ const bool aEnableFilter)
{
#if CAIRO_HAS_XLIB_SURFACE
cairo_surface_t* srcSurf =
aSurface->GetType() == SurfaceType::CAIRO ?
static_cast<SourceSurfaceCairo*>(aSurface)->GetSurface() : nullptr;
if (!SupportsXRender(srcSurf) || !gXRenderHasTransform) {
- return DrawTarget::Draw3DTransformedSurface(aSurface, aMatrix);
+ return DrawTarget::Draw3DTransformedSurface(aSurface, aMatrix, aEnableFilter);
}
Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
IntRect xformBounds =
RoundedOut(
fullMat.TransformAndClipBounds(Rect(Point(0, 0), Size(aSurface->GetSize())),
Rect(Point(0, 0), Size(GetSize()))));
if (xformBounds.IsEmpty()) {
@@ -2196,17 +2200,17 @@ DrawTargetCairo::Draw3DTransformedSurfac
cairo_new_path(mContext);
cairo_rectangle(mContext, xformBounds.x, xformBounds.y, xformBounds.width, xformBounds.height);
cairo_fill(mContext);
cairo_surface_destroy(xformSurf);
return true;
#else
- return DrawTarget::Draw3DTransformedSurface(aSurface, aMatrix);
+ return DrawTarget::Draw3DTransformedSurface(aSurface, aMatrix, aEnableFilter);
#endif
}
bool
DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat)
{
cairo_surface_reference(aSurface);
return InitAlreadyReferenced(aSurface, aSize, aFormat);
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -130,17 +130,18 @@ public:
const Pattern &aMask,
const DrawOptions &aOptions = DrawOptions()) override;
virtual void MaskSurface(const Pattern &aSource,
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aOptions = DrawOptions()) override;
virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
- const Matrix4x4& aMatrix) override;
+ const Matrix4x4& aMatrix,
+ const bool aEnableFilter) override;
virtual void PushClip(const Path *aPath) override;
virtual void PushClipRect(const Rect &aRect) override;
virtual void PopClip() override;
virtual void PushLayer(bool aOpaque, Float aOpacity,
SourceSurface* aMask,
const Matrix& aMaskTransform,
const IntRect& aBounds = IntRect(),
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -1522,17 +1522,19 @@ DrawTargetSkia::MaskSurface(const Patter
gfxDebug() << *this << ": MaskSurface() failed to extract alpha for mask";
return;
}
mCanvas->drawImage(alphaMask, aOffset.x, aOffset.y, &paint.mPaint);
}
bool
-DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
+DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface,
+ const Matrix4x4& aMatrix,
+ const bool aEnableFilter)
{
// Composite the 3D transform with the DT's transform.
Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
if (fullMat.IsSingular()) {
return false;
}
// Transform the surface bounds and clip to this DT.
IntRect xformBounds =
@@ -1569,17 +1571,18 @@ DrawTarget::Draw3DTransformedSurface(Sou
dstSurf->GetData(), dstSurf->Stride()));
if (!dstCanvas) {
return false;
}
// Do the transform.
SkPaint paint;
paint.setAntiAlias(true);
- paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setFilterQuality(aEnableFilter ? kLow_SkFilterQuality
+ : kNone_SkFilterQuality);
paint.setBlendMode(SkBlendMode::kSrc);
SkMatrix xform;
GfxMatrixToSkiaMatrix(fullMat, xform);
dstCanvas->setMatrix(xform);
dstCanvas->drawImage(srcImage, 0, 0, &paint);
dstCanvas->flush();
@@ -1592,34 +1595,37 @@ DrawTarget::Draw3DTransformedSurface(Sou
DrawSurface(dstSurf, Rect(xformBounds), Rect(Point(0, 0), Size(xformBounds.Size())));
SetTransform(origTransform);
return true;
}
bool
-DrawTargetSkia::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
+DrawTargetSkia::Draw3DTransformedSurface(SourceSurface* aSurface,
+ const Matrix4x4& aMatrix,
+ const bool aEnableFilter)
{
if (aMatrix.IsSingular()) {
return false;
}
MarkChanged();
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
if (!image) {
return true;
}
mCanvas->save();
SkPaint paint;
paint.setAntiAlias(true);
- paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setFilterQuality(aEnableFilter ? kLow_SkFilterQuality
+ : kNone_SkFilterQuality);
SkMatrix xform;
GfxMatrixToSkiaMatrix(aMatrix, xform);
mCanvas->concat(xform);
mCanvas->drawImage(image, 0, 0, &paint);
mCanvas->restore();
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -95,17 +95,18 @@ public:
virtual void Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aOptions = DrawOptions()) override;
virtual void MaskSurface(const Pattern &aSource,
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aOptions = DrawOptions()) override;
virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
- const Matrix4x4& aMatrix) override;
+ const Matrix4x4& aMatrix,
+ const bool aEnableFilter) override;
virtual void PushClip(const Path *aPath) override;
virtual void PushClipRect(const Rect& aRect) override;
virtual void PushDeviceSpaceClipRects(const IntRect* aRects, uint32_t aCount) override;
virtual void PopClip() override;
virtual void PushLayer(bool aOpaque, Float aOpacity,
SourceSurface* aMask,
const Matrix& aMaskTransform,
const IntRect& aBounds = IntRect(),
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -834,24 +834,25 @@ BasicCompositor::DrawGeometry(const Geom
}
if (!aTransform.Is2D()) {
dest->Flush();
RefPtr<SourceSurface> destSnapshot = dest->Snapshot();
SetupMask(aEffectChain, buffer, offset, sourceMask, maskTransform);
+ const bool aEnableFilter = aEnableAA;
if (sourceMask) {
RefPtr<DrawTarget> transformDT =
dest->CreateSimilarDrawTarget(IntSize::Truncate(transformBounds.Width(), transformBounds.Height()),
SurfaceFormat::B8G8R8A8);
new3DTransform.PostTranslate(-transformBounds.x, -transformBounds.y, 0);
if (transformDT &&
- transformDT->Draw3DTransformedSurface(destSnapshot, new3DTransform)) {
+ transformDT->Draw3DTransformedSurface(destSnapshot, new3DTransform, aEnableFilter)) {
RefPtr<SourceSurface> transformSnapshot = transformDT->Snapshot();
// Transform the source by it's normal transform, and then the inverse
// of the mask transform so that it's in the mask's untransformed
// coordinate space.
Matrix sourceTransform = newTransform;
sourceTransform.PostTranslate(transformBounds.TopLeft());
@@ -868,17 +869,17 @@ BasicCompositor::DrawGeometry(const Geom
// by the mask transform to put the result back into destination
// coords.
buffer->SetTransform(maskTransform);
buffer->MaskSurface(source, sourceMask, Point(0, 0));
buffer->PopClip();
}
} else {
- buffer->Draw3DTransformedSurface(destSnapshot, new3DTransform);
+ buffer->Draw3DTransformedSurface(destSnapshot, new3DTransform, aEnableFilter);
}
}
buffer->PopClip();
}
void
BasicCompositor::ClearRect(const gfx::Rect& aRect)
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -930,17 +930,17 @@ BasicLayerManager::PaintLayer(gfxContext
effectiveTransform.PreTranslate(bounds.x, bounds.y, 0);
RefPtr<SourceSurface> untransformedSurf = untransformedDT->Snapshot();
RefPtr<DrawTarget> xformDT =
untransformedDT->CreateSimilarDrawTarget(IntSize::Truncate(xformBounds.Width(), xformBounds.Height()),
SurfaceFormat::B8G8R8A8);
RefPtr<SourceSurface> xformSurf;
if(xformDT && untransformedSurf &&
- xformDT->Draw3DTransformedSurface(untransformedSurf, effectiveTransform)) {
+ xformDT->Draw3DTransformedSurface(untransformedSurf, effectiveTransform, true)) {
xformSurf = xformDT->Snapshot();
}
if (xformSurf) {
aTarget->SetPattern(
new gfxPattern(xformSurf,
Matrix::Translation(xformBounds.TopLeft())));
--- a/layout/generic/TextDrawTarget.h
+++ b/layout/generic/TextDrawTarget.h
@@ -358,17 +358,18 @@ public:
void MaskSurface(const Pattern &aSource,
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aOptions) override {
MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
}
bool Draw3DTransformedSurface(SourceSurface* aSurface,
- const Matrix4x4& aMatrix) override {
+ const Matrix4x4& aMatrix,
+ const bool aEnableFilter) override {
MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
}
void PushClip(const Path *aPath) override {
// Fine to pretend we do this
}
void PushClipRect(const Rect &aRect) override {
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -64,17 +64,17 @@ fuzzy-if(winWidget&&!layersGPUAccelerate
fails-if(!layersGPUAccelerated) fails-if(webrender) == 1035611-1.html 1035611-1-ref.html # Bug 1072898 for !layersGPUAccelerated failures
fails-if(webrender) != 1157984-1.html about:blank # Bug 1157984
fuzzy(3,99) == animate-cube-radians.html animate-cube-radians-ref.html # subpixel AA
fuzzy(3,99) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated,16,6) == animate-cube-radians-zoom.html animate-cube-radians-zoom-ref.html
!= animate-cube-radians-ref.html animate-cube-radians-zoom-ref.html
fuzzy(3,99) == animate-cube-degrees.html animate-cube-degrees-ref.html # subpixel AA
== animate-cube-degrees-zoom.html animate-cube-degrees-zoom-ref.html
!= animate-cube-degrees-ref.html animate-cube-degrees-zoom-ref.html
-fuzzy-if(gtkWidget,128,100) fuzzy-if(Android||OSX==1010||(gtkWidget&&layersGPUAccelerated),143,100) fuzzy-if(winWidget||OSX<1010,141,100) == preserves3d-nested.html preserves3d-nested-ref.html
+fuzzy(255,100) == preserves3d-nested.html preserves3d-nested-ref.html
fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-parent.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-child.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
== animate-backface-hidden.html about:blank
== 1245450-1.html green-rect.html
fuzzy(1,2000) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
fuzzy(1,15000) == opacity-preserve3d-2.html opacity-preserve3d-2-ref.html
fuzzy(1,10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
fuzzy(1,10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
@@ -85,8 +85,9 @@ fails-if(webrender) == snap-perspective-
fails-if(webrender) == mask-layer-3.html mask-layer-ref.html
fails-if(webrender) == split-intersect1.html split-intersect1-ref.html
fuzzy(255,150) fails-if(webrender) == split-intersect2.html split-intersect2-ref.html
fuzzy(255,100) fails-if(webrender) == split-non-ortho1.html split-non-ortho1-ref.html
fuzzy-if(winWidget,150,120) == component-alpha-1.html component-alpha-1-ref.html
== nested-transform-1.html nested-transform-1-ref.html
== transform-geometry-1.html transform-geometry-1-ref.html
== intermediate-1.html intermediate-1-ref.html
+fuzzy-if(winWidget||gtkWidget,1,1) == split-seam-1.html split-seam-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/split-seam-1-ref.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="UTF-8">
+<style>
+
+.scene {
+ position: absolute;
+ perspective-origin: 50% 50%;
+ perspective: 1000px;
+ transform-style: preserve-3d;
+}
+
+.element {
+ position: absolute;
+ left: 100px;
+ width: 200px;
+ height: 100px;
+ background: dimgrey;
+}
+
+.top {
+ top: 100px;
+}
+
+.bottom {
+ top: 300px;
+ transform: rotateY(-1deg);
+}
+
+</style>
+</head>
+<body>
+
+<div class="scene">
+ <div class="element top"></div>
+</div>
+<div class="scene">
+ <div class="element bottom"></div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/split-seam-1.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="UTF-8">
+<style>
+
+.scene {
+ position: absolute;
+ perspective-origin: 50% 50%;
+ perspective: 1000px;
+ transform-style: preserve-3d;
+}
+
+.element {
+ position: absolute;
+ left: 100px;
+ width: 200px;
+ height: 100px;
+ background: dimgrey;
+}
+
+.top {
+ top: 100px;
+}
+
+.bottom {
+ top: 300px;
+ transform: rotateY(-1deg);
+}
+
+</style>
+</head>
+<body>
+
+<div class="scene">
+ <div class="element top"></div>
+ <div class="element bottom"></div>
+</div>
+
+</body>
+</html>