Bug 1461849. Include a residual offset for blob images. r=mstange draft
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Wed, 16 May 2018 10:31:27 -0400
changeset 797302 ae96a49c162944f1db8b0a374c1132e6a788d912
parent 797301 ee2a8fa5ef852e9f4065a0c4f9cdecb8215de032
push id110453
push userbmo:jmuizelaar@mozilla.com
push dateFri, 18 May 2018 21:24:06 +0000
reviewersmstange
bugs1461849
milestone62.0a1
Bug 1461849. Include a residual offset for blob images. r=mstange This lets us improve the illuision that there's not an intermediate surface being used when drawing SVG. i.e. if content is transformed by 0.5px the 0.5px transform is included when drawing the SVG content. MozReview-Commit-ID: ChfbTFblVdR
gfx/layers/wr/WebRenderCommandBuilder.cpp
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -310,16 +310,17 @@ struct DIGroup
 
   nsPoint mAnimatedGeometryRootOrigin;
   nsPoint mLastAnimatedGeometryRootOrigin;
   IntRect mInvalidRect;
   nsRect mGroupBounds;
   int32_t mAppUnitsPerDevPixel;
   gfx::Size mScale;
   FrameMetrics::ViewID mScrollId;
+  LayerPoint mResidualOffset;
   LayerIntRect mLayerBounds;
   Maybe<wr::ImageKey> mKey;
   std::vector<RefPtr<SourceSurface>> mExternalSurfaces;
 
   DIGroup()
     : mAppUnitsPerDevPixel(0)
     , mScrollId(FrameMetrics::NULL_SCROLL_ID)
   {
@@ -564,19 +565,19 @@ struct DIGroup
         delete data;
       } else {
         data->mUsed = false;
       }
     }
 
     // Round the bounds out to leave space for unsnapped content
     LayoutDeviceToLayerScale2D scale(mScale.width, mScale.height);
-    LayerIntRect layerBounds = LayerIntRect::FromUnknownRect(mGroupBounds.ScaleToOutsidePixels(mScale.width, mScale.height, aGrouper->mAppUnitsPerDevPixel));
+    LayerIntRect layerBounds = mLayerBounds;
     IntSize dtSize = layerBounds.Size().ToUnknownSize();
-    LayoutDeviceRect bounds = layerBounds / scale;
+    LayoutDeviceRect bounds = (LayerRect(layerBounds) - mResidualOffset) / scale;
 
     if (mInvalidRect.IsEmpty()) {
       GP("Not repainting group because it's empty\n");
       GP("End EndGroup\n");
       if (mKey) {
         PushImage(aBuilder, bounds);
       }
       return;
@@ -960,16 +961,17 @@ Grouper::ConstructGroups(WebRenderComman
           aCommandBuilder->mManager->AddImageKeyForDiscard(groupData->mFollowingGroup.mKey.value());
           groupData->mFollowingGroup.mKey = Nothing();
         }
       }
       groupData->mFollowingGroup.mGroupBounds = currentGroup->mGroupBounds;
       groupData->mFollowingGroup.mAppUnitsPerDevPixel = currentGroup->mAppUnitsPerDevPixel;
       groupData->mFollowingGroup.mLayerBounds = currentGroup->mLayerBounds;
       groupData->mFollowingGroup.mScale = currentGroup->mScale;
+      groupData->mFollowingGroup.mResidualOffset = currentGroup->mResidualOffset;
 
       currentGroup = &groupData->mFollowingGroup;
 
       startOfCurrentGroup = item->GetAbove();
     } else { // inactive item
 
       if (item->GetType() == DisplayItemType::TYPE_TRANSFORM) {
         nsDisplayTransform* transformItem = static_cast<nsDisplayTransform*>(item);
@@ -1041,16 +1043,34 @@ Grouper::ConstructGroupInsideInactive(We
 
     BlobItemData* data = GetBlobItemDataForGroup(item, currentGroup);
     currentGroup->ComputeGeometryChange(item, data, mTransform, mDisplayListBuilder); // we compute the geometry change here because we have the transform around still
 
     item = item->GetAbove();
   }
 }
 
+/* This is just a copy of nsRect::ScaleToOutsidePixels with an offset added in.
+ * The offset is applied just before the rounding. It's in the scaled space. */
+static mozilla::gfx::IntRect
+ScaleToOutsidePixelsOffset(nsRect aRect, float aXScale, float aYScale,
+                           nscoord aAppUnitsPerPixel, LayerPoint aOffset)
+{
+  mozilla::gfx::IntRect rect;
+  rect.SetNonEmptyBox(NSToIntFloor(NSAppUnitsToFloatPixels(aRect.x,
+                                                           float(aAppUnitsPerPixel)) * aXScale + aOffset.x),
+                      NSToIntFloor(NSAppUnitsToFloatPixels(aRect.y,
+                                                           float(aAppUnitsPerPixel)) * aYScale + aOffset.y),
+                      NSToIntCeil(NSAppUnitsToFloatPixels(aRect.XMost(),
+                                                          float(aAppUnitsPerPixel)) * aXScale + aOffset.x),
+                      NSToIntCeil(NSAppUnitsToFloatPixels(aRect.YMost(),
+                                                          float(aAppUnitsPerPixel)) * aYScale + aOffset.y));
+  return rect;
+}
+
 void
 WebRenderCommandBuilder::DoGroupingForDisplayList(nsDisplayList* aList,
                                                   nsDisplayItem* aWrappingItem,
                                                   nsDisplayListBuilder* aDisplayListBuilder,
                                                   const StackingContextHelper& aSc,
                                                   wr::DisplayListBuilder& aBuilder,
                                                   wr::IpcResourceUpdateQueue& aResources)
 {
@@ -1066,21 +1086,26 @@ WebRenderCommandBuilder::DoGroupingForDi
   g.mDisplayListBuilder = aDisplayListBuilder;
   RefPtr<WebRenderGroupData> groupData = CreateOrRecycleWebRenderUserData<WebRenderGroupData>(aWrappingItem);
   bool snapped;
   nsRect groupBounds = aWrappingItem->GetBounds(aDisplayListBuilder, &snapped);
   DIGroup& group = groupData->mSubGroup;
   auto p = group.mGroupBounds;
   auto q = groupBounds;
   gfx::Size scale = aSc.GetInheritedScale();
+  auto trans = ViewAs<LayerPixel>(aSc.GetSnappingSurfaceTransform().GetTranslation());
+  auto snappedTrans = LayerIntPoint::Floor(trans);
+  LayerPoint residualOffset = trans - snappedTrans;
+
   GP("Inherrited scale %f %f\n", scale.width, scale.height);
   GP("Bounds: %d %d %d %d vs %d %d %d %d\n", p.x, p.y, p.width, p.height, q.x, q.y, q.width, q.height);
   if (!group.mGroupBounds.IsEqualEdges(groupBounds) ||
       group.mAppUnitsPerDevPixel != appUnitsPerDevPixel ||
-      group.mScale != scale) {
+      group.mScale != scale ||
+      group.mResidualOffset != residualOffset) {
     if (group.mAppUnitsPerDevPixel != appUnitsPerDevPixel) {
       GP("app unit %d %d\n", group.mAppUnitsPerDevPixel, appUnitsPerDevPixel);
     }
     // The bounds have changed so we need to discard the old image and add all
     // the commands again.
     auto p = group.mGroupBounds;
     auto q = groupBounds;
     GP("Bounds change: %d %d %d %d vs %d %d %d %d\n", p.x, p.y, p.width, p.height, q.x, q.y, q.width, q.height);
@@ -1094,22 +1119,28 @@ WebRenderCommandBuilder::DoGroupingForDi
   }
 
   FrameMetrics::ViewID scrollId = FrameMetrics::NULL_SCROLL_ID;
   if (const ActiveScrolledRoot* asr = aWrappingItem->GetActiveScrolledRoot()) {
     scrollId = asr->GetViewId();
   }
 
   g.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
-  g.mTransform = Matrix::Scaling(scale.width, scale.height);
+  group.mResidualOffset = residualOffset;
+  group.mGroupBounds = groupBounds;
   group.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
-  group.mGroupBounds = groupBounds;
+  group.mLayerBounds = LayerIntRect::FromUnknownRect(ScaleToOutsidePixelsOffset(group.mGroupBounds,
+                                                                                scale.width,
+                                                                                scale.height,
+                                                                                group.mAppUnitsPerDevPixel,
+                                                                                residualOffset));
+  g.mTransform = Matrix::Scaling(scale.width, scale.height)
+                                .PostTranslate(residualOffset.x, residualOffset.y);
   group.mScale = scale;
   group.mScrollId = scrollId;
-  group.mLayerBounds = LayerIntRect::FromUnknownRect(group.mGroupBounds.ScaleToOutsidePixels(scale.width, scale.height, group.mAppUnitsPerDevPixel));
   group.mAnimatedGeometryRootOrigin = group.mGroupBounds.TopLeft();
   g.ConstructGroups(this, aBuilder, aResources, &group, aList, aSc);
   mClipManager.EndList(aSc);
 }
 
 void
 WebRenderCommandBuilder::Destroy()
 {