Bug 1494100 Part 1 - Create ColumnUtils, and extract utility functions in nsColumnSetFrame into it. r=dholbert
authorTing-Yu Lin <tlin@mozilla.com>
Wed, 08 May 2019 22:49:31 +0000
changeset 531989 e77c2a2c5d8238d23de731605789269873ecd97e
parent 531988 6d0c3c2fda714601e6fb61019ed2a9b9db0eeb81
child 531990 93fd1b5a5a025a54f109c8ab76d17ee1e6f860d1
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1494100
milestone68.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 1494100 Part 1 - Create ColumnUtils, and extract utility functions in nsColumnSetFrame into it. r=dholbert The functions move to ColumnUtils will be used by ColumnSetWrapperFrame to implement GetPrefISize() and GetMinISize(). Also, I verify locally that non-unified build is still working by s/UNIFIED_SOURCES/SOURCES/ in layout/generic/moz.build. Differential Revision: https://phabricator.services.mozilla.com/D29614
layout/generic/ColumnUtils.cpp
layout/generic/ColumnUtils.h
layout/generic/moz.build
layout/generic/nsColumnSetFrame.cpp
new file mode 100644
--- /dev/null
+++ b/layout/generic/ColumnUtils.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A namespace class for static muti-column utilities. */
+
+#include "mozilla/ColumnUtils.h"
+
+#include <algorithm>
+
+#include "nsContainerFrame.h"
+#include "nsLayoutUtils.h"
+
+namespace mozilla {
+
+/* static */
+nscoord ColumnUtils::GetColumnGap(const nsContainerFrame* aFrame,
+                                  nscoord aPercentageBasis) {
+  const auto& columnGap = aFrame->StylePosition()->mColumnGap;
+  if (columnGap.IsNormal()) {
+    return aFrame->StyleFont()->mFont.size;
+  }
+  return nsLayoutUtils::ResolveGapToLength(columnGap, aPercentageBasis);
+}
+
+/* static */
+nscoord ColumnUtils::ClampUsedColumnWidth(const Length& aColumnWidth) {
+  // Per spec, used values will be clamped to a minimum of 1px.
+  return std::max(CSSPixel::ToAppUnits(1), aColumnWidth.ToAppUnits());
+}
+
+/* static */
+nscoord ColumnUtils::IntrinsicISize(uint32_t aColCount, nscoord aColGap,
+                                    nscoord aColISize) {
+  MOZ_ASSERT(aColCount > 0, "Cannot compute with zero columns!");
+
+  // Column box's inline-size times number of columns (n), plus n-1 column gaps.
+  nscoord iSize = aColISize * aColCount + aColGap * (aColCount - 1);
+
+  // The multiplication above can make 'iSize' negative (integer overflow),
+  // so use std::max to protect against that.
+  return std::max(iSize, aColISize);
+}
+
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/generic/ColumnUtils.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A namespace class for static muti-column utilities. */
+
+#ifndef mozilla_ColumnUtils_h
+#define mozilla_ColumnUtils_h
+
+#include "nsStyleCoord.h"
+
+class nsContainerFrame;
+
+namespace mozilla {
+
+// ColumnUtils is a namespace class containing utility functions used by
+// multi-column containers like ColumnSetWrapperFrame and nsColumnSetFrame.
+//
+class ColumnUtils final {
+ public:
+  // Compute used value of 'column-gap' for aFrame.
+  static nscoord GetColumnGap(const nsContainerFrame* aFrame,
+                              nscoord aPercentageBasis);
+
+  // Clamp used column width to a minimum of 1px.
+  static nscoord ClampUsedColumnWidth(const Length& aColumnWidth);
+
+  // Compute the intrinsic inline-size of a column container, given a non-zero
+  // column-count, column gap, and column box's inline-size.
+  static nscoord IntrinsicISize(uint32_t aColCount, nscoord aColGap,
+                                nscoord aColISize);
+};
+
+}  // namespace mozilla
+
+#endif  // mozilla_ColumnUtils_h
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -130,16 +130,17 @@ EXPORTS += [
     'ScrollSnap.h',
     'TextDrawTarget.h',
     'Visibility.h',
 ]
 
 EXPORTS.mozilla += [
     'AspectRatio.h',
     'AutoCopyListener.h',
+    'ColumnUtils.h',
     'CSSAlignUtils.h',
     'CSSOrderAwareFrameIterator.h',
     'FrameTypeList.h',
     'ReflowInput.h',
     'ReflowOutput.h',
     'ViewportFrame.h',
     'WritingModes.h',
 ]
@@ -148,16 +149,17 @@ EXPORTS.mozilla.layout += [
     'FrameChildList.h',
     'ScrollAnchorContainer.h',
 ]
 
 UNIFIED_SOURCES += [
     'BlockReflowInput.cpp',
     'BRFrame.cpp',
     'ColumnSetWrapperFrame.cpp',
+    'ColumnUtils.cpp',
     'CSSAlignUtils.cpp',
     'CSSOrderAwareFrameIterator.cpp',
     'DetailsFrame.cpp',
     'FrameChildList.cpp',
     'MathMLTextRunFactory.cpp',
     'nsAbsoluteContainingBlock.cpp',
     'nsBackdropFrame.cpp',
     'nsBlockFrame.cpp',
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for css3 multi-column layout */
 
 #include "nsColumnSetFrame.h"
 
+#include "mozilla/ColumnUtils.h"
 #include "mozilla/Logging.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/ToString.h"
 #include "nsCSSRendering.h"
 
 using namespace mozilla;
 using namespace mozilla::layout;
 
@@ -270,42 +271,28 @@ nscoord nsColumnSetFrame::GetAvailableCo
 
   WritingMode wm = aReflowInput.GetWritingMode();
   LogicalMargin bp = aReflowInput.ComputedLogicalBorderPadding();
   bp.ApplySkipSides(GetLogicalSkipSides(&aReflowInput));
   bp.BEnd(wm) = aReflowInput.ComputedLogicalBorderPadding().BEnd(wm);
   return std::max(0, aReflowInput.AvailableBSize() - bp.BStartEnd(wm));
 }
 
-static nscoord GetColumnGap(const nsColumnSetFrame* aFrame,
-                            nscoord aPercentageBasis) {
-  const auto& columnGap = aFrame->StylePosition()->mColumnGap;
-  if (columnGap.IsNormal()) {
-    return aFrame->StyleFont()->mFont.size;
-  }
-  return nsLayoutUtils::ResolveGapToLength(columnGap, aPercentageBasis);
-}
-
 static uint32_t ColumnBalancingDepth(const ReflowInput& aReflowInput,
                                      uint32_t aMaxDepth) {
   uint32_t depth = 0;
   for (const ReflowInput* ri = aReflowInput.mParentReflowInput;
        ri && depth < aMaxDepth; ri = ri->mParentReflowInput) {
     if (ri->mFlags.mIsColumnBalancing) {
       ++depth;
     }
   }
   return depth;
 }
 
-static nscoord ClampUsedColumnWidth(const Length& aColumnWidth) {
-  // Per spec, used values will be clamped to a minimum of 1px.
-  return std::max(CSSPixel::ToAppUnits(1), aColumnWidth.ToAppUnits());
-}
-
 nsColumnSetFrame::ReflowConfig nsColumnSetFrame::ChooseColumnStrategy(
     const ReflowInput& aReflowInput, bool aForceAuto = false) const {
   WritingMode wm = aReflowInput.GetWritingMode();
 
   const nsStyleColumn* colStyle = StyleColumn();
   nscoord availContentISize = GetAvailableContentISize(aReflowInput);
   if (aReflowInput.ComputedISize() != NS_INTRINSICSIZE) {
     availContentISize = aReflowInput.ComputedISize();
@@ -326,17 +313,18 @@ nsColumnSetFrame::ReflowConfig nsColumnS
     colBSize = std::min(colBSize, aReflowInput.ComputedMaxBSize());
   } else if (StaticPrefs::layout_css_column_span_enabled() &&
              aReflowInput.mCBReflowInput->ComputedMaxBSize() !=
                  NS_INTRINSICSIZE) {
     colBSize =
         std::min(colBSize, aReflowInput.mCBReflowInput->ComputedMaxBSize());
   }
 
-  nscoord colGap = GetColumnGap(this, aReflowInput.ComputedISize());
+  nscoord colGap =
+      ColumnUtils::GetColumnGap(this, aReflowInput.ComputedISize());
   int32_t numColumns = colStyle->mColumnCount;
 
   // If column-fill is set to 'balance', then we want to balance the columns.
   const bool isBalancing =
       colStyle->mColumnFill == StyleColumnFill::Balance && !aForceAuto;
   if (isBalancing) {
     const uint32_t kMaxNestedColumnBalancingDepth = 2;
     const uint32_t balancingDepth =
@@ -345,17 +333,18 @@ nsColumnSetFrame::ReflowConfig nsColumnS
       numColumns = 1;
     }
   }
 
   nscoord colISize;
   // In vertical writing-mode, "column-width" (inline size) will actually be
   // physical height, but its CSS name is still column-width.
   if (colStyle->mColumnWidth.IsLength()) {
-    colISize = ClampUsedColumnWidth(colStyle->mColumnWidth.AsLength());
+    colISize =
+        ColumnUtils::ClampUsedColumnWidth(colStyle->mColumnWidth.AsLength());
     NS_ASSERTION(colISize >= 0, "negative column width");
     // Reduce column count if necessary to make columns fit in the
     // available width. Compute max number of columns that fit in
     // availContentISize, satisfying colGap*(maxColumns - 1) +
     // colISize*maxColumns <= availContentISize
     if (availContentISize != NS_INTRINSICSIZE && colGap + colISize > 0 &&
         numColumns > 0) {
       // This expression uses truncated rounding, which is what we
@@ -492,74 +481,66 @@ nscoord nsColumnSetFrame::GetMinISize(gf
 
   if (mFrames.FirstChild() && !StyleDisplay()->IsContainSize()) {
     // We want to ignore this in the case that we're size contained
     // because our children should not contribute to our
     // intrinsic size.
     iSize = mFrames.FirstChild()->GetMinISize(aRenderingContext);
   }
   const nsStyleColumn* colStyle = StyleColumn();
-  nscoord colISize;
   if (colStyle->mColumnWidth.IsLength()) {
-    colISize = ClampUsedColumnWidth(colStyle->mColumnWidth.AsLength());
+    nscoord colISize =
+        ColumnUtils::ClampUsedColumnWidth(colStyle->mColumnWidth.AsLength());
     // As available width reduces to zero, we reduce our number of columns
     // to one, and don't enforce the column width, so just return the min
     // of the child's min-width with any specified column width.
     iSize = std::min(iSize, colISize);
   } else {
     NS_ASSERTION(colStyle->mColumnCount > 0,
                  "column-count and column-width can't both be auto");
     // As available width reduces to zero, we still have mColumnCount columns,
-    // so multiply the child's min-width by the number of columns (n) and
-    // include n-1 column gaps.
-    colISize = iSize;
-    iSize *= colStyle->mColumnCount;
-    nscoord colGap = GetColumnGap(this, NS_UNCONSTRAINEDSIZE);
-    iSize += colGap * (colStyle->mColumnCount - 1);
-    // The multiplication above can make 'width' negative (integer overflow),
-    // so use std::max to protect against that.
-    iSize = std::max(iSize, colISize);
+    // so compute our minimum size based on the number of columns and their gaps
+    // and minimum per-column size.
+    nscoord colGap = ColumnUtils::GetColumnGap(this, NS_UNCONSTRAINEDSIZE);
+    iSize = ColumnUtils::IntrinsicISize(colStyle->mColumnCount, colGap, iSize);
   }
   // XXX count forced column breaks here? Maybe we should return the child's
   // min-width times the minimum number of columns.
   return iSize;
 }
 
 nscoord nsColumnSetFrame::GetPrefISize(gfxContext* aRenderingContext) {
   // Our preferred width is our desired column width, if specified, otherwise
   // the child's preferred width, times the number of columns, plus the width
   // of any required column gaps
   // XXX what about forced column breaks here?
   nscoord result = 0;
   DISPLAY_PREF_INLINE_SIZE(this, result);
   const nsStyleColumn* colStyle = StyleColumn();
-  nscoord colGap = GetColumnGap(this, NS_UNCONSTRAINEDSIZE);
 
   nscoord colISize;
   if (colStyle->mColumnWidth.IsLength()) {
-    colISize = ClampUsedColumnWidth(colStyle->mColumnWidth.AsLength());
+    colISize =
+        ColumnUtils::ClampUsedColumnWidth(colStyle->mColumnWidth.AsLength());
   } else if (mFrames.FirstChild() && !StyleDisplay()->IsContainSize()) {
     // We want to ignore this in the case that we're size contained
     // because our children should not contribute to our
     // intrinsic size.
     colISize = mFrames.FirstChild()->GetPrefISize(aRenderingContext);
   } else {
     colISize = 0;
   }
 
-  int32_t numColumns = colStyle->mColumnCount;
-  if (numColumns <= 0) {
-    // if column-count is auto, assume one column
-    numColumns = 1;
-  }
-
-  nscoord iSize = colISize * numColumns + colGap * (numColumns - 1);
-  // The multiplication above can make 'iSize' negative (integer overflow),
-  // so use std::max to protect against that.
-  result = std::max(iSize, colISize);
+  // If column-count is auto, assume one column.
+  uint32_t numColumns =
+      colStyle->mColumnCount == nsStyleColumn::kColumnCountAuto
+          ? 1
+          : colStyle->mColumnCount;
+  nscoord colGap = ColumnUtils::GetColumnGap(this, NS_UNCONSTRAINEDSIZE);
+  result = ColumnUtils::IntrinsicISize(numColumns, colGap, colISize);
   return result;
 }
 
 nsColumnSetFrame::ColumnBalanceData nsColumnSetFrame::ReflowChildren(
     ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput,
     nsReflowStatus& aStatus, const ReflowConfig& aConfig,
     bool aUnboundedLastColumn) {
   ColumnBalanceData colData;