diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h b/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h index 8cf0ce717642..99aae3e74c0c 100644 --- a/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h +++ b/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h @@ -47,17 +47,20 @@ class InlineLevelBox { static InlineLevelBox createLineBreakBox(const Box&, const RenderStyle&, InlineLayoutUnit logicalLeft); static InlineLevelBox createGenericInlineLevelBox(const Box&, const RenderStyle&, InlineLayoutUnit logicalLeft); - InlineLayoutUnit ascent() const { return m_ascent; } - std::optional descent() const { return m_descent; } - // See https://www.w3.org/TR/css-inline-3/#layout-bounds - struct LayoutBounds { - InlineLayoutUnit height() const { return ascent + descent; } - bool operator==(const LayoutBounds& other) const { return ascent == other.ascent && descent == other.descent; } - + struct AscentAndDescent { InlineLayoutUnit ascent { 0 }; InlineLayoutUnit descent { 0 }; + + InlineLayoutUnit height() const { return ascent + descent; } + bool operator==(const AscentAndDescent& other) const { return ascent == other.ascent && descent == other.descent; } + // FIXME: Remove this. + // We need floor/ceil to match legacy layout integral positioning. + void round(); }; - LayoutBounds layoutBounds() const { return m_layoutBounds; } + InlineLayoutUnit ascent() const { return m_ascentAndDescent.ascent; } + InlineLayoutUnit descent() const { return m_ascentAndDescent.descent; } + // See https://www.w3.org/TR/css-inline-3/#layout-bounds + AscentAndDescent layoutBounds() const { return m_layoutBounds; } bool hasContent() const { return m_hasContent; } void setHasContent(); @@ -135,9 +138,8 @@ class InlineLevelBox { void setLogicalHeight(InlineLayoutUnit logicalHeight) { m_logicalRect.setHeight(roundToInt(logicalHeight)); } void setLogicalTop(InlineLayoutUnit logicalTop) { m_logicalRect.setTop(logicalTop >= 0 ? roundToInt(logicalTop) : -roundToInt(-logicalTop)); } void setLogicalLeft(InlineLayoutUnit logicalLeft) { m_logicalRect.setLeft(logicalLeft); } - void setAscent(InlineLayoutUnit ascent) { m_ascent = roundToInt(ascent); } - void setDescent(InlineLayoutUnit descent) { m_descent = roundToInt(descent); } - void setLayoutBounds(const LayoutBounds& layoutBounds) { m_layoutBounds = { InlineLayoutUnit(roundToInt(layoutBounds.ascent)), InlineLayoutUnit(roundToInt(layoutBounds.descent)) }; } + void setAscentAndDescent(AscentAndDescent ascentAndDescent) { m_ascentAndDescent = { InlineLayoutUnit(roundToInt(ascentAndDescent.ascent)), InlineLayoutUnit(roundToInt(ascentAndDescent.descent)) }; } + void setLayoutBounds(const AscentAndDescent& layoutBounds) { m_layoutBounds = { InlineLayoutUnit(roundToInt(layoutBounds.ascent)), InlineLayoutUnit(roundToInt(layoutBounds.descent)) }; } void setInlineBoxContentOffsetForLeadingTrim(InlineLayoutUnit offset) { m_inlineBoxContentOffsetForLeadingTrim = offset; } void setIsFirstBox() { m_isFirstWithinLayoutBox = true; } @@ -147,10 +149,9 @@ class InlineLevelBox { CheckedRef m_layoutBox; // This is the combination of margin and border boxes. Inline level boxes are vertically aligned using their margin boxes. InlineRect m_logicalRect; - LayoutBounds m_layoutBounds; + AscentAndDescent m_layoutBounds; + AscentAndDescent m_ascentAndDescent; InlineLayoutUnit m_inlineBoxContentOffsetForLeadingTrim { 0.f }; - InlineLayoutUnit m_ascent { 0 }; - std::optional m_descent; bool m_hasContent { false }; // These bits are about whether this inline level box is the first/last generated box of the associated Layout::Box // (e.g. always true for atomic inline level boxes, but inline boxes spanning over multiple lines can produce separate first/last boxes). @@ -287,6 +288,12 @@ inline bool InlineLevelBox::lineBoxContain() const return true; } +inline void InlineLevelBox::AscentAndDescent::round() +{ + ascent = floorf(ascent); + descent = ceilf(descent); +} + } } diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp index 769ff4f52a61..5602940f17ed 100644 --- a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp +++ b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp @@ -90,16 +90,7 @@ TextUtil::FallbackFontList LineBoxBuilder::collectFallbackFonts(const InlineLeve return fallbackFonts; } -struct AscentAndDescent { - InlineLayoutUnit ascent { 0 }; - InlineLayoutUnit descent { 0 }; - - InlineLayoutUnit height() const { return ascent + descent; } - // FIXME: Remove this. - // We need floor/ceil to match legacy layout integral positioning. - AscentAndDescent round() const { return { floorf(ascent), ceilf(descent) }; } -}; -static AscentAndDescent primaryFontMetricsForInlineBox(const InlineLevelBox& inlineBox, FontBaseline fontBaseline = AlphabeticBaseline) +static InlineLevelBox::AscentAndDescent primaryFontMetricsForInlineBox(const InlineLevelBox& inlineBox, FontBaseline fontBaseline = AlphabeticBaseline) { ASSERT(inlineBox.isInlineBox()); auto& fontMetrics = inlineBox.primarymetricsOfPrimaryFont(); @@ -116,7 +107,7 @@ static bool isTextEdgeLeading(const InlineLevelBox& inlineBox) return textEdge.over == TextEdgeType::Leading; } -static AscentAndDescent ascentAndDescentWithTextEdgeForInlineBox(const InlineLevelBox& inlineBox, const FontMetrics& fontMetrics, FontBaseline fontBaseline) +static InlineLevelBox::AscentAndDescent ascentAndDescentWithTextEdgeForInlineBox(const InlineLevelBox& inlineBox, const FontMetrics& fontMetrics, FontBaseline fontBaseline) { ASSERT(inlineBox.isInlineBox()); @@ -163,7 +154,7 @@ static AscentAndDescent ascentAndDescentWithTextEdgeForInlineBox(const InlineLev return { ascent(), descent() }; } -AscentAndDescent LineBoxBuilder::enclosingAscentDescentWithFallbackFonts(const InlineLevelBox& inlineBox, const TextUtil::FallbackFontList& fallbackFontsForContent, FontBaseline fontBaseline) const +InlineLevelBox::AscentAndDescent LineBoxBuilder::enclosingAscentDescentWithFallbackFonts(const InlineLevelBox& inlineBox, const TextUtil::FallbackFontList& fallbackFontsForContent, FontBaseline fontBaseline) const { ASSERT(!fallbackFontsForContent.isEmpty()); ASSERT(inlineBox.isInlineBox()); @@ -235,15 +226,16 @@ void LineBoxBuilder::setLayoutBoundsForInlineBox(InlineLevelBox& inlineBox, Font void LineBoxBuilder::setVerticalPropertiesForInlineLevelBox(const LineBox& lineBox, InlineLevelBox& inlineLevelBox) const { - auto setAscentAndDescent = [&] (auto ascentAndDescent, bool applyLegacyRounding = true) { - auto adjustedAscentAndDescent = applyLegacyRounding ? ascentAndDescent.round() : ascentAndDescent; - inlineLevelBox.setAscent(adjustedAscentAndDescent.ascent); - inlineLevelBox.setDescent(adjustedAscentAndDescent.descent); - inlineLevelBox.setLayoutBounds({ adjustedAscentAndDescent.ascent, adjustedAscentAndDescent.descent }); + auto setVerticalProperties = [&] (InlineLevelBox::AscentAndDescent ascentAndDescent, bool applyLegacyRounding = true) { + if (applyLegacyRounding) + ascentAndDescent.round(); + inlineLevelBox.setAscentAndDescent(ascentAndDescent); + inlineLevelBox.setLayoutBounds(ascentAndDescent); + inlineLevelBox.setLogicalHeight(ascentAndDescent.height()); }; if (inlineLevelBox.isInlineBox()) { - auto ascentAndDescent = [&]() -> AscentAndDescent { + auto ascentAndDescent = [&]() -> InlineLevelBox::AscentAndDescent { auto leadingTrim = inlineLevelBox.leadingTrim(); auto fontBaseline = lineBox.baselineType(); if (inlineLevelBox.isRootInlineBox() || leadingTrim == LeadingTrim::Normal) @@ -256,8 +248,8 @@ void LineBoxBuilder::setVerticalPropertiesForInlineLevelBox(const LineBox& lineB return { ascent, descent }; }(); - setAscentAndDescent(ascentAndDescent); - inlineLevelBox.setLogicalHeight(ascentAndDescent.height()); + setVerticalProperties(ascentAndDescent); + // Override default layout bounds. setLayoutBoundsForInlineBox(inlineLevelBox, lineBox.baselineType()); // With leading-trim, the inline box top is not always where the content starts. @@ -267,8 +259,7 @@ void LineBoxBuilder::setVerticalPropertiesForInlineLevelBox(const LineBox& lineB } if (inlineLevelBox.isLineBreakBox()) { auto parentAscentAndDescent = primaryFontMetricsForInlineBox(lineBox.parentInlineBox(inlineLevelBox), lineBox.baselineType()); - setAscentAndDescent(parentAscentAndDescent); - inlineLevelBox.setLogicalHeight(parentAscentAndDescent.height()); + setVerticalProperties(parentAscentAndDescent); return; } if (inlineLevelBox.isListMarker()) { @@ -277,15 +268,15 @@ void LineBoxBuilder::setVerticalPropertiesForInlineLevelBox(const LineBox& lineB auto& listMarkerBoxGeometry = formattingContext().geometryForBox(layoutBox); auto marginBoxHeight = listMarkerBoxGeometry.marginBoxHeight(); - inlineLevelBox.setLogicalHeight(marginBoxHeight); if (lineBox.baselineType() == IdeographicBaseline) { // FIXME: We should rely on the integration baseline. - setAscentAndDescent(primaryFontMetricsForInlineBox(lineBox.parentInlineBox(inlineLevelBox), lineBox.baselineType())); + setVerticalProperties(primaryFontMetricsForInlineBox(lineBox.parentInlineBox(inlineLevelBox), lineBox.baselineType())); + inlineLevelBox.setLogicalHeight(marginBoxHeight); return; } if (auto ascent = downcast(layoutBox).baselineForIntegration()) - return setAscentAndDescent(AscentAndDescent { *ascent, marginBoxHeight - *ascent }); - setAscentAndDescent(AscentAndDescent { marginBoxHeight, { } }); + return setVerticalProperties({ *ascent, marginBoxHeight - *ascent }); + setVerticalProperties({ marginBoxHeight, { } }); return; } if (inlineLevelBox.isAtomicInlineLevelBox()) { @@ -310,8 +301,7 @@ void LineBoxBuilder::setVerticalPropertiesForInlineLevelBox(const LineBox& lineB } return marginBoxHeight; }(); - setAscentAndDescent(AscentAndDescent { ascent, marginBoxHeight - ascent }, false); - inlineLevelBox.setLogicalHeight(marginBoxHeight); + setVerticalProperties({ ascent, marginBoxHeight - ascent }, false); return; } ASSERT_NOT_REACHED(); @@ -472,7 +462,7 @@ void LineBoxBuilder::adjustInlineBoxHeightsForLineBoxContainIfApplicable(LineBox continue; auto& inlineBoxGeometry = formattingContext().geometryForBox(inlineLevelBox.layoutBox()); auto ascent = inlineLevelBox.ascent() + inlineBoxGeometry.marginBorderAndPaddingBefore(); - auto descent = valueOrDefault(inlineLevelBox.descent()) + inlineBoxGeometry.marginBorderAndPaddingAfter(); + auto descent = inlineLevelBox.descent() + inlineBoxGeometry.marginBorderAndPaddingAfter(); inlineBoxBoundsMap.set(&inlineLevelBox, TextUtil::EnclosingAscentDescent { ascent, descent }); } } @@ -603,8 +593,7 @@ void LineBoxBuilder::adjustIdeographicBaselineIfApplicable(LineBox& lineBox) auto inlineLevelBoxHeight = inlineLevelBox.logicalHeight(); InlineLayoutUnit ideographicBaseline = roundToInt(inlineLevelBoxHeight / 2); // Move the baseline position but keep the same logical height. - inlineLevelBox.setAscent(ideographicBaseline); - inlineLevelBox.setDescent(inlineLevelBoxHeight - ideographicBaseline); + inlineLevelBox.setAscentAndDescent({ ideographicBaseline, inlineLevelBoxHeight - ideographicBaseline }); inlineLevelBox.setLayoutBounds({ ideographicBaseline, inlineLevelBoxHeight - ideographicBaseline }); } @@ -649,7 +638,7 @@ void LineBoxBuilder::computeLineBoxGeometry(LineBox& lineBox) const auto& rootInlineBox = lineBox.rootInlineBox(); switch (rootStyle.textEdge().under) { case TextEdgeType::Text: - return rootInlineBox.layoutBounds().descent - *rootInlineBox.descent(); + return rootInlineBox.layoutBounds().descent - rootInlineBox.descent(); case TextEdgeType::Alphabetic: return rootInlineBox.layoutBounds().descent; case TextEdgeType::CJKIdeographic: diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h index ebb7f6939cf2..a7e7fa5b5423 100644 --- a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h +++ b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h @@ -36,7 +36,6 @@ namespace Layout { class Box; class ElementBox; class LayoutState; -struct AscentAndDescent; class LineBoxBuilder { public: @@ -49,7 +48,7 @@ class LineBoxBuilder { void setLayoutBoundsForInlineBox(InlineLevelBox&, FontBaseline) const; void adjustInlineBoxHeightsForLineBoxContainIfApplicable(LineBox&); void computeLineBoxGeometry(LineBox&) const; - AscentAndDescent enclosingAscentDescentWithFallbackFonts(const InlineLevelBox&, const TextUtil::FallbackFontList& fallbackFontsForContent, FontBaseline) const; + InlineLevelBox::AscentAndDescent enclosingAscentDescentWithFallbackFonts(const InlineLevelBox&, const TextUtil::FallbackFontList& fallbackFontsForContent, FontBaseline) const; TextUtil::FallbackFontList collectFallbackFonts(const InlineLevelBox& parentInlineBox, const Line::Run&, const RenderStyle&); void constructInlineLevelBoxes(LineBox&); diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxVerticalAligner.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxVerticalAligner.cpp index 0d8f9029ee72..9e4d7f161318 100644 --- a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxVerticalAligner.cpp +++ b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxVerticalAligner.cpp @@ -200,7 +200,7 @@ LineBoxVerticalAligner::LineBoxAlignmentContent LineBoxVerticalAligner::computeL case VerticalAlign::TextBottom: { // Note that text-bottom aligns with the inline box's font metrics bottom (descent) and not the layout bounds bottom. auto parentInlineBoxLayoutBounds = parentInlineBox.layoutBounds(); - auto parentInlineBoxLogicalBottom = parentInlineBoxLayoutBounds.height() - parentInlineBoxLayoutBounds.descent + *parentInlineBox.descent(); + auto parentInlineBoxLogicalBottom = parentInlineBoxLayoutBounds.height() - parentInlineBoxLayoutBounds.descent + parentInlineBox.descent(); logicalTop = parentInlineBoxLogicalBottom - layoutBounds.height(); break; } @@ -310,7 +310,7 @@ void LineBoxVerticalAligner::computeRootInlineBoxVerticalPosition(LineBox& lineB baselineOffsetFromParentBaseline = parentInlineBox.ascent() - layoutBounds.ascent; break; case VerticalAlign::TextBottom: - baselineOffsetFromParentBaseline = layoutBounds.descent - *parentInlineBox.descent(); + baselineOffsetFromParentBaseline = layoutBounds.descent - parentInlineBox.descent(); break; case VerticalAlign::Sub: baselineOffsetFromParentBaseline = -(parentInlineBox.fontSize() / 5 + 1); @@ -364,7 +364,7 @@ void LineBoxVerticalAligner::computeRootInlineBoxVerticalPosition(LineBox& lineB rootInlineBox.setLogicalTop(rootInlineBoxLogicalTop); } -InlineLevelBox::LayoutBounds LineBoxVerticalAligner::layoutBoundsForInlineBoxSubtree(const LineBox::InlineLevelBoxList& nonRootInlineLevelBoxes, size_t inlineBoxIndex) const +InlineLevelBox::AscentAndDescent LineBoxVerticalAligner::layoutBoundsForInlineBoxSubtree(const LineBox::InlineLevelBoxList& nonRootInlineLevelBoxes, size_t inlineBoxIndex) const { // https://w3c.github.io/csswg-drafts/css2/#propdef-vertical-align // @@ -376,7 +376,7 @@ InlineLevelBox::LayoutBounds LineBoxVerticalAligner::layoutBoundsForInlineBoxSub // The top of the aligned subtree is the highest of the tops of the boxes in the subtree, and the bottom is analogous. ASSERT(nonRootInlineLevelBoxes[inlineBoxIndex].isInlineBox()); auto& formattingGeometry = this->formattingGeometry(); - auto enclosingLayoutBounds = InlineLevelBox::LayoutBounds { }; + auto enclosingLayoutBounds = InlineLevelBox::AscentAndDescent { }; auto& inlineBoxParent = nonRootInlineLevelBoxes[inlineBoxIndex].layoutBox().parent(); for (size_t index = inlineBoxIndex + 1; index < nonRootInlineLevelBoxes.size(); ++index) { auto& descendantInlineLevelBox = nonRootInlineLevelBoxes[index]; diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxVerticalAligner.h b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxVerticalAligner.h index eaae12a89560..048833799491 100644 --- a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxVerticalAligner.h +++ b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxVerticalAligner.h @@ -54,7 +54,7 @@ class LineBoxVerticalAligner { void computeRootInlineBoxVerticalPosition(LineBox&, const LineBoxAlignmentContent&) const; void alignInlineLevelBoxes(LineBox&, InlineLayoutUnit lineBoxLogicalHeight) const; InlineLayoutUnit adjustForAnnotationIfNeeded(LineBox&, InlineLayoutUnit lineBoxHeight) const; - InlineLevelBox::LayoutBounds layoutBoundsForInlineBoxSubtree(const LineBox::InlineLevelBoxList& nonRootInlineLevelBoxes, size_t inlineBoxIndex) const; + InlineLevelBox::AscentAndDescent layoutBoundsForInlineBoxSubtree(const LineBox::InlineLevelBoxList& nonRootInlineLevelBoxes, size_t inlineBoxIndex) const; const InlineFormattingGeometry& formattingGeometry() const { return m_inlineFormattingGeometry; } const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }