Skip to content

Commit

Permalink
[IFC][hanging punctuation] Line's trailing hanging content is either …
Browse files Browse the repository at this point in the history
…preserved whitespace or punctuation

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

Reviewed by Antti Koivisto.

The hanging content could be
- leading punctuation (at the front of the first formatted line)
- trailing punctuation (at the end of the last formatted line)
  or preserved whitespace (and the end of each line)

This patch ensures that Line::HangingContent reflects ^^. It also computes trailing hanging punctuation when applicable.

* Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp:
(WebCore::Layout::Line::resetTrailingContent):
(WebCore::Layout::Line::removeHangingGlyphs):
(WebCore::Layout::Line::appendInlineBoxStart):
(WebCore::Layout::Line::appendInlineBoxEnd):
(WebCore::Layout::Line::appendTextContent):
(WebCore::Layout::Line::HangingContent::addLeadingGlyphs): Deleted.
(WebCore::Layout::Line::HangingContent::addTrailingGlyphs): Deleted.
* Source/WebCore/layout/formattingContexts/inline/InlineLine.h:
(WebCore::Layout::Line::hangingTrailingWhitespaceWidth const):
(WebCore::Layout::Line::hangingTrailingContentWidth const):
(WebCore::Layout::Line::HangingContent::setLeadingPunctuation):
(WebCore::Layout::Line::HangingContent::resetTrailingContent):
(WebCore::Layout::Line::HangingContent::trailingWhitespaceWidth const):
(WebCore::Layout::Line::HangingContent::trailingWidth const):
(WebCore::Layout::Line::HangingContent::width const):
(WebCore::Layout::Line::HangingContent::setTrailingPunctuation):
(WebCore::Layout::Line::HangingContent::setTrailingWhitespace):
(WebCore::Layout::Line::HangingContent::length const):
(WebCore::Layout::Line::HangingContent::resetTrailingPunctuation):
(WebCore::Layout::Line::hangingLeadingContentWidth const): Deleted.
(WebCore::Layout::Line::HangingContent::leadingLength const): Deleted.
(WebCore::Layout::Line::HangingContent::trailingLength const): Deleted.
(WebCore::Layout::Line::HangingContent::leadingWidth const): Deleted.
(WebCore::Layout::Line::HangingContent::reset): Deleted.
(WebCore::Layout::Line::HangingContent::resetTrailingGlyphs): Deleted.
* Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp:
(WebCore::Layout::trimmableTrailingContentWidth):

Canonical link: https://commits.webkit.org/258159@main
  • Loading branch information
alanbaradlay committed Dec 20, 2022
1 parent 5b954c5 commit 4d0e3a4
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 52 deletions.
43 changes: 16 additions & 27 deletions Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp
Expand Up @@ -85,7 +85,7 @@ void Line::initialize(const Vector<InlineItem>& lineSpanningInlineBoxes, bool is
void Line::resetTrailingContent()
{
m_trimmableTrailingContent.reset();
m_hangingContent.resetTrailingGlyphs();
m_hangingContent.resetTrailingContent();
m_trailingSoftHyphenWidth = { };
}

Expand Down Expand Up @@ -257,7 +257,7 @@ void Line::removeHangingGlyphs()
{
ASSERT(m_trimmableTrailingContent.isEmpty());
m_contentLogicalWidth -= m_hangingContent.width();
m_hangingContent.reset();
m_hangingContent.resetTrailingContent();
}

void Line::resetBidiLevelForTrailingWhitespace(UBiDiLevel rootBidiLevel)
Expand Down Expand Up @@ -331,7 +331,7 @@ void Line::appendInlineBoxStart(const InlineItem& inlineItem, const RenderStyle&
{
auto& inlineBoxGeometry = formattingContext().geometryForBox(inlineItem.layoutBox());
if (inlineBoxGeometry.marginBorderAndPaddingStart())
m_hangingContent.resetTrailingGlyphs();
m_hangingContent.resetTrailingContent();
// This is really just a placeholder to mark the start of the inline box <span>.
++m_nonSpanningInlineLevelBoxCount;
auto logicalLeft = lastRunLogicalRight();
Expand All @@ -352,7 +352,7 @@ void Line::appendInlineBoxStart(const InlineItem& inlineItem, const RenderStyle&
void Line::appendInlineBoxEnd(const InlineItem& inlineItem, const RenderStyle& style, InlineLayoutUnit logicalWidth)
{
if (formattingContext().geometryForBox(inlineItem.layoutBox()).marginBorderAndPaddingEnd())
m_hangingContent.resetTrailingGlyphs();
m_hangingContent.resetTrailingContent();
// This is really just a placeholder to mark the end of the inline box </span>.
auto removeTrailingLetterSpacing = [&] {
if (!m_trimmableTrailingContent.isTrailingRunPartiallyTrimmable())
Expand Down Expand Up @@ -478,22 +478,27 @@ void Line::appendTextContent(const InlineTextItem& inlineTextItem, const RenderS
auto isTrimmable = updateTrimmableStatus();

auto updateHangingStatus = [&] {
if (inlineTextItem.isWhitespace() && !isTrimmable && m_runs[lastRunIndex].shouldTrailingWhitespaceHang()) {
// Hanging trailing whitespace.
m_hangingContent.addTrailingGlyphs(inlineTextItem.length(), logicalWidth);
if (runHasHangablePunctuationStart)
m_hangingContent.setLeadingPunctuation(TextUtil::hangablePunctuationStartWidth(inlineTextItem, style));

auto runHasHangableWhitespaceEnd = inlineTextItem.isWhitespace() && !isTrimmable && m_runs[lastRunIndex].shouldTrailingWhitespaceHang();
auto runHasHangablePunctuationEnd = TextUtil::hasHangablePunctuationEnd(inlineTextItem, style);
if (runHasHangableWhitespaceEnd) {
ASSERT(!runHasHangablePunctuationEnd);
m_hangingContent.setTrailingWhitespace(inlineTextItem.length(), logicalWidth);
return;
}
if (runHasHangablePunctuationStart) {
m_hangingContent.addLeadingGlyphs(1, TextUtil::hangablePunctuationStartWidth(inlineTextItem, style));
if (runHasHangablePunctuationEnd) {
ASSERT(!runHasHangableWhitespaceEnd);
m_hangingContent.setTrailingPunctuation(TextUtil::hangablePunctuationEndWidth(inlineTextItem, style));
return;
}
m_hangingContent.resetTrailingGlyphs();
m_hangingContent.resetTrailingContent();
};
updateHangingStatus();

if (inlineTextItem.hasTrailingSoftHyphen())
m_trailingSoftHyphenWidth = style.fontCascade().width(TextRun { StringView { style.hyphenString() } });

}

void Line::appendNonReplacedInlineLevelBox(const InlineItem& inlineItem, const RenderStyle& style, InlineLayoutUnit marginBoxLogicalWidth)
Expand Down Expand Up @@ -667,22 +672,6 @@ InlineLayoutUnit Line::TrimmableTrailingContent::removePartiallyTrimmableContent
return remove();
}

void Line::HangingContent::addLeadingGlyphs(size_t length, InlineLayoutUnit logicalWidth)
{
// Hanging punctuation.
m_leadingLength += length;
m_leadingWidth += logicalWidth;
}

void Line::HangingContent::addTrailingGlyphs(size_t length, InlineLayoutUnit logicalWidth)
{
// When a glyph at the start or end edge of a line hangs, it is not considered when measuring the line’s contents for fit, alignment, or justification.
// Depending on the line’s alignment/justification, this can result in the mark being placed outside the line box.
// https://drafts.csswg.org/css-text-3/#hanging
m_trailingLength += length;
m_trailingWidth += logicalWidth;
}

inline static Line::Run::Type toLineRunType(const InlineItem& inlineItem)
{
switch (inlineItem.type()) {
Expand Down
64 changes: 41 additions & 23 deletions Source/WebCore/layout/formattingContexts/inline/InlineLine.h
Expand Up @@ -57,8 +57,8 @@ class Line {
InlineLayoutUnit trimmableTrailingWidth() const { return m_trimmableTrailingContent.width(); }
bool isTrailingRunFullyTrimmable() const { return m_trimmableTrailingContent.isTrailingRunFullyTrimmable(); }

InlineLayoutUnit hangingTrailingWhitespaceWidth() const { return m_hangingContent.trailingWhitespaceWidth(); }
InlineLayoutUnit hangingTrailingContentWidth() const { return m_hangingContent.trailingWidth(); }
InlineLayoutUnit hangingLeadingContentWidth() const { return m_hangingContent.leadingWidth(); }

std::optional<InlineLayoutUnit> trailingSoftHyphenWidth() const { return m_trailingSoftHyphenWidth; }
void addTrailingHyphen(InlineLayoutUnit hyphenLogicalWidth);
Expand Down Expand Up @@ -237,25 +237,29 @@ class Line {
};

struct HangingContent {
void addLeadingGlyphs(size_t length, InlineLayoutUnit logicalWidth);
void addTrailingGlyphs(size_t length, InlineLayoutUnit logicalWidth);
void setLeadingPunctuation(InlineLayoutUnit logicalWidth) { m_leadingPunctuationWidth = logicalWidth; }
void setTrailingPunctuation(InlineLayoutUnit logicalWidth);
void setTrailingWhitespace(size_t length, InlineLayoutUnit logicalWidth);

void reset();
void resetTrailingGlyphs();
void resetTrailingContent() { m_trailingContent = { }; }
void resetTrailingPunctuation();

size_t leadingLength() const { return m_leadingLength; }
size_t trailingLength() const { return m_trailingLength; }
size_t length() const { return leadingLength() + trailingLength(); }
InlineLayoutUnit trailingWhitespaceWidth() const { return m_trailingContent && m_trailingContent->type == TrailingContent::Type::Whitespace ? m_trailingContent->width : 0.f; }
InlineLayoutUnit trailingWidth() const { return m_trailingContent ? m_trailingContent->width : 0.f; }
InlineLayoutUnit width() const { return m_leadingPunctuationWidth + trailingWidth(); }

InlineLayoutUnit leadingWidth() const { return m_leadingWidth; }
InlineLayoutUnit trailingWidth() const { return m_trailingWidth; }
InlineLayoutUnit width() const { return leadingWidth() + trailingWidth(); }
size_t length() const;

private:
size_t m_leadingLength { 0 };
size_t m_trailingLength { 0 };
InlineLayoutUnit m_leadingWidth { 0 };
InlineLayoutUnit m_trailingWidth { 0 };
InlineLayoutUnit m_leadingPunctuationWidth { 0.f };
// There's either a whitespace or punctuation trailing content.
struct TrailingContent {
enum class Type : uint8_t { Whitespace, Punctuation };
Type type { Type::Whitespace };
size_t length { 0 };
InlineLayoutUnit width { 0.f };
};
std::optional<TrailingContent> m_trailingContent { };
};

const InlineFormattingContext& m_inlineFormattingContext;
Expand All @@ -264,7 +268,7 @@ class Line {
HangingContent m_hangingContent;
InlineLayoutUnit m_contentLogicalWidth { 0 };
size_t m_nonSpanningInlineLevelBoxCount { 0 };
std::optional<InlineLayoutUnit> m_trailingSoftHyphenWidth { 0 };
std::optional<InlineLayoutUnit> m_trailingSoftHyphenWidth { };
InlineBoxListWithClonedDecorationEnd m_inlineBoxListWithClonedDecorationEnd;
InlineLayoutUnit m_clonedEndDecorationWidthForInlineBoxRuns { 0 };
bool m_hasNonDefaultBidiLevelRun { false };
Expand All @@ -290,17 +294,31 @@ inline void Line::TrimmableTrailingContent::reset()
m_trimmableContentOffset = { };
}

inline void Line::HangingContent::reset()
inline void Line::HangingContent::setTrailingPunctuation(InlineLayoutUnit logicalWidth)
{
m_trailingContent = { TrailingContent::Type::Punctuation, 1, logicalWidth };
}

inline void Line::HangingContent::setTrailingWhitespace(size_t length, InlineLayoutUnit logicalWidth)
{
m_trailingContent = { TrailingContent::Type::Whitespace, length, logicalWidth };
}

inline size_t Line::HangingContent::length() const
{
m_leadingLength = { };
m_leadingWidth = { };
resetTrailingGlyphs();
size_t length = 0;
if (m_leadingPunctuationWidth)
++length;
if (m_trailingContent)
length += m_trailingContent->length;
return length;
}

inline void Line::HangingContent::resetTrailingGlyphs()
inline void Line::HangingContent::resetTrailingPunctuation()
{
m_trailingLength = { };
m_trailingWidth = { };
if (!m_trailingContent || m_trailingContent->type == TrailingContent::Type::Whitespace)
return;
m_trailingContent = { };
}

inline void Line::Run::setNeedsHyphen(InlineLayoutUnit hyphenLogicalWidth)
Expand Down
Expand Up @@ -827,10 +827,10 @@ static bool shouldDisableHyphenation(const RenderStyle& rootStyle, unsigned succ
static float trimmableTrailingContentWidth(const Line& line)
{
if (auto trimmableWidth = line.trimmableTrailingWidth()) {
ASSERT(!line.hangingTrailingContentWidth());
ASSERT(!line.hangingTrailingWhitespaceWidth());
return trimmableWidth;
}
return line.hangingTrailingContentWidth();
return line.hangingTrailingWhitespaceWidth();
}

static inline InlineLayoutUnit availableWidth(const LineCandidate::InlineContent& candidateContent, const Line& line, InlineLayoutUnit availableWidthForContent)
Expand Down

0 comments on commit 4d0e3a4

Please sign in to comment.