Bug 1490747 part 1 - Center the <legend> border-box (not its margin-box) within the <fieldset> border area. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Fri, 12 Oct 2018 21:36:03 +0200
changeset 499534 8f7a45eb3e5116e2ff06d867a14a2464f0bab306
parent 499533 de1a5f51757856ff727f2e08aad9563593f0a1e0
child 499535 83fca840ea7f02901d0ad92a09a28120b1bc82a6
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1490747
milestone64.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 1490747 part 1 - Center the <legend> border-box (not its margin-box) within the <fieldset> border area. r=dholbert
layout/forms/nsFieldSetFrame.cpp
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -38,24 +38,41 @@ nsFieldSetFrame::nsFieldSetFrame(Compute
 {
   mLegendSpace  = 0;
 }
 
 nsRect
 nsFieldSetFrame::VisualBorderRectRelativeToSelf() const
 {
   WritingMode wm = GetWritingMode();
-  Side legendSide = wm.PhysicalSide(eLogicalSideBStart);
-  nscoord legendBorder = StyleBorder()->GetComputedBorderWidth(legendSide);
   LogicalRect r(wm, LogicalPoint(wm, 0, 0), GetLogicalSize(wm));
   nsSize containerSize = r.Size(wm).GetPhysicalSize(wm);
-  if (legendBorder < mLegendRect.BSize(wm)) {
-    nscoord off = (mLegendRect.BSize(wm) - legendBorder) / 2;
-    r.BStart(wm) += off;
-    r.BSize(wm) -= off;
+  if (nsIFrame* legend = GetLegend()) {
+    nscoord legendSize = legend->GetLogicalSize(wm).BSize(wm);
+    auto legendMargin = legend->GetLogicalUsedMargin(wm);
+    nscoord legendStartMargin = legendMargin.BStart(wm);
+    nscoord legendEndMargin = legendMargin.BEnd(wm);
+    nscoord border = GetUsedBorder().Side(wm.PhysicalSide(eLogicalSideBStart));
+    // Calculate the offset from the border area block-axis start edge needed to
+    // center-align our border with the legend's border-box (in the block-axis).
+    nscoord off = (legendStartMargin + legendSize / 2) - border / 2;
+    // We don't want to display our border above our border area.
+    if (off > nscoord(0)) {
+      nscoord marginBoxSize = legendStartMargin + legendSize + legendEndMargin;
+      if (marginBoxSize > border) {
+        // We don't want to display our border below the legend's margin-box,
+        // so we align it to the block-axis end if that happens.
+        nscoord overflow = off + border - marginBoxSize;
+        if (overflow > nscoord(0)) {
+          off -= overflow;
+        }
+        r.BStart(wm) += off;
+        r.BSize(wm) -= off;
+      }
+    }
   }
   return r.GetPhysicalRect(wm, containerSize);
 }
 
 nsIFrame*
 nsFieldSetFrame::GetInner() const
 {
   nsIFrame* last = mFrames.LastChild();
@@ -440,30 +457,41 @@ nsFieldSetFrame::Reflow(nsPresContext*  
     const nsSize dummyContainerSize;
     ReflowChild(legend, aPresContext, legendDesiredSize, *legendReflowInput,
                 wm, LogicalPoint(wm), dummyContainerSize,
                 NS_FRAME_NO_MOVE_FRAME, aStatus);
 #ifdef NOISY_REFLOW
     printf("  returned (%d, %d)\n",
            legendDesiredSize.Width(), legendDesiredSize.Height());
 #endif
-    // figure out the legend's rectangle
+    // Calculate the legend's margin-box rectangle.
     legendMargin = legend->GetLogicalUsedMargin(wm);
     mLegendRect =
       LogicalRect(wm, 0, 0,
                   legendDesiredSize.ISize(wm) + legendMargin.IStartEnd(wm),
                   legendDesiredSize.BSize(wm) + legendMargin.BStartEnd(wm));
     nscoord oldSpace = mLegendSpace;
     mLegendSpace = 0;
-    if (mLegendRect.BSize(wm) > border.BStart(wm)) {
-      // center the border on the legend
-      mLegendSpace = mLegendRect.BSize(wm) - border.BStart(wm);
+    nscoord borderBStart = border.BStart(wm);
+    if (mLegendRect.BSize(wm) > borderBStart) {
+      // mLegendSpace is the space to subtract from our content-box size below.
+      mLegendSpace = mLegendRect.BSize(wm) - borderBStart;
     } else {
-      mLegendRect.BStart(wm) =
-        (border.BStart(wm) - mLegendRect.BSize(wm)) / 2;
+      // Calculate the border-box position that would center the legend's
+      // border-box within the fieldset border:
+      nscoord off = (borderBStart - legendDesiredSize.BSize(wm)) / 2;
+      off -= legendMargin.BStart(wm); // convert to a margin-box position
+      if (off > nscoord(0)) {
+        // Align the legend to the end if center-aligning it would overflow.
+        nscoord overflow = off + mLegendRect.BSize(wm) - borderBStart;
+        if (overflow > nscoord(0)) {
+          off -= overflow;
+        }
+        mLegendRect.BStart(wm) += off;
+      }
     }
 
     // if the legend space changes then we need to reflow the
     // content area as well.
     if (mLegendSpace != oldSpace && inner) {
       reflowInner = true;
     }