Bug 1319407 - Apply clip-path to each frame when box-decoration-break is clone. r=cjku,heycam draft
authorLouis Chang <lochang@mozilla.com>
Mon, 24 Jul 2017 11:14:47 +0800
changeset 614089 79f482236ad377948f94a69e2648d07a24a49e2b
parent 614088 7accd152f3e0ebe51dd91427413419be545477a4
child 614090 7cdb6f6630bf7ffeb9f49f34b18536f2299b6eb9
push id69912
push userlochang@mozilla.com
push dateMon, 24 Jul 2017 03:54:33 +0000
reviewerscjku, heycam
bugs1319407
milestone56.0a1
Bug 1319407 - Apply clip-path to each frame when box-decoration-break is clone. r=cjku,heycam MozReview-Commit-ID: E7IR49MzkWm
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/painting/nsDisplayList.cpp
layout/svg/nsSVGIntegrationUtils.cpp
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3905,19 +3905,19 @@ nsLayoutUtils::BinarySearchForPosition(D
                                 aBaseInx, inx, aEndInx, aCursorPos, aIndex,
                                 aTextWidth)) {
       return true;
     }
   }
   return false;
 }
 
-static void
-AddBoxesForFrame(nsIFrame* aFrame,
-                 nsLayoutUtils::BoxCallback* aCallback)
+void
+nsLayoutUtils::AddBoxesForFrame(nsIFrame* aFrame,
+                                nsLayoutUtils::BoxCallback* aCallback)
 {
   nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
 
   if (pseudoType == nsCSSAnonBoxes::tableWrapper) {
     AddBoxesForFrame(aFrame->PrincipalChildList().FirstChild(), aCallback);
     if (aCallback->mIncludeCaptionBoxForTable) {
       nsIFrame* kid = aFrame->GetChildList(nsIFrame::kCaptionList).FirstChild();
       if (kid) {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1150,16 +1150,21 @@ public:
    * continuations, "drilling down" through table wrapper frames and
    * some anonymous blocks since they're not real CSS boxes.
    * If aFrame is null, no boxes are returned.
    * SVG frames return a single box, themselves.
    */
   static void GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback);
 
   /**
+   * Like GetAllInFlowBoxes, but doesn't include continuations.
+   */
+  static void AddBoxesForFrame(nsIFrame* aFrame, BoxCallback* aCallback);
+
+  /**
    * Find the first frame descendant of aFrame (including aFrame) which is
    * not an anonymous frame that getBoxQuads/getClientRects should ignore.
    */
   static nsIFrame* GetFirstNonAnonymousFrame(nsIFrame* aFrame);
 
   class RectCallback {
   public:
     virtual void AddRect(const nsRect& aRect) = 0;
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8576,16 +8576,22 @@ nsDisplayMask::~nsDisplayMask()
 }
 #endif
 
 bool nsDisplayMask::TryMerge(nsDisplayItem* aItem)
 {
   if (aItem->GetType() != TYPE_MASK)
     return false;
 
+  // Do not merge items for box-decoration-break:clone elements,
+  // since each box should have its own mask in that case.
+  if (mFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone) {
+    return false;
+  }
+
   // items for the same content element should be merged into a single
   // compositing group
   // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
   if (aItem->Frame()->GetContent() != mFrame->GetContent()) {
     return false;
   }
   if (aItem->GetClipChain() != GetClipChain()) {
     return false;
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -132,16 +132,31 @@ GetPreEffectsVisualOverflowUnion(nsIFram
                                               aCurrentFramePreEffectsOverflow,
                                               aInReflow);
   // Compute union of all overflow areas relative to aFirstContinuation:
   nsLayoutUtils::GetAllInFlowBoxes(aFirstContinuation, &collector);
   // Return the result in user space:
   return collector.GetResult() + aFirstContinuationToUserSpace;
 }
 
+static nsRect
+GetPreEffectsVisualOverflow(nsIFrame* aFirstContinuation,
+                            nsIFrame* aCurrentFrame,
+                            const nsPoint& aFirstContinuationToUserSpace)
+{
+  PreEffectsVisualOverflowCollector collector(aFirstContinuation,
+                                              nullptr,
+                                              nsRect(),
+                                              false);
+  // Compute overflow areas of current frame relative to aFirstContinuation:
+  nsLayoutUtils::AddBoxesForFrame(aCurrentFrame, &collector);
+  // Return the result in user space:
+  return collector.GetResult() + aFirstContinuationToUserSpace;
+}
+
 
 bool
 nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame)
 {
   // Even when SVG display lists are disabled, returning true for SVG frames
   // does not adversely affect any of our callers. Therefore we don't bother
   // checking the SDL prefs here, since we don't know if we're being called for
   // painting or hit-testing anyway.
@@ -206,19 +221,26 @@ nsSVGIntegrationUtils::GetSVGBBoxForNonS
   NS_ASSERTION(!(aNonSVGFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT),
                "Frames with SVG layout should not get here");
   MOZ_ASSERT(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG) ||
              aNonSVGFrame->IsSVGOuterSVGFrame());
 
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(aNonSVGFrame);
   // 'r' is in "user space":
-  nsRect r = GetPreEffectsVisualOverflowUnion(firstFrame, nullptr, nsRect(),
-                                              GetOffsetToBoundingBox(firstFrame),
-                                              false);
+  nsRect r;
+  if (aNonSVGFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone) {
+    r = GetPreEffectsVisualOverflow(firstFrame, aNonSVGFrame,
+                                    GetOffsetToBoundingBox(firstFrame));
+  } else {
+    r = GetPreEffectsVisualOverflowUnion(firstFrame, nullptr, nsRect(),
+                                         GetOffsetToBoundingBox(firstFrame),
+                                         false);
+  }
+
   return nsLayoutUtils::RectToGfxRect(r,
            aNonSVGFrame->PresContext()->AppUnitsPerCSSPixel());
 }
 
 // XXX Since we're called during reflow, this method is broken for frames with
 // continuations. When we're called for a frame with continuations, we're
 // called for each continuation in turn as it's reflowed. However, it isn't
 // until the last continuation is reflowed that this method's