Skip to content

Commit

Permalink
[leading-trim][IFC] Add support for leading-trim on non-root inline b…
Browse files Browse the repository at this point in the history
…oxes

https://bugs.webkit.org/show_bug.cgi?id=248644

Reviewed by Antti Koivisto.

This patch adds initial support for leading-trim on non-root inline boxes.
"leading-trim" consults "text-edge" and trims the over/under sides accordingly.

Trimming here means that the content box of the inline box shrinks to match what "text-edge" says.
It also means that now the content logical top inside the inline box does not necessarily match the inline box's logical top. e.g. when text-edge says "ex" and leading-trim says "start", the "over ex" part of the text content starts overflowing the inline box's content box, or in other words the text content's top position is above the containing inline box's top.

* Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h:
(WebCore::Layout::InlineLevelBox::leadingTrim const):
(WebCore::Layout::InlineLevelBox::inlineBoxContentOffsetForLeadingTrim const):
(WebCore::Layout::InlineLevelBox::setInlineBoxContentOffsetForLeadingTrim):
(WebCore::Layout::m_style):
* Source/WebCore/layout/formattingContexts/inline/InlineLineBox.cpp:
(WebCore::Layout::LineBox::logicalRectForTextRun const):
* Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp:
(WebCore::Layout::LineBoxBuilder::computedAsentAndDescentForInlineBox const):
(WebCore::Layout::LineBoxBuilder::setVerticalPropertiesForInlineLevelBox const):
* Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h:

Canonical link: https://commits.webkit.org/257338@main
  • Loading branch information
alanbaradlay committed Dec 4, 2022
1 parent fc7f341 commit 951ce5d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 4 deletions.
Expand Up @@ -77,7 +77,10 @@ class InlineLevelBox {
const FontMetrics& primarymetricsOfPrimaryFont() const { return m_style.primaryFontMetrics; }
InlineLayoutUnit fontSize() const { return m_style.primaryFontSize; }

// FIXME: Maybe it's time to subclass inline box types.
TextEdge textEdge() const { return m_style.textEdge; }
LeadingTrim leadingTrim() const { return m_style.leadingTrim; }
InlineLayoutUnit inlineBoxContentOffsetForLeadingTrim() const { return m_inlineBoxContentOffsetForLeadingTrim; }

bool hasAnnotation() const { return hasContent() && m_annotation.has_value(); };
std::optional<InlineLayoutUnit> annotationAbove() const { return hasAnnotation() && m_annotation->type == Annotation::Type::Above ? std::make_optional(m_annotation->size) : std::nullopt; }
Expand Down Expand Up @@ -132,6 +135,7 @@ class InlineLevelBox {
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 setInlineBoxContentOffsetForLeadingTrim(InlineLayoutUnit offset) { m_inlineBoxContentOffsetForLeadingTrim = offset; }

void setIsFirstBox() { m_isFirstWithinLayoutBox = true; }
void setIsLastBox() { m_isLastWithinLayoutBox = true; }
Expand All @@ -141,6 +145,7 @@ class InlineLevelBox {
// This is the combination of margin and border boxes. Inline level boxes are vertically aligned using their margin boxes.
InlineRect m_logicalRect;
std::optional<LayoutBounds> m_layoutBounds { };
InlineLayoutUnit m_inlineBoxContentOffsetForLeadingTrim { 0.f };
InlineLayoutUnit m_ascent { 0 };
std::optional<InlineLayoutUnit> m_descent;
bool m_hasContent { false };
Expand All @@ -154,6 +159,7 @@ class InlineLevelBox {
const FontMetrics& primaryFontMetrics;
const Length& lineHeight;
TextEdge textEdge;
LeadingTrim leadingTrim;
WTF::OptionSet<LineBoxContain> lineBoxContain;
InlineLayoutUnit primaryFontSize { 0 };
VerticalAlignment verticalAlignment { };
Expand All @@ -174,7 +180,7 @@ inline InlineLevelBox::InlineLevelBox(const Box& layoutBox, const RenderStyle& s
, m_isFirstWithinLayoutBox(positionWithinLayoutBox.contains(PositionWithinLayoutBox::First))
, m_isLastWithinLayoutBox(positionWithinLayoutBox.contains(PositionWithinLayoutBox::Last))
, m_type(type)
, m_style({ style.fontCascade().metricsOfPrimaryFont(), style.lineHeight(), style.textEdge(), style.lineBoxContain(), InlineLayoutUnit(style.fontCascade().fontDescription().computedPixelSize()), { } })
, m_style({ style.fontCascade().metricsOfPrimaryFont(), style.lineHeight(), style.textEdge(), style.leadingTrim(), style.lineBoxContain(), InlineLayoutUnit(style.fontCascade().fontDescription().computedPixelSize()), { } })
{
m_style.verticalAlignment.type = style.verticalAlign();
if (m_style.verticalAlignment.type == VerticalAlign::Length)
Expand Down
Expand Up @@ -53,13 +53,13 @@ InlineRect LineBox::logicalRectForTextRun(const Line::Run& run) const
ASSERT(run.isText() || run.isSoftLineBreak());
auto* parentInlineBox = &inlineLevelBoxForLayoutBox(run.layoutBox().parent());
ASSERT(parentInlineBox->isInlineBox());
auto runlogicalTop = parentInlineBox->logicalTop();
auto runlogicalTop = parentInlineBox->logicalTop() - parentInlineBox->inlineBoxContentOffsetForLeadingTrim();
InlineLayoutUnit logicalHeight = parentInlineBox->primarymetricsOfPrimaryFont().height();

while (parentInlineBox != &m_rootInlineBox && !parentInlineBox->hasLineBoxRelativeAlignment()) {
parentInlineBox = &inlineLevelBoxForLayoutBox(parentInlineBox->layoutBox().parent());
ASSERT(parentInlineBox->isInlineBox());
runlogicalTop += parentInlineBox->logicalTop();
runlogicalTop += (parentInlineBox->logicalTop() - parentInlineBox->inlineBoxContentOffsetForLeadingTrim());
}
return { runlogicalTop, run.logicalLeft(), run.logicalWidth(), logicalHeight };
}
Expand Down
Expand Up @@ -294,6 +294,59 @@ void LineBoxBuilder::setLayoutBoundsForInlineBox(InlineLevelBox& inlineBox, Font
inlineBox.setLayoutBounds({ floorf(ascent), ceilf(descent) });
}

AscentAndDescent LineBoxBuilder::computedAsentAndDescentForInlineBox(InlineLevelBox& inlineBox, FontBaseline fontBaseline) const
{
ASSERT(inlineBox.isInlineBox());
if (inlineBox.isRootInlineBox())
return primaryFontMetricsForInlineBox(inlineBox, fontBaseline);

auto& fontMetrics = inlineBox.primarymetricsOfPrimaryFont();
auto leadingTrim = inlineBox.leadingTrim();
if (leadingTrim == LeadingTrim::Normal)
return primaryFontMetricsForInlineBox(inlineBox, fontBaseline);
auto ascent = [&]() -> InlineLayoutUnit {
if (leadingTrim == LeadingTrim::End)
return fontMetrics.ascent(fontBaseline);

switch (inlineBox.textEdge().over) {
case TextEdgeType::Leading:
case TextEdgeType::Text:
return fontMetrics.ascent(fontBaseline);
case TextEdgeType::CapHeight:
return fontMetrics.floatCapHeight();
case TextEdgeType::ExHeight:
return fontMetrics.xHeight();
case TextEdgeType::CJKIdeographic:
case TextEdgeType::CJKIdeographicInk:
ASSERT_NOT_IMPLEMENTED_YET();
return fontMetrics.ascent(fontBaseline);
default:
ASSERT_NOT_REACHED();
return fontMetrics.ascent(fontBaseline);
}
};
auto descent = [&]() -> InlineLayoutUnit {
if (leadingTrim == LeadingTrim::Start)
return fontMetrics.descent(fontBaseline);

switch (inlineBox.textEdge().under) {
case TextEdgeType::Leading:
case TextEdgeType::Text:
return fontMetrics.descent(fontBaseline);
case TextEdgeType::Alphabetic:
return 0.f;
case TextEdgeType::CJKIdeographic:
case TextEdgeType::CJKIdeographicInk:
ASSERT_NOT_IMPLEMENTED_YET();
return fontMetrics.descent(fontBaseline);
default:
ASSERT_NOT_REACHED();
return fontMetrics.descent(fontBaseline);
}
};
return { ascent(), descent() };
}

void LineBoxBuilder::setVerticalPropertiesForInlineLevelBox(const LineBox& lineBox, InlineLevelBox& inlineLevelBox) const
{
auto setAscentAndDescent = [&] (auto ascentAndDescent, bool applyLegacyRounding = true) {
Expand All @@ -304,9 +357,13 @@ void LineBoxBuilder::setVerticalPropertiesForInlineLevelBox(const LineBox& lineB

if (inlineLevelBox.isInlineBox()) {
setLayoutBoundsForInlineBox(inlineLevelBox, lineBox.baselineType());
auto ascentAndDescent = primaryFontMetricsForInlineBox(inlineLevelBox, lineBox.baselineType());
auto ascentAndDescent = computedAsentAndDescentForInlineBox(inlineLevelBox, lineBox.baselineType());
setAscentAndDescent(ascentAndDescent);
inlineLevelBox.setLogicalHeight(ascentAndDescent.height());

// With leading-trim, the inline box top is not always where the content starts.
auto fontMetricAscent = primaryFontMetricsForInlineBox(inlineLevelBox, lineBox.baselineType()).ascent;
inlineLevelBox.setInlineBoxContentOffsetForLeadingTrim(fontMetricAscent - ascentAndDescent.ascent);
return;
}
if (inlineLevelBox.isLineBreakBox()) {
Expand Down
Expand Up @@ -35,6 +35,7 @@ namespace Layout {
class Box;
class ElementBox;
class LayoutState;
struct AscentAndDescent;

class LineBoxBuilder {
public:
Expand All @@ -45,6 +46,7 @@ class LineBoxBuilder {
private:
void setVerticalPropertiesForInlineLevelBox(const LineBox&, InlineLevelBox&) const;
void setLayoutBoundsForInlineBox(InlineLevelBox&, FontBaseline) const;
AscentAndDescent computedAsentAndDescentForInlineBox(InlineLevelBox&, FontBaseline) const;
void adjustInlineBoxHeightsForLineBoxContainIfApplicable(const LineBuilder::LineContent&, LineBox&, size_t lineIndex);
InlineLevelBox::LayoutBounds adjustedLayoutBoundsWithFallbackFonts(InlineLevelBox&, const TextUtil::FallbackFontList& fallbackFontsForContent, FontBaseline) const;
TextUtil::FallbackFontList collectFallbackFonts(const InlineLevelBox& parentInlineBox, const Line::Run&, const RenderStyle&);
Expand Down

0 comments on commit 951ce5d

Please sign in to comment.