mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-26 17:17:31 +09:00
Issue #1230 - Part 1: Fix Back-computing percentages for intrinsic sizing in Layout CSS-Grid
List of relevant patches applied: 1398537 part 2 - [css-multicol] Implement percentages for 'column-gap' (Gecko part). 1434478 part 1 - [css-grid] Stop back-computing percentage grid gaps when the percentage basis is indefinite. Treat them as zero sized instead. 1434478 part 2 - Stop back-computing percentage padding/margin when the percentage basis is indefinite. Treat them as zero sized instead. 1434478 part 3 - Remove IntrinsicISizeOffsetData::hPctPadding/hPctMargin members since they are now unused. 1434478 part 4 - Factor out constants like NS_UNCONSTRAINEDSIZE so they can be used in headers without needing nsIFrame.h (idempotent patch). 1434478 part 5 - Create nsLayoutUtils::ResolveToLength for resolving CSS <length-percentage> (idempotent patch). 1434478 part 6 - Propagate a percentage basis to nsIFrame::IntrinsicISizeOffsets for resolving padding/margin. This is needed only for CSS Grid since in other cases we're only using IntrinsicISizeOffsets in the inline-axis and the percentage basis is always indefinite for *intrinsic sizing*. When calculating the intrinsic size of grid items in the grid container's block axis however, we do have a definite size for the grid area in the inline-axis and it should be used per: https://drafts.csswg.org/css-grid/#algo-overview "2. Next, the track sizing algorithm resolves the sizes of the grid rows, using the grid column sizes calculated in the previous step." (Percentage padding/margin for grid items is always resolved against the grid area's inline-size nowadays.)
This commit is contained in:
parent
1f9d16132b
commit
e4c397f0d9
16 changed files with 240 additions and 319 deletions
31
layout/base/LayoutConstants.h
Normal file
31
layout/base/LayoutConstants.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* constants used throughout the Layout module */
|
||||
|
||||
#ifndef LayoutConstants_h___
|
||||
#define LayoutConstants_h___
|
||||
|
||||
#include "nsSize.h" // for NS_MAXSIZE
|
||||
|
||||
/**
|
||||
* Constant used to indicate an unconstrained size.
|
||||
*/
|
||||
#define NS_UNCONSTRAINEDSIZE NS_MAXSIZE
|
||||
|
||||
// NOTE: There are assumptions all over that these have the same value,
|
||||
// namely NS_UNCONSTRAINEDSIZE.
|
||||
#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE
|
||||
#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE
|
||||
#define NS_AUTOOFFSET NS_UNCONSTRAINEDSIZE
|
||||
|
||||
// +1 is to avoid clamped huge margin values being processed as auto margins
|
||||
#define NS_AUTOMARGIN (NS_UNCONSTRAINEDSIZE + 1)
|
||||
|
||||
#define NS_INTRINSIC_WIDTH_UNKNOWN nscoord_MIN
|
||||
|
||||
|
||||
#endif // LayoutConstants_h___
|
||||
|
|
@ -13,6 +13,9 @@ with Files('Display*'):
|
|||
with Files('FrameLayerBuilder.*'):
|
||||
BUG_COMPONENT = ('Core', 'Layout: View Rendering')
|
||||
|
||||
with Files('LayoutConstants.*'):
|
||||
BUG_COMPONENT = ('Core', 'Layout: View Rendering')
|
||||
|
||||
with Files('LayerState.*'):
|
||||
BUG_COMPONENT = ('Core', 'Layout: View Rendering')
|
||||
|
||||
|
|
@ -63,6 +66,7 @@ EXPORTS += [
|
|||
'FrameLayerBuilder.h',
|
||||
'FrameProperties.h',
|
||||
'LayerState.h',
|
||||
'LayoutConstants.h',
|
||||
'LayoutLogging.h',
|
||||
'nsArenaMemoryStats.h',
|
||||
'nsBidi.h',
|
||||
|
|
|
|||
|
|
@ -4671,8 +4671,6 @@ GetDefiniteSize(const nsStyleCoord& aStyle,
|
|||
nscoord pb = aIsInlineAxis ? aPercentageBasis.value().ISize(wm)
|
||||
: aPercentageBasis.value().BSize(wm);
|
||||
if (pb == NS_UNCONSTRAINEDSIZE) {
|
||||
// XXXmats given that we're calculating an intrinsic size here,
|
||||
// maybe we should back-compute the calc-size using AddPercents?
|
||||
return false;
|
||||
}
|
||||
*aResult = std::max(0, calc->mLength +
|
||||
|
|
@ -4916,12 +4914,9 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext,
|
|||
nscoord result = aContentSize;
|
||||
nscoord min = aContentMinSize;
|
||||
nscoord coordOutsideSize = 0;
|
||||
float pctOutsideSize = 0;
|
||||
float pctTotal = 0.0f;
|
||||
|
||||
if (!(aFlags & nsLayoutUtils::IGNORE_PADDING)) {
|
||||
coordOutsideSize += aOffsets.hPadding;
|
||||
pctOutsideSize += aOffsets.hPctPadding;
|
||||
}
|
||||
|
||||
coordOutsideSize += aOffsets.hBorder;
|
||||
|
|
@ -4929,21 +4924,15 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext,
|
|||
if (aBoxSizing == StyleBoxSizing::Border) {
|
||||
min += coordOutsideSize;
|
||||
result = NSCoordSaturatingAdd(result, coordOutsideSize);
|
||||
pctTotal += pctOutsideSize;
|
||||
|
||||
coordOutsideSize = 0;
|
||||
pctOutsideSize = 0.0f;
|
||||
}
|
||||
|
||||
coordOutsideSize += aOffsets.hMargin;
|
||||
pctOutsideSize += aOffsets.hPctMargin;
|
||||
|
||||
min += coordOutsideSize;
|
||||
result = NSCoordSaturatingAdd(result, coordOutsideSize);
|
||||
pctTotal += pctOutsideSize;
|
||||
|
||||
const bool shouldAddPercent = aType == nsLayoutUtils::PREF_ISIZE ||
|
||||
(aFlags & nsLayoutUtils::ADD_PERCENTS);
|
||||
nscoord size;
|
||||
if (aType == nsLayoutUtils::MIN_ISIZE &&
|
||||
(((aStyleSize.HasPercent() || aStyleMaxSize.HasPercent()) &&
|
||||
|
|
@ -4961,18 +4950,6 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext,
|
|||
GetIntrinsicCoord(aStyleSize, aRenderingContext, aFrame,
|
||||
PROP_WIDTH, size)) {
|
||||
result = size + coordOutsideSize;
|
||||
if (shouldAddPercent) {
|
||||
result = nsLayoutUtils::AddPercents(result, pctOutsideSize);
|
||||
}
|
||||
} else {
|
||||
// NOTE: We could really do a lot better for percents and for some
|
||||
// cases of calc() containing percent (certainly including any where
|
||||
// the coefficient on the percent is positive and there are no max()
|
||||
// expressions). However, doing better for percents wouldn't be
|
||||
// backwards compatible.
|
||||
if (shouldAddPercent) {
|
||||
result = nsLayoutUtils::AddPercents(result, pctTotal);
|
||||
}
|
||||
}
|
||||
|
||||
nscoord maxSize = aFixedMaxSize ? *aFixedMaxSize : 0;
|
||||
|
|
@ -4980,9 +4957,6 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext,
|
|||
GetIntrinsicCoord(aStyleMaxSize, aRenderingContext, aFrame,
|
||||
PROP_MAX_WIDTH, maxSize)) {
|
||||
maxSize += coordOutsideSize;
|
||||
if (shouldAddPercent) {
|
||||
maxSize = nsLayoutUtils::AddPercents(maxSize, pctOutsideSize);
|
||||
}
|
||||
if (result > maxSize) {
|
||||
result = maxSize;
|
||||
}
|
||||
|
|
@ -4993,17 +4967,11 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext,
|
|||
GetIntrinsicCoord(aStyleMinSize, aRenderingContext, aFrame,
|
||||
PROP_MIN_WIDTH, minSize)) {
|
||||
minSize += coordOutsideSize;
|
||||
if (shouldAddPercent) {
|
||||
minSize = nsLayoutUtils::AddPercents(minSize, pctOutsideSize);
|
||||
}
|
||||
if (result < minSize) {
|
||||
result = minSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldAddPercent) {
|
||||
min = nsLayoutUtils::AddPercents(min, pctTotal);
|
||||
}
|
||||
if (result < min) {
|
||||
result = min;
|
||||
}
|
||||
|
|
@ -5020,9 +4988,6 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext,
|
|||
: devSize.width);
|
||||
// GetMinimumWidgetSize() returns a border-box width.
|
||||
themeSize += aOffsets.hMargin;
|
||||
if (shouldAddPercent) {
|
||||
themeSize = nsLayoutUtils::AddPercents(themeSize, aOffsets.hPctMargin);
|
||||
}
|
||||
if (themeSize > result || !canOverride) {
|
||||
result = themeSize;
|
||||
}
|
||||
|
|
@ -5267,9 +5232,19 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
|
|||
min = aFrame->GetMinISize(aRenderingContext);
|
||||
}
|
||||
|
||||
nscoord pmPercentageBasis = NS_UNCONSTRAINEDSIZE;
|
||||
if (aPercentageBasis.isSome()) {
|
||||
// The padding/margin percentage basis is the inline-size in the parent's
|
||||
// writing-mode.
|
||||
auto childWM = aFrame->GetWritingMode();
|
||||
pmPercentageBasis =
|
||||
aFrame->GetParent()->GetWritingMode().IsOrthogonalTo(childWM) ?
|
||||
aPercentageBasis->BSize(childWM) :
|
||||
aPercentageBasis->ISize(childWM);
|
||||
}
|
||||
nsIFrame::IntrinsicISizeOffsetData offsets =
|
||||
MOZ_LIKELY(isInlineAxis) ? aFrame->IntrinsicISizeOffsets()
|
||||
: aFrame->IntrinsicBSizeOffsets();
|
||||
MOZ_LIKELY(isInlineAxis) ? aFrame->IntrinsicISizeOffsets(pmPercentageBasis)
|
||||
: aFrame->IntrinsicBSizeOffsets(pmPercentageBasis);
|
||||
nscoord contentBoxSize = result;
|
||||
result = AddIntrinsicSizeOffset(aRenderingContext, aFrame, offsets, aType,
|
||||
boxSizing, result, min, styleISize,
|
||||
|
|
@ -5310,11 +5285,12 @@ nsLayoutUtils::IntrinsicForContainer(nsRenderingContext* aRenderingContext,
|
|||
}
|
||||
|
||||
/* static */ nscoord
|
||||
nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis,
|
||||
nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis,
|
||||
nsRenderingContext* aRC,
|
||||
nsIFrame* aFrame,
|
||||
IntrinsicISizeType aType,
|
||||
uint32_t aFlags)
|
||||
nsIFrame* aFrame,
|
||||
IntrinsicISizeType aType,
|
||||
const LogicalSize& aPercentageBasis,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
MOZ_ASSERT(aFrame);
|
||||
MOZ_ASSERT(aFrame->IsFlexOrGridItem(),
|
||||
|
|
@ -5328,9 +5304,7 @@ nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis,
|
|||
aWM.IsVertical() ? "vertical" : "horizontal");
|
||||
#endif
|
||||
|
||||
// Note: this method is only meant for grid/flex items which always
|
||||
// include percentages in their intrinsic size.
|
||||
aFlags |= nsLayoutUtils::ADD_PERCENTS;
|
||||
// Note: this method is only meant for grid/flex items.
|
||||
const nsStylePosition* const stylePos = aFrame->StylePosition();
|
||||
const nsStyleCoord* style = aAxis == eAxisHorizontal ? &stylePos->mMinWidth
|
||||
: &stylePos->mMinHeight;
|
||||
|
|
@ -5375,11 +5349,17 @@ nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis,
|
|||
// wrapping inside of it should not apply font size inflation.
|
||||
AutoMaybeDisableFontInflation an(aFrame);
|
||||
|
||||
PhysicalAxis ourInlineAxis =
|
||||
aFrame->GetWritingMode().PhysicalAxis(eLogicalAxisInline);
|
||||
// The padding/margin percentage basis is the inline-size in the parent's
|
||||
// writing-mode.
|
||||
auto childWM = aFrame->GetWritingMode();
|
||||
nscoord pmPercentageBasis =
|
||||
aFrame->GetParent()->GetWritingMode().IsOrthogonalTo(childWM) ?
|
||||
aPercentageBasis.BSize(childWM) :
|
||||
aPercentageBasis.ISize(childWM);
|
||||
PhysicalAxis ourInlineAxis = childWM.PhysicalAxis(eLogicalAxisInline);
|
||||
nsIFrame::IntrinsicISizeOffsetData offsets =
|
||||
ourInlineAxis == aAxis ? aFrame->IntrinsicISizeOffsets()
|
||||
: aFrame->IntrinsicBSizeOffsets();
|
||||
ourInlineAxis == aAxis ? aFrame->IntrinsicISizeOffsets(pmPercentageBasis)
|
||||
: aFrame->IntrinsicBSizeOffsets(pmPercentageBasis);
|
||||
nscoord result = 0;
|
||||
nscoord min = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef nsLayoutUtils_h__
|
||||
#define nsLayoutUtils_h__
|
||||
|
||||
#include "LayoutConstants.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
|
@ -154,6 +155,7 @@ public:
|
|||
typedef mozilla::ScreenMargin ScreenMargin;
|
||||
typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
|
||||
typedef mozilla::StyleGeometryBox StyleGeometryBox;
|
||||
typedef mozilla::LogicalSize LogicalSize;
|
||||
|
||||
/**
|
||||
* Finds previously assigned ViewID for the given content element, if any.
|
||||
|
|
@ -1381,7 +1383,8 @@ public:
|
|||
* variations if that's what matches aAxis) and its padding, border and margin
|
||||
* in the corresponding dimension.
|
||||
* @param aPercentageBasis an optional percentage basis (in aFrame's WM).
|
||||
* Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes.
|
||||
* If the basis is indefinite in a given axis, pass a size with
|
||||
* NS_UNCONSTRAINEDSIZE in that component.
|
||||
* If you pass Nothing() a percentage basis will be calculated from aFrame's
|
||||
* ancestors' computed size in the relevant axis, if needed.
|
||||
* @param aMarginBoxMinSizeClamp make the result fit within this margin-box
|
||||
|
|
@ -1395,14 +1398,13 @@ public:
|
|||
IGNORE_PADDING = 0x01,
|
||||
BAIL_IF_REFLOW_NEEDED = 0x02, // returns NS_INTRINSIC_WIDTH_UNKNOWN if so
|
||||
MIN_INTRINSIC_ISIZE = 0x04, // use min-width/height instead of width/height
|
||||
ADD_PERCENTS = 0x08, // apply AddPercents also for MIN_ISIZE
|
||||
};
|
||||
static nscoord
|
||||
IntrinsicForAxis(mozilla::PhysicalAxis aAxis,
|
||||
nsRenderingContext* aRenderingContext,
|
||||
nsIFrame* aFrame,
|
||||
IntrinsicISizeType aType,
|
||||
const mozilla::Maybe<mozilla::LogicalSize>& aPercentageBasis = mozilla::Nothing(),
|
||||
const mozilla::Maybe<LogicalSize>& aPercentageBasis = mozilla::Nothing(),
|
||||
uint32_t aFlags = 0,
|
||||
nscoord aMarginBoxMinSizeClamp = NS_MAXSIZE);
|
||||
/**
|
||||
|
|
@ -1427,31 +1429,18 @@ public:
|
|||
* calculates the result as if the 'min-' computed value is zero.
|
||||
* Otherwise, return NS_UNCONSTRAINEDSIZE.
|
||||
*
|
||||
* @param aPercentageBasis the percentage basis (in aFrame's WM).
|
||||
* Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes.
|
||||
* @note this behavior is specific to Grid/Flexbox (currently) so aFrame
|
||||
* should be a grid/flex item.
|
||||
*/
|
||||
static nscoord MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis,
|
||||
nsRenderingContext* aRC,
|
||||
nsIFrame* aFrame,
|
||||
IntrinsicISizeType aType,
|
||||
uint32_t aFlags = 0);
|
||||
|
||||
/**
|
||||
* This function increases an initial intrinsic size, 'aCurrent', according
|
||||
* to the given 'aPercent', such that the size-increase makes up exactly
|
||||
* 'aPercent' percent of the returned value. If 'aPercent' or 'aCurrent' are
|
||||
* less than or equal to zero the original 'aCurrent' value is returned.
|
||||
* If 'aPercent' is greater than or equal to 1.0 the value nscoord_MAX is
|
||||
* returned.
|
||||
*/
|
||||
static nscoord AddPercents(nscoord aCurrent, float aPercent)
|
||||
{
|
||||
if (aPercent > 0.0f && aCurrent > 0) {
|
||||
return MOZ_UNLIKELY(aPercent >= 1.0f) ? nscoord_MAX
|
||||
: NSToCoordRound(float(aCurrent) / (1.0f - aPercent));
|
||||
}
|
||||
return aCurrent;
|
||||
}
|
||||
static nscoord
|
||||
MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis,
|
||||
nsRenderingContext* aRC,
|
||||
nsIFrame* aFrame,
|
||||
IntrinsicISizeType aType,
|
||||
const LogicalSize& aPercentageBasis,
|
||||
uint32_t aFlags = 0);
|
||||
|
||||
/*
|
||||
* Convert nsStyleCoord to nscoord when percentages depend on the
|
||||
|
|
@ -2876,6 +2865,62 @@ public:
|
|||
static nsRect ComputeGeometryBox(nsIFrame* aFrame,
|
||||
StyleGeometryBox aGeometryBox);
|
||||
|
||||
/**
|
||||
* Resolve a CSS <length-percentage> value to a definite size.
|
||||
*/
|
||||
template<bool clampNegativeResultToZero>
|
||||
static nscoord ResolveToLength(const nsStyleCoord& aCoord,
|
||||
nscoord aPercentageBasis)
|
||||
{
|
||||
NS_WARNING_ASSERTION(aPercentageBasis >= nscoord(0), "nscoord overflow?");
|
||||
|
||||
switch (aCoord.GetUnit()) {
|
||||
case eStyleUnit_Coord:
|
||||
MOZ_ASSERT(!clampNegativeResultToZero || aCoord.GetCoordValue() >= 0,
|
||||
"This value should have been rejected by the style system");
|
||||
return aCoord.GetCoordValue();
|
||||
case eStyleUnit_Percent:
|
||||
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
|
||||
return nscoord(0);
|
||||
}
|
||||
MOZ_ASSERT(!clampNegativeResultToZero || aCoord.GetPercentValue() >= 0,
|
||||
"This value should have been rejected by the style system");
|
||||
return NSToCoordFloorClamped(aPercentageBasis *
|
||||
aCoord.GetPercentValue());
|
||||
case eStyleUnit_Calc: {
|
||||
nsStyleCoord::Calc* calc = aCoord.GetCalcValue();
|
||||
nscoord result;
|
||||
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
|
||||
result = calc->mLength;
|
||||
} else {
|
||||
result = calc->mLength +
|
||||
NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
|
||||
}
|
||||
if (clampNegativeResultToZero && result < 0) {
|
||||
return nscoord(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected unit!");
|
||||
return nscoord(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a column-gap/row-gap to a definite size.
|
||||
* @note This method resolves 'normal' to zero.
|
||||
* Callers who want different behavior should handle 'normal' on their own.
|
||||
*/
|
||||
static nscoord ResolveGapToLength(const nsStyleCoord& aGap,
|
||||
nscoord aPercentageBasis)
|
||||
{
|
||||
if (aGap.GetUnit() == eStyleUnit_Normal) {
|
||||
return nscoord(0);
|
||||
}
|
||||
return ResolveToLength<true>(aGap, aPercentageBasis);
|
||||
}
|
||||
|
||||
private:
|
||||
static uint32_t sFontSizeInflationEmPerLine;
|
||||
static uint32_t sFontSizeInflationMinTwips;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue