Bug 1067088 - Use aBorderArea when not skipping any sides (e.g. ::first-letter), not the joined border area. r=roc a=sledru
authorMats Palmgren <mats@mozilla.com>
Thu, 18 Sep 2014 16:12:39 +0000
changeset 216792 9f2dc7a2df34
parent 216791 2dce6525ddfe
child 216793 7cd3ae0255ec
push id3913
push usermpalmgren@mozilla.com
push date2014-09-18 16:12 +0000
treeherdermozilla-beta@9f2dc7a2df34 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, sledru
bugs1067088
milestone33.0
Bug 1067088 - Use aBorderArea when not skipping any sides (e.g. ::first-letter), not the joined border area. r=roc a=sledru
layout/base/nsCSSRendering.cpp
layout/reftests/css-break/box-decoration-break-first-letter-ref.html
layout/reftests/css-break/box-decoration-break-first-letter.html
layout/reftests/css-break/reftest.list
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -501,34 +501,40 @@ static bool
 IsBoxDecorationSlice(const nsStyleBorder& aStyleBorder)
 {
   return aStyleBorder.mBoxDecorationBreak ==
            NS_STYLE_BOX_DECORATION_BREAK_SLICE;
 }
 
 static nsRect
 BoxDecorationRectForBorder(nsIFrame* aFrame, const nsRect& aBorderArea,
+                           Sides aSkipSides,
                            const nsStyleBorder* aStyleBorder = nullptr)
 {
   if (!aStyleBorder) {
     aStyleBorder = aFrame->StyleBorder();
   }
-  return ::IsBoxDecorationSlice(*aStyleBorder)
+  // If aSkipSides.IsEmpty() then there are no continuations, or it's
+  // a ::first-letter that wants all border sides on the first continuation.
+  return ::IsBoxDecorationSlice(*aStyleBorder) && !aSkipSides.IsEmpty()
            ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBorder)
            : aBorderArea;
 }
 
 static nsRect
 BoxDecorationRectForBackground(nsIFrame* aFrame, const nsRect& aBorderArea,
+                               Sides aSkipSides,
                                const nsStyleBorder* aStyleBorder = nullptr)
 {
   if (!aStyleBorder) {
     aStyleBorder = aFrame->StyleBorder();
   }
-  return ::IsBoxDecorationSlice(*aStyleBorder)
+  // If aSkipSides.IsEmpty() then there are no continuations, or it's
+  // a ::first-letter that wants all border sides on the first continuation.
+  return ::IsBoxDecorationSlice(*aStyleBorder) && !aSkipSides.IsEmpty()
            ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBackground)
            : aBorderArea;
 }
 
 //----------------------------------------------------------------------
 // Thebes Border Rendering Code Start
 
 /*
@@ -642,34 +648,29 @@ nsCSSRendering::PaintBorderWithStyleBord
       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);
+    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, aSkipSides, &aStyleBorder);
   gfxCornerSizes bgRadii;
   ::GetRadii(aForFrame, aStyleBorder, aBorderArea, joinedBorderArea, &bgRadii);
 
-
   SF(" joinedBorderArea: %d %d %d %d\n", joinedBorderArea.x, joinedBorderArea.y,
      joinedBorderArea.width, joinedBorderArea.height);
 
   // start drawing
   gfxContext* ctx = aRenderingContext.ThebesContext();
   ctx->Save();
 
   if (::IsBoxDecorationSlice(aStyleBorder)) {
-    if (aSkipSides.IsEmpty()) {
-      // No continuations most likely, or ::first-letter that wants all border-
-      // sides on the first continuation.
-      joinedBorderArea = aBorderArea;
-    } else if (joinedBorderArea.IsEqualEdges(aBorderArea)) {
+    if (joinedBorderArea.IsEqualEdges(aBorderArea)) {
       // No need for a clip, just skip the sides we don't want.
       border.ApplySkipSides(aSkipSides);
     } 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.
       aRenderingContext.IntersectClip(aBorderArea);
     }
   } else {
@@ -1185,17 +1186,18 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
   } else {
     nativeTheme = false;
     hasBorderRadius = true; // we'll update this below
   }
 
   nsRect frameRect = nativeTheme ?
     aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
     aFrameArea;
-  frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect);
+  Sides skipSides = aForFrame->GetSkipSides();
+  frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect, skipSides);
 
   // Get any border radius, since box-shadow must also have rounded corners if
   // the frame does.
   gfxCornerSizes borderRadii;
   const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
   if (hasBorderRadius) {
     nscoord twipsRadii[8];
     NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(),
@@ -1225,17 +1227,16 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
       aForFrame->GetPaddingRect() - aForFrame->GetPosition() + aFrameArea.TopLeft();
     skipGfxRect = nsLayoutUtils::RectToGfxRect(paddingRect, twipsPerPixel);
   } else if (hasBorderRadius) {
     skipGfxRect.Deflate(gfxMargin(
         std::max(borderRadii[C_TL].height, borderRadii[C_TR].height), 0,
         std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0));
   }
 
-  Sides skipSides = aForFrame->GetSkipSides();
   for (uint32_t i = shadows->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
     if (shadowItem->mInset)
       continue;
 
     nsRect shadowRect = frameRect;
     shadowRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
     if (!nativeTheme) {
@@ -1400,17 +1401,19 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
     // inner box-shadows for them. But we allow chrome to paint inner
     // box shadows since chrome can be aware of the platform theme.
     return;
   }
 
   NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame ||
                aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
 
-  nsRect frameRect = ::BoxDecorationRectForBorder(aForFrame, aFrameArea);
+  Sides skipSides = aForFrame->GetSkipSides();
+  nsRect frameRect =
+    ::BoxDecorationRectForBorder(aForFrame, aFrameArea, skipSides);
   nsRect paddingRect = frameRect;
   nsMargin border = aForFrame->GetUsedBorder();
   paddingRect.Deflate(border);
 
   // Get any border radius, since box-shadow must also have rounded corners
   // if the frame does.
   nscoord twipsRadii[8];
   nsSize sz = frameRect.Size();
@@ -2688,20 +2691,21 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   // At this point, drawBackgroundImage and drawBackgroundColor are
   // true if and only if we are actually supposed to paint an image or
   // color into aDirtyRect, respectively.
   if (!drawBackgroundImage && !drawBackgroundColor)
     return;
 
   // Compute the outermost boundary of the area that might be painted.
   // Same coordinate space as aBorderArea & aBGClipRect.
+  Sides skipSides = aForFrame->GetSkipSides();
   nsRect paintBorderArea =
-    ::BoxDecorationRectForBackground(aForFrame, aBorderArea, &aBorder);
+    ::BoxDecorationRectForBackground(aForFrame, aBorderArea, skipSides, &aBorder);
   nsRect clipBorderArea =
-    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aBorder);
+    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, skipSides, &aBorder);
   gfxCornerSizes bgRadii;
   bool haveRoundedCorners =
     ::GetRadii(aForFrame, aBorder, aBorderArea, clipBorderArea, &bgRadii);
 
   // The 'bgClipArea' (used only by the image tiling logic, far below)
   // is the caller-provided aBGClipRect if any, or else the area
   // determined by the value of 'background-clip' in
   // SetupCurrentBackgroundClip.  (Arguably it should be the
@@ -2892,18 +2896,19 @@ nsCSSRendering::PaintBackgroundColorWith
   NS_ASSERTION(drawBackgroundImage || drawBackgroundColor,
                "Should not be trying to paint a background if we don't have one");
   if (!drawBackgroundColor) {
     return;
   }
 
   // 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, &aBorder);
+    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, skipSides, &aBorder);
   gfxCornerSizes bgRadii;
   bool haveRoundedCorners =
     ::GetRadii(aForFrame, aBorder, aBorderArea, clipBorderArea, &bgRadii);
 
   // The background is rendered over the 'background-clip' area,
   // which is normally equal to the border area but may be reduced
   // to the padding area by CSS.  Also, if the border is solid, we
   // don't need to draw outside the padding area.  In either case,
@@ -3238,17 +3243,19 @@ nsCSSRendering::PrepareBackgroundLayer(n
 nsRect
 nsCSSRendering::GetBackgroundLayerRect(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        const nsRect& aBorderArea,
                                        const nsRect& aClipRect,
                                        const nsStyleBackground::Layer& aLayer,
                                        uint32_t aFlags)
 {
-  nsRect borderArea = ::BoxDecorationRectForBackground(aForFrame, aBorderArea);
+  Sides skipSides = aForFrame->GetSkipSides();
+  nsRect borderArea =
+    ::BoxDecorationRectForBackground(aForFrame, aBorderArea, skipSides);
   nsBackgroundLayerState state =
       PrepareBackgroundLayer(aPresContext, aForFrame, aFlags, borderArea,
                              aClipRect, aLayer);
   return state.mFillArea;
 }
 
 /* static */ bool
 nsCSSRendering::IsBackgroundImageDecodedForStyleContextAndLayer(
@@ -3314,18 +3321,18 @@ DrawBorderImage(nsPresContext*       aPr
   // Determine the border image area, which by default corresponds to the
   // border box but can be modified by 'border-image-outset'.
   // 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.IsEmpty()) {
-    borderImgArea =
-      ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aStyleBorder);
+    borderImgArea = ::BoxDecorationRectForBorder(aForFrame, aBorderArea,
+                                                 aSkipSides, &aStyleBorder);
     if (borderImgArea.IsEqualEdges(aBorderArea)) {
       // No need for a clip, just skip the sides we don't want.
       borderWidths.ApplySkipSides(aSkipSides);
       imageOutset.ApplySkipSides(aSkipSides);
       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.
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-first-letter-ref.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>::first-letter with border-radius</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1067088">
+<style>
+html,body { color:black; background-color:white; font-size:24px; }
+div { line-height:36px; }
+.b { background: blue; }
+.r100p { border-radius: 100%; }
+.r10p { border-radius: 10%; }
+.s1 { border:1px solid black; }
+.i { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR%2FmAAAAAXNSR0IArs4c6QAAADpJREFUWMPtzgENAAAIA6Br%2F85aQzdIQGVyUCdaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpan1oLQKsBY3S7VU8AAAAASUVORK5CYII%3D); }
+.shadowi { box-shadow: inset 15px 9px 7px 0px #00F; }
+.shadowo { box-shadow: 0px 0px 7px 0px #00F;}
+.shadowio { box-shadow: inset 15px 9px 7px 0px #00F, 0px 0px 7px 0px #00F;}
+.bi {
+  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;
+}
+</style>
+</head>
+<body>
+<table cellpadding="10"><tr><td>
+  <div><span class="b r100p">F</span>irst-letter</div>
+  <div><span class="b r10p">F</span>irst-letter</div>
+  <div><span class="b s1 r100p">F</span>irst-letter</div>
+  <div><span class="b s1 r10p">F</span>irst-letter</div>
+  <div><span class="shadowo r100p">F</span>irst-letter</div>
+  <div><span class="shadowo s1 r10p">F</span>irst-letter</div>
+  <div><span class="shadowi s1 r100p">F</span>irst-letter</div>
+  <div><span class="shadowi r10p">F</span>irst-letter</div>
+  <div><span class="shadowio r100p">F</span>irst-letter</div>
+  <div><span class="shadowio s1 r10p">F</span>irst-letter</div>
+  <div><span class="s1 r100p">F</span>irst-letter</div>
+  <div><span class="s1 r10p">F</span>irst-letter</div>
+  <div><span class="i r100p">F</span>irst-letter</div>
+  <div><span class="i r10p">F</span>irst-letter</div>
+  <div><span class="i s1 r100p">F</span>irst-letter</div>
+  <div><span class="i s1 r10p">F</span>irst-letter</div>
+  <div><span class="bi">F</span>irst-letter</div>
+</td>
+<td>
+  <div><span class="b r100p">F</span>irst-letter</div>
+  <div><span class="b r10p">F</span>irst-letter</div>
+  <div><span class="b s1 r100p">F</span>irst-letter</div>
+  <div><span class="b s1 r10p">F</span>irst-letter</div>
+  <div><span class="shadowo r100p">F</span>irst-letter</div>
+  <div><span class="shadowo s1 r10p">F</span>irst-letter</div>
+  <div><span class="shadowi s1 r100p">F</span>irst-letter</div>
+  <div><span class="shadowi r10p">F</span>irst-letter</div>
+  <div><span class="shadowio r100p">F</span>irst-letter</div>
+  <div><span class="shadowio s1 r10p">F</span>irst-letter</div>
+  <div><span class="s1 r100p">F</span>irst-letter</div>
+  <div><span class="s1 r10p">F</span>irst-letter</div>
+  <div><span class="i r100p">F</span>irst-letter</div>
+  <div><span class="i r10p">F</span>irst-letter</div>
+  <div><span class="i s1 r100p">F</span>irst-letter</div>
+  <div><span class="i s1 r10p">F</span>irst-letter</div>
+  <div><span class="bi">F</span>irst-letter</div>
+</td>
+</tr></table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-first-letter.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>::first-letter with border-radius</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1067088">
+<style>
+html,body { color:black; background-color:white; font-size:24px; }
+div { line-height:36px; }
+.b::first-letter { background: blue; }
+.c::first-letter { box-decoration-break:clone; }
+.r100p::first-letter { border-radius: 100%; }
+.r10p::first-letter { border-radius: 10%; }
+.s1::first-letter { border:1px solid black; }
+.i::first-letter { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR%2FmAAAAAXNSR0IArs4c6QAAADpJREFUWMPtzgENAAAIA6Br%2F85aQzdIQGVyUCdaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpan1oLQKsBY3S7VU8AAAAASUVORK5CYII%3D); }
+.shadowi::first-letter { box-shadow: inset 15px 9px 7px 0px #00F; }
+.shadowo::first-letter { box-shadow: 0px 0px 7px 0px #00F;}
+.shadowio::first-letter { box-shadow: inset 15px 9px 7px 0px #00F, 0px 0px 7px 0px #00F;}
+.bi::first-letter {
+  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;
+}
+</style>
+</head>
+<body>
+<table cellpadding="10"><tr><td>
+  <div class="b r100p">First-letter</div>
+  <div class="b r10p">First-letter</div>
+  <div class="b s1 r100p">First-letter</div>
+  <div class="b s1 r10p">First-letter</div>
+  <div class="shadowo r100p">First-letter</div>
+  <div class="shadowo s1 r10p">First-letter</div>
+  <div class="shadowi s1 r100p">First-letter</div>
+  <div class="shadowi r10p">First-letter</div>
+  <div class="shadowio r100p">First-letter</div>
+  <div class="shadowio s1 r10p">First-letter</div>
+  <div class="s1 r100p">First-letter</div>
+  <div class="s1 r10p">First-letter</div>
+  <div class="i r100p">First-letter</div>
+  <div class="i r10p">First-letter</div>
+  <div class="i s1 r100p">First-letter</div>
+  <div class="i s1 r10p">First-letter</div>
+  <div class="bi">First-letter</div>
+</td>
+<td>
+  <!-- box-decoration-break:clone should render the same for ::first-letter -->
+  <div class="c b r100p">First-letter</div>
+  <div class="c b r10p">First-letter</div>
+  <div class="c b s1 r100p">First-letter</div>
+  <div class="c b s1 r10p">First-letter</div>
+  <div class="c shadowo r100p">First-letter</div>
+  <div class="c shadowo s1 r10p">First-letter</div>
+  <div class="c shadowi s1 r100p">First-letter</div>
+  <div class="c shadowi r10p">First-letter</div>
+  <div class="c shadowio r100p">First-letter</div>
+  <div class="c shadowio s1 r10p">First-letter</div>
+  <div class="c s1 r100p">First-letter</div>
+  <div class="c s1 r10p">First-letter</div>
+  <div class="c i r100p">First-letter</div>
+  <div class="c i r10p">First-letter</div>
+  <div class="c i s1 r100p">First-letter</div>
+  <div class="c i s1 r10p">First-letter</div>
+  <div class="c bi">First-letter</div>
+</td>
+</tr></table>
+</body>
+</html>
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -1,8 +1,9 @@
 default-preferences pref(layout.css.box-decoration-break.enabled,true)
 
 == box-decoration-break-1.html box-decoration-break-1-ref.html
 fuzzy(1,20) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
 fuzzy(16,460) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html
 random-if(!gtk2Widget) HTTP(..) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
 == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
 == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
+== box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html