Bug 852100 - Part 1. Bring in pixel snap offset while painting source image. draft
authorcku <cku@mozilla.com>
Tue, 15 Aug 2017 16:12:59 +0800
changeset 646650 b657869877b663658453a7fd39248527253a0606
parent 644465 253a8560dc34456d2e8a13065e4b3eb5ecf6704f
child 646651 779b700096e8308b94070f79bb01eb1d27754826
child 646652 e83fb06d070f8560d8f9cd88a0e2c4c8e3018941
push id74196
push userbmo:cku@mozilla.com
push dateTue, 15 Aug 2017 16:17:22 +0000
bugs852100
milestone57.0a1
Bug 852100 - Part 1. Bring in pixel snap offset while painting source image. MozReview-Commit-ID: D58KaMOjeEi
layout/svg/nsFilterInstance.cpp
layout/svg/nsFilterInstance.h
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -369,17 +369,18 @@ nsFilterInstance::ComputeNeededBoxes()
 
   UpdateNeededBounds(sourceGraphicNeededRegion, mSourceGraphic.mNeededBounds);
   UpdateNeededBounds(fillPaintNeededRegion, mFillPaint.mNeededBounds);
   UpdateNeededBounds(strokePaintNeededRegion, mStrokePaint.mNeededBounds);
 }
 
 void
 nsFilterInstance::BuildSourcePaint(SourceInfo *aSource,
-                                   imgDrawingParams& aImgParams)
+                                   imgDrawingParams& aImgParams,
+                                   const Point& aOffset)
 {
   MOZ_ASSERT(mTargetFrame);
   nsIntRect neededRect = aSource->mNeededBounds;
   if (neededRect.IsEmpty()) {
     return;
   }
 
   RefPtr<DrawTarget> offscreenDT =
@@ -389,17 +390,18 @@ nsFilterInstance::BuildSourcePaint(Sourc
     return;
   }
 
   RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(offscreenDT);
   MOZ_ASSERT(ctx); // already checked the draw target above
   gfxContextAutoSaveRestore saver(ctx);
 
   ctx->SetMatrix(mPaintTransform *
-                 gfxMatrix::Translation(-neededRect.TopLeft()));
+                 gfxMatrix::Translation(-neededRect.TopLeft()) *
+                 gfxMatrix::Translation(aOffset.x, aOffset.y));
   GeneralPattern pattern;
   if (aSource == &mFillPaint) {
     nsSVGUtils::MakeFillPatternFor(mTargetFrame, ctx, &pattern, aImgParams);
   } else if (aSource == &mStrokePaint) {
     nsSVGUtils::MakeStrokePatternFor(mTargetFrame, ctx, &pattern, aImgParams);
   }
 
   if (pattern.GetPattern()) {
@@ -407,29 +409,31 @@ nsFilterInstance::BuildSourcePaint(Sourc
                           pattern);
   }
 
   aSource->mSourceSurface = offscreenDT->Snapshot();
   aSource->mSurfaceRect = neededRect;
 }
 
 void
-nsFilterInstance::BuildSourcePaints(imgDrawingParams& aImgParams)
+nsFilterInstance::BuildSourcePaints(imgDrawingParams& aImgParams,
+                                    const Point& aOffset)
 {
   if (!mFillPaint.mNeededBounds.IsEmpty()) {
-    BuildSourcePaint(&mFillPaint, aImgParams);
+    BuildSourcePaint(&mFillPaint, aImgParams, aOffset);
   }
 
   if (!mStrokePaint.mNeededBounds.IsEmpty()) {
-    BuildSourcePaint(&mStrokePaint, aImgParams);
+    BuildSourcePaint(&mStrokePaint, aImgParams, aOffset);
   }
 }
 
 void
-nsFilterInstance::BuildSourceImage(imgDrawingParams& aImgParams)
+nsFilterInstance::BuildSourceImage(imgDrawingParams& aImgParams,
+                                   const Point& aOffset)
 {
   MOZ_ASSERT(mTargetFrame);
 
   nsIntRect neededRect = mSourceGraphic.mNeededBounds;
   if (neededRect.IsEmpty()) {
     return;
   }
 
@@ -459,17 +463,18 @@ nsFilterInstance::BuildSourceImage(imgDr
   // code more complex while being hard to get right without introducing
   // subtle bugs, and in practice it probably makes no real difference.)
   RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(offscreenDT);
   MOZ_ASSERT(ctx); // already checked the draw target above
   gfxMatrix devPxToCssPxTM = nsSVGUtils::GetCSSPxToDevPxMatrix(mTargetFrame);
   DebugOnly<bool> invertible = devPxToCssPxTM.Invert();
   MOZ_ASSERT(invertible);
   ctx->SetMatrix(devPxToCssPxTM * mPaintTransform *
-                 gfxMatrix::Translation(-neededRect.TopLeft()));
+                 gfxMatrix::Translation(-neededRect.TopLeft()) *
+                 gfxMatrix::Translation(aOffset.x, aOffset.y));
 
   mPaintCallback->Paint(*ctx, mTargetFrame, mPaintTransform, &dirty, aImgParams);
 
   mSourceGraphic.mSourceSurface = offscreenDT->Snapshot();
   mSourceGraphic.mSurfaceRect = neededRect;
 }
 
 void
@@ -482,33 +487,35 @@ nsFilterInstance::Render(DrawTarget* aDr
     return;
   }
 
   nsIntRect filterRect =
     mPostFilterDirtyRegion.GetBounds().Intersect(OutputFilterSpaceBounds());
   if (filterRect.IsEmpty() || mPaintTransform.IsSingular()) {
     return;
   }
+  Matrix originMatrix = aDrawTarget->GetTransform();
+  Point snapOffset(originMatrix._31 - int(originMatrix._31),
+                   originMatrix._32 - int(originMatrix._32));
 
   AutoRestoreTransform autoRestoreTransform(aDrawTarget);
-  Matrix newTM =
-    aDrawTarget->GetTransform().PreTranslate(filterRect.x, filterRect.y);
+  Matrix newTM = originMatrix.PreTranslate(filterRect.x, filterRect.y);
   aDrawTarget->SetTransform(newTM);
 
   ComputeNeededBoxes();
 
-  BuildSourceImage(aImgParams);
-  BuildSourcePaints(aImgParams);
+  BuildSourceImage(aImgParams, snapOffset);
+  BuildSourcePaints(aImgParams, snapOffset);
 
   FilterSupport::RenderFilterDescription(
     aDrawTarget, mFilterDescription, IntRectToRect(filterRect),
     mSourceGraphic.mSourceSurface, mSourceGraphic.mSurfaceRect,
     mFillPaint.mSourceSurface, mFillPaint.mSurfaceRect,
     mStrokePaint.mSourceSurface, mStrokePaint.mSurfaceRect,
-    mInputImages, Point(0, 0));
+    mInputImages, Point(-snapOffset.x, -snapOffset.y));
 }
 
 nsRegion
 nsFilterInstance::ComputePostFilterDirtyRegion()
 {
   if (mPreFilterDirtyRegion.IsEmpty() || mPrimitiveDescriptions.IsEmpty()) {
     return nsRegion();
   }
--- a/layout/svg/nsFilterInstance.h
+++ b/layout/svg/nsFilterInstance.h
@@ -51,16 +51,17 @@ class nsFilterInstance
 {
   typedef mozilla::gfx::IntRect IntRect;
   typedef mozilla::gfx::SourceSurface SourceSurface;
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
   typedef mozilla::gfx::FilterDescription FilterDescription;
   typedef mozilla::dom::UserSpaceMetrics UserSpaceMetrics;
   typedef mozilla::image::imgDrawingParams imgDrawingParams;
+  typedef mozilla::gfx::Point Point;
 public:
   /**
    * Create a FilterDescription for the supplied filter. All coordinates in
    * the description are in filter space.
    * @param aFilterInputIsTainted Describes whether the SourceImage / SourceAlpha
    *   input is tainted. This affects whether feDisplacementMap will respect
    *   the filter input as its map input, and it affects the IsTainted() state
    *   on the filter primitives in the FilterDescription. "Tainted" is a term
@@ -216,30 +217,31 @@ private:
     // Set by BuildSourceImage / BuildSourcePaint.
     IntRect mSurfaceRect;
   };
 
   /**
    * Creates a SourceSurface for either the FillPaint or StrokePaint graph
    * nodes
    */
-  void BuildSourcePaint(SourceInfo *aPrimitive, imgDrawingParams& aImgParams);
+  void BuildSourcePaint(SourceInfo *aPrimitive, imgDrawingParams& aImgParams,
+                        const Point& aOffset);
 
   /**
    * Creates a SourceSurface for either the FillPaint and StrokePaint graph
    * nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and
    * mStrokePaint.mSourceSurface respectively.
    */
-  void BuildSourcePaints(imgDrawingParams& aImgParams);
+  void BuildSourcePaints(imgDrawingParams& aImgParams, const Point& aOffset);
 
   /**
    * Creates the SourceSurface for the SourceGraphic graph node, paints its
    * contents, and assigns it to mSourceGraphic.mSourceSurface.
    */
-  void BuildSourceImage(imgDrawingParams& aImgParams);
+  void BuildSourceImage(imgDrawingParams& aImgParams, const Point& aOffset);
 
   /**
    * Build the list of FilterPrimitiveDescriptions that describes the filter's
    * filter primitives and their connections. This populates
    * mPrimitiveDescriptions and mInputImages. aFilterInputIsTainted describes
    * whether the SourceGraphic is tainted.
    */
   nsresult BuildPrimitives(const nsTArray<nsStyleFilter>& aFilterChain,