Bug 988653 - Fix 'border-image' layout for fragmented boxes and add support for both box-decoration-break:clone/slice. r=cam
authorMats Palmgren <matspal@gmail.com>
Mon, 05 May 2014 17:55:55 +0000
changeset 181575 75cafc47ff36efd9105771e2a0e1de9317de174c
parent 181574 06da59d29a4854ec7bc8295db751c45e340625ae
child 181576 e2e7cad0ccaeb1bb0c9718273bc7839ec507ff42
push id43092
push usermpalmgren@mozilla.com
push dateMon, 05 May 2014 17:56:10 +0000
treeherdermozilla-inbound@75cafc47ff36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscam
bugs988653
milestone32.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 988653 - Fix 'border-image' layout for fragmented boxes and add support for both box-decoration-break:clone/slice. r=cam
layout/base/nsCSSRendering.cpp
layout/reftests/css-break/box-decoration-break-border-image-ref.html
layout/reftests/css-break/box-decoration-break-border-image.html
layout/reftests/css-break/reftest.list
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -368,17 +368,18 @@ struct ColorStop {
 };
 
 /* Local functions */
 static void DrawBorderImage(nsPresContext* aPresContext,
                             nsRenderingContext& aRenderingContext,
                             nsIFrame* aForFrame,
                             const nsRect& aBorderArea,
                             const nsStyleBorder& aStyleBorder,
-                            const nsRect& aDirtyRect);
+                            const nsRect& aDirtyRect,
+                            int aSkipSides);
 
 static nscolor MakeBevelColor(mozilla::css::Side whichSide, uint8_t style,
                               nscolor aBackgroundColor,
                               nscolor aBorderColor);
 
 static InlineBackgroundData* gInlineBGData = nullptr;
 
 // Initialize any static variables used by nsCSSRendering.
@@ -626,34 +627,34 @@ nsCSSRendering::PaintBorderWithStyleBord
   if (displayData->mAppearance) {
     nsITheme *theme = aPresContext->GetTheme();
     if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance))
       return; // Let the theme handle it.
   }
 
   if (aStyleBorder.IsBorderImageLoaded()) {
     DrawBorderImage(aPresContext, aRenderingContext, aForFrame,
-                    aBorderArea, aStyleBorder, aDirtyRect);
+                    aBorderArea, aStyleBorder, aDirtyRect, aSkipSides);
     return;
   }
 
   // Get our style context's color struct.
   const nsStyleColor* ourColor = aStyleContext->StyleColor();
 
   // In NavQuirks mode we want to use the parent's context as a starting point
   // for determining the background color.
   bool quirks = aPresContext->CompatibilityMode() == eCompatibility_NavQuirks;
   nsIFrame* bgFrame = FindNonTransparentBackgroundFrame(aForFrame, quirks);
   nsStyleContext* bgContext = bgFrame->StyleContext();
   nscolor bgColor =
     bgContext->GetVisitedDependentColor(eCSSProperty_background_color);
 
   nsMargin border = aStyleBorder.GetComputedBorder();
-  if ((0 == border.left) && (0 == border.right) &&
-      (0 == border.top) && (0 == border.bottom)) {
+  if (0 == border.left && 0 == border.right &&
+      0 == border.top  && 0 == border.bottom) {
     // Empty border area
     return;
   }
 
   // Compute the outermost boundary of the area that might be painted.
   // Same coordinate space as aBorderArea & aBGClipRect.
   nsRect joinedBorderArea =
     ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aStyleBorder);
@@ -3196,17 +3197,18 @@ nsCSSRendering::AreAllBackgroundImagesDe
 }
 
 static void
 DrawBorderImage(nsPresContext*       aPresContext,
                 nsRenderingContext&  aRenderingContext,
                 nsIFrame*            aForFrame,
                 const nsRect&        aBorderArea,
                 const nsStyleBorder& aStyleBorder,
-                const nsRect&        aDirtyRect)
+                const nsRect&        aDirtyRect,
+                int                  aSkipSides)
 {
   NS_PRECONDITION(aStyleBorder.IsBorderImageLoaded(),
                   "drawing border image that isn't successfully loaded");
 
   if (aDirtyRect.IsEmpty())
     return;
 
   nsImageRenderer renderer(aForFrame, &aStyleBorder.mBorderImageSource, 0);
@@ -3218,20 +3220,49 @@ DrawBorderImage(nsPresContext*       aPr
   // different style, they'll potentially have the wrong size for the
   // border too.
   aForFrame->AssociateImage(aStyleBorder.mBorderImageSource, aPresContext);
 
   if (!renderer.PrepareImage()) {
     return;
   }
 
+  // NOTE: no Save() yet, we do that later by calling autoSR.EnsureSaved()
+  // in case we need it.
+  gfxContextAutoSaveRestore autoSR;
+
   // Determine the border image area, which by default corresponds to the
   // border box but can be modified by 'border-image-outset'.
-  nsRect borderImgArea(aBorderArea);
-  borderImgArea.Inflate(aStyleBorder.GetImageOutset());
+  // Note that 'border-radius' do not apply to 'border-image' borders per
+  // <http://dev.w3.org/csswg/css-backgrounds/#corner-clipping>.
+  nsRect borderImgArea;
+  nsMargin borderWidths(aStyleBorder.GetComputedBorder());
+  nsMargin imageOutset(aStyleBorder.GetImageOutset());
+  if (::IsBoxDecorationSlice(aStyleBorder) && aSkipSides != 0) {
+    borderImgArea =
+      ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aStyleBorder);
+    if (borderImgArea.IsEqualEdges(aBorderArea)) {
+      // No need for a clip, just skip the sides we don't want.
+      ::ApplySkipSides(aSkipSides, &borderWidths);
+      ::ApplySkipSides(aSkipSides, &imageOutset);
+      borderImgArea.Inflate(imageOutset);
+    } else {
+      // We're drawing borders around the joined continuation boxes so we need
+      // to clip that to the slice that we want for this frame.
+      borderImgArea.Inflate(imageOutset);
+      ::ApplySkipSides(aSkipSides, &imageOutset);
+      nsRect clip = aBorderArea;
+      clip.Inflate(imageOutset);
+      autoSR.EnsureSaved(aRenderingContext.ThebesContext());
+      aRenderingContext.IntersectClip(clip);
+    }
+  } else {
+    borderImgArea = aBorderArea;
+    borderImgArea.Inflate(imageOutset);
+  }
 
   // Calculate the image size used to compute slice points.
   CSSSizeOrRatio intrinsicSize = renderer.ComputeIntrinsicSize();
   nsSize imageSize = nsImageRenderer::ComputeConcreteSize(CSSSizeOrRatio(),
                                                           intrinsicSize,
                                                           borderImgArea.Size());
   renderer.SetPreferredSize(intrinsicSize, imageSize);
 
@@ -3260,17 +3291,16 @@ DrawBorderImage(nsPresContext*       aPr
         break;
     }
     if (value < 0)
       value = 0;
     if (value > imgDimension)
       value = imgDimension;
     slice.Side(s) = value;
 
-    nsMargin borderWidths(aStyleBorder.GetComputedBorder());
     coord = aStyleBorder.mBorderImageWidth.Get(s);
     switch (coord.GetUnit()) {
       case eStyleUnit_Coord: // absolute dimension
         value = coord.GetCoordValue();
         break;
       case eStyleUnit_Percent:
         value = coord.GetPercentValue() * borderDimension;
         break;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-border-image-ref.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Testcase for border-image + box-decoration-break</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=988653">
+  <meta charset="utf-8">
+  <style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+* { font-family: DejaVuSansMono; }
+
+html,body {
+  color:black; background-color:white; font-size:16px; padding:0; padding-left:10px; margin:0;
+}
+
+b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,.b.clone {
+  border: 5px solid red;
+  border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD%2FgAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAoUlEQVR42u3bwQ0AIAgEwcOmtXttgScmsxWQCTyp3EysJo61IliwYMGCBUuwYMGCBQuWYMGCBQsWLMGCBQsWLFiCBQsWLFiwBAsWLFiwYAkWLFiwYMESLFiwYMGCpXaVka%2BsO8dmOUNYggULFixYsAQLFixYsGAJFixYsGDBEixYsGDBgiVYsGDBggVLsGDBggULlmDBggULFizBggUL1t89N%2FYEtBGStpoAAAAASUVORK5CYII%3D) 10 10 repeat;
+  border-image-outset: 7px 3px 5px 9px;
+}
+.b {
+  border: 5px solid transparent;
+  background: pink;
+}
+.b.clone {
+  background: pink;
+  height:28px;
+}
+.col3 .b.clone {
+  height:32px;
+}
+
+.columns {
+  -moz-columns: 2;
+  width: 200px;
+  height: 50px;
+  background: grey;
+  margin-right: 20px;
+  margin-bottom: 20px;
+  float:left;
+}
+.col3 {
+  -moz-columns: 3;
+}
+.vbreak { height:65px; width:41px; }
+.h { width:30px;height:30px; background:grey; }
+.m { margin-left:15px; }
+.col3 .vbreak { height:115px; }
+x { display:inline-block; width:31px; height:18px; line-height:1; }
+y { display:inline-block; width:47px; height:18px; line-height:1; }
+pos1 { position:absolute; top:50px; width:700px; }
+pos2 { position:absolute; top:150px; width:700px; }
+pos3 { position:absolute; top:380px; width:700px; }
+pos4 { position:absolute; top:510px; width:700px; }
+
+b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10 {position:absolute;}
+c1,c2,c3,c4,c5,c6,c7,c8,c9,c10 {position:absolute; overflow:hidden; z-index:1;}
+
+
+b1 { top:50px; left:20px; height:65px; width:41px; }
+c1 { top:0; left:0; height:88px; width:200px; }
+
+b2 { top:-38px; left:128px; height:66px; width:41px; }
+c2 { top:50px; left:0; height:61px; width:200px; }
+
+b3 { top:50px; left:240px; height:115px; width:41px; }
+c3 { top:0; left:0; height:92px; width:600px; }
+
+b4 { top:-42px; left:312px; height:115px; width:41px; }
+c4 { top:50px; left:0; height:42px; width:600px; }
+
+b5 { top:-84px; left:384px; height:116px; width:41px; }
+c5 { top:50px; left:0; height:100px; width:600px; }
+
+b6 { top:148px; left:20px; height:19px; z-index:1; }
+m6 { top:135px; left:56px; height:55px; width:100px; background:white; z-index:2; }
+
+b7 { top:30px; left:-36px; width:78px; height:19px; }
+c7 { top:170px; left:20px; height:300px; width:200px; }
+
+b8 { top:30px; left:77px; width:125px; height:19px; }
+m8 { top:15px; left:113px; width:125px; height:55px; background:white; }
+c8 { top:170px; left:20px; height:300px; width:600px; }
+
+b9 { top:30px; left:-36px; width:125px; height:19px; }
+c9 { top:222px; left:20px; height:300px; width:47px; }
+
+b10 { top:30px; left:-83px; width:125px; height:19px; }
+c10 { top:274px; left:20px; height:300px; width:156px; }
+
+  </style>
+</head>
+<body>
+<c1><b1></b1></c1>
+<c2><b2></b2></c2>
+<c3><b3></b3></c3>
+<c4><b4></b4></c4>
+<c5><b5></b5></c5>
+<b6><x></x><y></y><br></b6><m6></m6>
+<c7><b7><x></x><y></y></b7></c7>
+<c8><b8><x></x><y></y><y></y></b8><m8></m8></c8>
+<c9><b9><x></x><y></y><y></y></b9></c9>
+<c10><b10><x></x><y></y><y></y></b10></c10>
+<pre>box-decoration-break:slice</pre>
+
+<pos1>
+<div class="columns"><div class="b vbreak slice"></div></div>
+<div class="columns col3"><div class="b vbreak slice"></div></div>
+</pos1>
+
+<pos2>
+<span class="b slice"><x></x><div class="h"></div><y></y></span>
+<span class="b slice m"><x></x><div class="h"></div><y></y><div class="h"></div><y></y></span>
+
+<pre>box-decoration-break:clone</pre>
+</pos2>
+
+<pos3>
+<div class="columns"><div class="b vbreak clone"></div><div class="b vbreak clone"></div></div>
+<div class="columns col3"><div class="b vbreak clone"></div><div class="b vbreak clone"></div><div class="b vbreak clone"></div></div>
+</pos3>
+
+<pos4>
+<span class="b clone"><x></x></span><div class="h"></div><span class="b clone"><y></y></span>
+<span class="b clone m"><x></x></span><div class="h"></div><span class="b clone m"><y></y></span><div class="h"></div><span class="b clone m"><y></y></span>
+</pos4>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-border-image.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Testcase for border-image + box-decoration-break</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=988653">
+  <link rel="help" href="http://dev.w3.org/csswg/css-break/#break-decoration">
+  <link rel="match" href="box-decoration-break-border-image-ref.html">
+  <meta charset="utf-8">
+  <style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+* { font-family: DejaVuSansMono; }
+
+html,body {
+  color:black; background-color:white; font-size:16px; padding:0; padding-left:10px; margin:0;
+}
+
+.b {
+  border: 5px solid red;
+  border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD%2FgAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAoUlEQVR42u3bwQ0AIAgEwcOmtXttgScmsxWQCTyp3EysJo61IliwYMGCBUuwYMGCBQuWYMGCBQsWLMGCBQsWLFiCBQsWLFiwBAsWLFiwYAkWLFiwYMESLFiwYMGCpXaVka%2BsO8dmOUNYggULFixYsAQLFixYsGAJFixYsGDBEixYsGDBgiVYsGDBggVLsGDBggULlmDBggULFizBggUL1t89N%2FYEtBGStpoAAAAASUVORK5CYII%3D) 10 10 repeat;
+  background: pink;
+  border-image-outset: 7px 3px 5px 9px;
+}
+
+.columns {
+  -moz-columns: 2;
+  width: 200px;
+  height: 50px;
+  background: grey;
+  margin-right: 20px;
+  margin-bottom: 20px;
+  float:left;
+}
+.col3 {
+  -moz-columns: 3;
+}
+.vbreak { height:65px; width:41px; }
+.h { width:30px;height:30px; background:grey; }
+.m { margin-left:15px; }
+.col3 .vbreak { height:115px; }
+.clone { box-decoration-break:clone; }
+.slice { box-decoration-break:slice; }
+x { display:inline-block; width:31px; height:18px; line-height:1; }
+y { display:inline-block; width:47px; height:18px; line-height:1; }
+pos1 { position:absolute; top:50px; width:700px; }
+pos2 { position:absolute; top:150px; width:700px; }
+pos3 { position:absolute; top:380px; width:700px; }
+pos4 { position:absolute; top:510px; width:700px; }
+  </style>
+</head>
+<body>
+<pre>box-decoration-break:slice</pre>
+
+<pos1>
+<div class="columns"><div class="b vbreak slice"></div></div>
+<div class="columns col3"><div class="b vbreak slice"></div></div>
+</pos1>
+
+<pos2>
+<span class="b slice" style="border-style:dashed;"><x></x><div class="h"></div><y></y></span>
+<span class="b slice m" style="border-style:dashed;"><x></x><div class="h"></div><y></y><div class="h"></div><y></y></span>
+
+<pre>box-decoration-break:clone</pre>
+</pos2>
+
+<pos3>
+<div class="columns"><div class="b vbreak clone"></div></div>
+<div class="columns col3"><div class="b vbreak clone"></div></div>
+</pos3>
+
+<pos4>
+<span class="b clone" style="border-style:dashed;"><x></x><div class="h"></div><y></y></span>
+<span class="b clone m" style="border-style:dashed;"><x></x><div class="h"></div><y></y><div class="h"></div><y></y></span>
+</pos4>
+
+</body>
+</html>
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -1,4 +1,5 @@
 pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-1.html box-decoration-break-1-ref.html
 
 fuzzy(1,20) pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
 fuzzy(16,460) pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html
+random-if(!gtk2Widget) pref(layout.css.box-decoration-break.enabled,true) HTTP(..) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html