Bug 1311270 - Part 5. Handle rendering of mask-clip:fill-box/stroke-box/view-box. draft
authorcku <cku@mozilla.com>
Wed, 23 Nov 2016 18:23:32 +0800
changeset 453291 bfd590b7897c7b1eebda7b642afcdd0bddb3faea
parent 453290 74732dd4185f554e226c712738592448df215798
child 453292 d9925011bd36dc82dccdb9ffb8fdcb7c085ccc33
push id39618
push userbmo:cku@mozilla.com
push dateFri, 23 Dec 2016 04:25:44 +0000
bugs1311270
milestone53.0a1
Bug 1311270 - Part 5. Handle rendering of mask-clip:fill-box/stroke-box/view-box. MozReview-Commit-ID: JhInquHEgmy
layout/painting/nsCSSRendering.cpp
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1894,54 +1894,119 @@ SetupDirtyRects(const nsRect& aBGClipAre
   // Compute the Thebes equivalent of the dirtyRect.
   *aDirtyRectGfx = nsLayoutUtils::RectToGfxRect(*aDirtyRect, aAppUnitsPerPixel);
   NS_WARNING_ASSERTION(aDirtyRect->IsEmpty() || !aDirtyRectGfx->IsEmpty(),
                        "converted dirty rect should not be empty");
   MOZ_ASSERT(!aDirtyRect->IsEmpty() || aDirtyRectGfx->IsEmpty(),
              "second should be empty if first is");
 }
 
+static bool
+IsSVGStyleGeometryBox(StyleGeometryBox aBox)
+{
+  return (aBox == StyleGeometryBox::Fill || aBox == StyleGeometryBox::Stroke ||
+          aBox == StyleGeometryBox::View);
+}
+
+static bool
+IsHTMLStyleGeometryBox(StyleGeometryBox aBox)
+{
+  return (aBox == StyleGeometryBox::Content ||
+          aBox == StyleGeometryBox::Padding ||
+          aBox == StyleGeometryBox::Border ||
+          aBox == StyleGeometryBox::Margin);
+}
+
+static StyleGeometryBox
+ComputeBoxValue(nsIFrame* aForFrame, StyleGeometryBox aBox)
+{
+  // Except <svg>, all svg elements are not associate with CSS layout box.
+  if (aForFrame->IsFrameOfType(nsIFrame::eSVG) &&
+      (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)) {
+    // For SVG elements without associated CSS layout box, the values
+    // content-box, padding-box, border-box and margin-box compute to fill-box.
+    if (IsHTMLStyleGeometryBox(aBox)) {
+      return StyleGeometryBox::Fill;
+    }
+  } else {
+    // For elements with associated CSS layout box, the values fill-box,
+    // stroke-box and view-box compute to the initial value of mask-clip.
+    if (IsSVGStyleGeometryBox(aBox)) {
+      return StyleGeometryBox::Border;
+    }
+  }
+
+  return aBox;
+}
+
 /* static */ void
 nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer,
                                   nsIFrame* aForFrame, const nsStyleBorder& aBorder,
                                   const nsRect& aBorderArea, const nsRect& aCallerDirtyRect,
                                   bool aWillPaintBorder, nscoord aAppUnitsPerPixel,
                                   /* out */ ImageLayerClipState* aClipState)
 {
-  StyleGeometryBox backgroundClip = aLayer.mClip;
+  StyleGeometryBox backgroundClip = ComputeBoxValue(aForFrame, aLayer.mClip);
+
+  if (IsSVGStyleGeometryBox(backgroundClip)) {
+    MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) &&
+               (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame));
+
+    aClipState->mHasAdditionalBGClipArea = false;
+    aClipState->mCustomClip = false;
+
+    // The coordinate space of clipArea is svg user space.
+    nsRect clipArea =
+      nsLayoutUtils::ComputeGeometryBox(aForFrame, backgroundClip);
+
+    nsRect strokeBox = (backgroundClip == StyleGeometryBox::Stroke)
+      ? clipArea
+      : nsLayoutUtils::ComputeGeometryBox(aForFrame, StyleGeometryBox::Stroke);
+    nsRect clipAreaRelativeToStrokeBox = clipArea - strokeBox.TopLeft();
+
+    // aBorderArea is the stroke-box area in a coordinate space defined by
+    // the caller. This coordinate space can be svg user space of aForFrame,
+    // the space of aForFrame's reference-frame, or anything else.
+    //
+    // Which coordinate space chosen for aBorderArea is not matter. What
+    // matter is to ensure returning aClipState->mBGClipArea in the consistent
+    // coordiante space with aBorderArea. So we evaluate the position of clip
+    // area base on the position of aBorderArea here.
+    aClipState->mBGClipArea =
+      clipAreaRelativeToStrokeBox + aBorderArea.TopLeft();
+
+    SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect,
+                    aAppUnitsPerPixel, &aClipState->mDirtyRect,
+                    &aClipState->mDirtyRectGfx);
+    return;
+  }
 
   if (backgroundClip == StyleGeometryBox::NoClip) {
     aClipState->mBGClipArea = aCallerDirtyRect;
     aClipState->mHasAdditionalBGClipArea = false;
     aClipState->mCustomClip = false;
 
     SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect,
                     aAppUnitsPerPixel, &aClipState->mDirtyRect,
                     &aClipState->mDirtyRectGfx);
     return;
   }
 
+  MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) ||
+             aForFrame->GetType() == nsGkAtoms::svgOuterSVGFrame);
+
   // Compute the outermost boundary of the area that might be painted.
   // Same coordinate space as aBorderArea.
   Sides skipSides = aForFrame->GetSkipSides();
   nsRect clipBorderArea =
     ::BoxDecorationRectForBorder(aForFrame, aBorderArea, skipSides, &aBorder);
 
   bool haveRoundedCorners = GetRadii(aForFrame, aBorder, aBorderArea,
                                      clipBorderArea, aClipState->mRadii);
 
-  // XXX TODO: bug 1303623 only implements the parser of fill-box|stroke-box|view-box|no-clip.
-  // So we need to fallback to default value when rendering. We should remove this
-  // in bug 1311270.
-  if (backgroundClip == StyleGeometryBox::Fill ||
-      backgroundClip == StyleGeometryBox::Stroke ||
-      backgroundClip == StyleGeometryBox::View) {
-    backgroundClip = StyleGeometryBox::Border;
-  }
-
   bool isSolidBorder =
       aWillPaintBorder && IsOpaqueBorder(aBorder);
   if (isSolidBorder && backgroundClip == StyleGeometryBox::Border) {
     // If we have rounded corners, we need to inflate the background
     // drawing area a bit to avoid seams between the border and
     // background.
     backgroundClip = haveRoundedCorners
                      ? StyleGeometryBox::MozAlmostPadding