Bug 1495170. Use CreateClippedDrawTarget more. r=mstange
authorJeff Muizelaar <jrmuizel@gmail.com>
Mon, 04 Mar 2019 22:30:09 -0500
changeset 506850 20d6f233678b8cbbfec09f85c40ae42e21263a72
parent 506849 df0f64d6ae61e707d451d6ab0443e00ef2fbf8b9
child 506851 2858e470c2bcaa361b6809158921b01ed0f12d93
push idunknown
push userunknown
push dateunknown
reviewersmstange
bugs1495170
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1495170. Use CreateClippedDrawTarget more. r=mstange This lets us restrict the size of the mask surface that we allocate to the destination tile size. This gives a large performance improvement. It also includes some miscelanous fixes to the CreateClippedDrawTarget code path. Differential Revision: https://phabricator.services.mozilla.com/D21750
gfx/2d/DrawTargetOffset.cpp
gfx/2d/DrawTargetOffset.h
gfx/2d/RecordedEventImpl.h
layout/painting/nsDisplayList.cpp
layout/svg/nsSVGClipPathFrame.cpp
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGMaskFrame.cpp
--- a/gfx/2d/DrawTargetOffset.cpp
+++ b/gfx/2d/DrawTargetOffset.cpp
@@ -160,16 +160,22 @@ void DrawTargetOffset::PushLayer(bool aO
                                  const IntRect& aBounds, bool aCopyBackground) {
   IntRect bounds = aBounds - mOrigin;
 
   mDrawTarget->PushLayer(aOpaque, aOpacity, aMask, aMaskTransform, bounds,
                          aCopyBackground);
   SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
 }
 
+already_AddRefed<SourceSurface> DrawTargetOffset::IntoLuminanceSource(
+    LuminanceType aLuminanceType, float aOpacity) {
+  return MakeAndAddRef<SourceSurfaceOffset>(
+      DrawTarget::IntoLuminanceSource(aLuminanceType, aOpacity), mOrigin);
+}
+
 void DrawTargetOffset::PushLayerWithBlend(bool aOpaque, Float aOpacity,
                                           SourceSurface* aMask,
                                           const Matrix& aMaskTransform,
                                           const IntRect& aBounds,
                                           bool aCopyBackground,
                                           CompositionOp aOp) {
   IntRect bounds = aBounds - mOrigin;
 
--- a/gfx/2d/DrawTargetOffset.h
+++ b/gfx/2d/DrawTargetOffset.h
@@ -21,17 +21,17 @@ namespace gfx {
 
 class SourceSurfaceOffset : public SourceSurface {
  public:
   SourceSurfaceOffset(RefPtr<SourceSurface> aSurface, IntPoint aOffset)
       : mSurface(aSurface), mOffset(aOffset) {}
   virtual SurfaceType GetType() const override { return SurfaceType::OFFSET; }
   virtual IntSize GetSize() const override { return mSurface->GetSize(); }
   virtual IntRect GetRect() const override {
-    return IntRect(mOffset, mSurface->GetSize());
+    return mSurface->GetRect() + mOffset;
   }
   virtual SurfaceFormat GetFormat() const override {
     return mSurface->GetFormat();
   }
   virtual already_AddRefed<DataSourceSurface> GetDataSurface() override {
     return mSurface->GetDataSurface();
   }
 
@@ -54,16 +54,18 @@ class DrawTargetOffset : public DrawTarg
   }
   virtual DrawTargetType GetType() const override {
     return mDrawTarget->GetType();
   }
   virtual BackendType GetBackendType() const override {
     return mDrawTarget->GetBackendType();
   }
   virtual already_AddRefed<SourceSurface> Snapshot() override;
+  virtual already_AddRefed<SourceSurface> IntoLuminanceSource(
+      LuminanceType aLuminanceType, float aOpacity) override;
   virtual void DetachAllSnapshots() override;
   virtual IntSize GetSize() const override { return mDrawTarget->GetSize(); }
   virtual IntRect GetRect() const override {
     return IntRect(mOrigin, GetSize());
   }
 
   virtual void Flush() override;
   virtual void DrawSurface(SourceSurface *aSurface, const Rect &aDest,
--- a/gfx/2d/RecordedEventImpl.h
+++ b/gfx/2d/RecordedEventImpl.h
@@ -1996,31 +1996,30 @@ inline bool RecordedCreateDrawTargetForF
   return true;
 }
 
 inline bool RecordedCreateClippedDrawTarget::PlayEvent(
     Translator *aTranslator) const {
   const IntRect baseRect = aTranslator->GetReferenceDrawTarget()->GetRect();
   const IntRect transformedRect = RoundedToInt(
       mTransform.Inverse().TransformBounds(IntRectToRect(baseRect)));
-  const IntRect intersection =
+  IntRect intersection =
       IntRect(IntPoint(0, 0), mMaxSize).Intersect(transformedRect);
 
+  // Making 0 size DrawTargets isn't great. So let's make sure we have a size of
+  // at least 1
+  if (intersection.width == 0) intersection.width = 1;
+  if (intersection.height == 0) intersection.height = 1;
+
   RefPtr<DrawTarget> newDT =
       aTranslator->GetReferenceDrawTarget()->CreateSimilarDrawTarget(
-          intersection.Size(), SurfaceFormat::A8);
+          intersection.Size(), mFormat);
   // It's overkill to use a TiledDrawTarget for a single tile
   // but it was the easiest way to get the offset handling working
-  gfx::TileSet tileset;
-  gfx::Tile tile;
-  tile.mDrawTarget = newDT;
-  tile.mTileOrigin = gfx::IntPoint(intersection.X(), intersection.Y());
-  tileset.mTiles = &tile;
-  tileset.mTileCount = 1;
-  newDT = gfx::Factory::CreateTiledDrawTarget(tileset);
+  newDT = gfx::Factory::CreateOffsetDrawTarget(newDT, intersection.TopLeft());
 
   // If we couldn't create a DrawTarget this will probably cause us to crash
   // with nullptr later in the playback, so return false to abort.
   if (!newDT) {
     return false;
   }
 
   aTranslator->AddDrawTarget(mRefPtr, newDT);
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -830,28 +830,29 @@ static bool GenerateAndPushTextMask(nsIF
   LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
       aFillRect, aFrame->PresContext()->AppUnitsPerDevPixel());
 
   // Evaluate required surface size.
   IntRect drawRect =
       RoundedOut(ToRect(sourceCtx->GetClipExtents(gfxContext::eDeviceSpace)));
 
   Matrix currentMatrix = sourceCtx->CurrentMatrix();
-  Matrix maskTransform =
-      currentMatrix * Matrix::Translation(-drawRect.x, -drawRect.y);
-  maskTransform.Invert();
+  Matrix invCurrentMatrix = currentMatrix;
+  invCurrentMatrix.Invert();
+  Matrix maskSurfaceDeviceOffsetTranslation =
+      Matrix::Translation(drawRect.TopLeft());
 
   // Create a mask surface.
   RefPtr<DrawTarget> sourceTarget = sourceCtx->GetDrawTarget();
   if (!sourceTarget->CanCreateSimilarDrawTarget(drawRect.Size(),
                                                 SurfaceFormat::A8)) {
     return false;
   }
   RefPtr<DrawTarget> maskDT = sourceTarget->CreateClippedDrawTarget(
-      drawRect.Size(), maskTransform * currentMatrix, SurfaceFormat::A8);
+      drawRect.Size(), maskSurfaceDeviceOffsetTranslation, SurfaceFormat::A8);
   if (!maskDT || !maskDT->IsValid()) {
     return false;
   }
   RefPtr<gfxContext> maskCtx =
       gfxContext::CreatePreservingTransformOrNull(maskDT);
   MOZ_ASSERT(maskCtx);
   maskCtx->SetMatrix(Matrix::Translation(bounds.TopLeft().ToUnknownPoint()) *
                      currentMatrix * Matrix::Translation(-drawRect.TopLeft()));
@@ -859,18 +860,19 @@ static bool GenerateAndPushTextMask(nsIF
   // Shade text shape into mask A8 surface.
   nsLayoutUtils::PaintFrame(
       maskCtx, aFrame, nsRect(nsPoint(0, 0), aFrame->GetSize()),
       NS_RGB(255, 255, 255), nsDisplayListBuilderMode::GENERATE_GLYPH);
 
   // Push the generated mask into aContext, so that the caller can pop and
   // blend with it.
   RefPtr<SourceSurface> maskSurface = maskDT->Snapshot();
-  sourceCtx->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, 1.0,
-                                   maskSurface, maskTransform);
+  sourceCtx->PushGroupForBlendBack(
+      gfxContentType::COLOR_ALPHA, 1.0, maskSurface,
+      maskSurfaceDeviceOffsetTranslation * invCurrentMatrix);
 
   return true;
 }
 
 /* static */
 void nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(
     Layer* aLayer, nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem,
     nsIFrame* aFrame, DisplayItemType aType) {
--- a/layout/svg/nsSVGClipPathFrame.cpp
+++ b/layout/svg/nsSVGClipPathFrame.cpp
@@ -85,18 +85,18 @@ already_AddRefed<DrawTarget> nsSVGClipPa
   IntRect bounds = RoundedOut(
       ToRect(aReferenceContext.GetClipExtents(gfxContext::eDeviceSpace)));
   if (bounds.IsEmpty()) {
     // We don't need to create a mask surface, all drawing is clipped anyway.
     return nullptr;
   }
 
   DrawTarget* referenceDT = aReferenceContext.GetDrawTarget();
-  RefPtr<DrawTarget> maskDT =
-      referenceDT->CreateSimilarDrawTarget(bounds.Size(), SurfaceFormat::A8);
+  RefPtr<DrawTarget> maskDT = referenceDT->CreateClippedDrawTarget(
+      bounds.Size(), Matrix::Translation(bounds.TopLeft()), SurfaceFormat::A8);
 
   aOffset = bounds.TopLeft();
 
   return maskDT.forget();
 }
 
 static void ComposeExtraMask(DrawTarget* aTarget, SourceSurface* aExtraMask,
                              const Matrix& aExtraMasksTransform) {
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -533,18 +533,19 @@ static MaskPaintResult CreateAndPaintMas
     paintResult.transparentBlackMask = true;
     return paintResult;
   }
 
   if (!ctx.GetDrawTarget()->CanCreateSimilarDrawTarget(maskSurfaceRect.Size(),
                                                        SurfaceFormat::A8)) {
     return paintResult;
   }
-  RefPtr<DrawTarget> maskDT = ctx.GetDrawTarget()->CreateSimilarDrawTarget(
-      maskSurfaceRect.Size(), SurfaceFormat::A8);
+  RefPtr<DrawTarget> maskDT = ctx.GetDrawTarget()->CreateClippedDrawTarget(
+      maskSurfaceRect.Size(), Matrix::Translation(aParams.maskRect.TopLeft()),
+      SurfaceFormat::A8);
   if (!maskDT || !maskDT->IsValid()) {
     return paintResult;
   }
 
   // We can paint mask along with opacity only if
   // 1. There is only one mask, or
   // 2. No overlap among masks.
   // Collision detect in #2 is not that trivial, we only accept #1 here.
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -79,21 +79,25 @@ already_AddRefed<SourceSurface> nsSVGMas
   } else {
     maskType = aParams.maskMode == StyleMaskMode::Luminance
                    ? NS_STYLE_MASK_TYPE_LUMINANCE
                    : NS_STYLE_MASK_TYPE_ALPHA;
   }
 
   RefPtr<DrawTarget> maskDT;
   if (maskType == NS_STYLE_MASK_TYPE_LUMINANCE) {
-    maskDT = context->GetDrawTarget()->CreateSimilarDrawTarget(
-        maskSurfaceSize, SurfaceFormat::B8G8R8A8);
+    maskDT = context->GetDrawTarget()->CreateClippedDrawTarget(
+        maskSurfaceSize,
+        Matrix::Translation(maskSurfaceRect.x, maskSurfaceRect.y),
+        SurfaceFormat::B8G8R8A8);
   } else {
-    maskDT = context->GetDrawTarget()->CreateSimilarDrawTarget(
-        maskSurfaceSize, SurfaceFormat::A8);
+    maskDT = context->GetDrawTarget()->CreateClippedDrawTarget(
+        maskSurfaceSize,
+        Matrix::Translation(maskSurfaceRect.x, maskSurfaceRect.y),
+        SurfaceFormat::A8);
   }
 
   if (!maskDT || !maskDT->IsValid()) {
     return nullptr;
   }
 
   Matrix maskSurfaceMatrix =
       context->CurrentMatrix() *