Skip to content

Commit

Permalink
[IFC][hanging punctuation] Line::applyRunExpansion should only trim p…
Browse files Browse the repository at this point in the history
…re-wrap triggered hanging whitespace

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

Reviewed by Antti Koivisto.

1. Hanging content is not supposed to be taken into account when computing expansion opportunities (align justify).
2. Hanging trailing whitespace content (triggered by pre-wrap) falls outside of the line box,
but it is still part of the trailing text run (i.e. not trimmed).
3. FontCascade::expansionOpportunityCount takes text content (string) to compute the expansion opportunities.
4. We have to adjust the run's length to make sure that the hanging trailing whitespace is not part of this expansion computation.

* Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp:
(WebCore::Layout::Line::applyRunExpansion):
* Source/WebCore/layout/formattingContexts/inline/InlineLine.h:
(WebCore::Layout::Line::HangingContent::resetTrailingContent):
(WebCore::Layout::Line::HangingContent::trailingWhitespaceWidth const):
(WebCore::Layout::Line::HangingContent::trailingWhitespaceLength const):

Canonical link: https://commits.webkit.org/258306@main
  • Loading branch information
alanbaradlay committed Dec 23, 2022
1 parent 7e5f5d8 commit c604535
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 11 deletions.
27 changes: 17 additions & 10 deletions Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp
Expand Up @@ -97,10 +97,7 @@ void Line::applyRunExpansion(InlineLayoutUnit horizontalAvailableSpace)
// the last line before a forced break or the end of the block is start-aligned.
if (m_runs.isEmpty() || m_runs.last().isLineBreak())
return;
// A hanging glyph is still enclosed inside its parent inline box and still participates in text justification:
// its character advance is just not measured when determining how much content fits on the line, how much the line’s contents
// need to be expanded or compressed for justification, or how to position the content within the line box for text alignment.
auto spaceToDistribute = horizontalAvailableSpace - contentLogicalWidth() + m_hangingContent.width();
auto spaceToDistribute = horizontalAvailableSpace - contentLogicalWidth() + m_hangingContent.trailingWhitespaceWidth();
if (spaceToDistribute <= 0)
return;
// Collect and distribute the expansion opportunities.
Expand All @@ -111,24 +108,34 @@ void Line::applyRunExpansion(InlineLayoutUnit horizontalAvailableSpace)

// Line start behaves as if we had an expansion here (i.e. fist runs should not start with allowing left expansion).
auto runIsAfterExpansion = true;
auto hangingContentLength = m_hangingContent.length();
auto hangingTrailingWhitespaceLength = m_hangingContent.trailingWhitespaceLength();
auto lastTextRunIndexForTrimming = [&]() -> std::optional<size_t> {
if (!hangingTrailingWhitespaceLength)
return { };
for (auto index = m_runs.size(); index--;) {
if (m_runs[index].isText())
return index;
}
return { };
}();
for (size_t runIndex = 0; runIndex < m_runs.size(); ++runIndex) {
auto& run = m_runs[runIndex];
auto expansionBehavior = ExpansionBehavior::defaultBehavior();
size_t expansionOpportunitiesInRun = 0;

// FIXME: Check why we don't apply expansion when whitespace is preserved.
if (run.isText() && (!TextUtil::shouldPreserveSpacesAndTabs(run.layoutBox()) || hangingContentLength)) {
if (run.isText() && (!TextUtil::shouldPreserveSpacesAndTabs(run.layoutBox()) || hangingTrailingWhitespaceLength)) {
if (run.hasTextCombine())
expansionBehavior = ExpansionBehavior::forbidAll();
else {
expansionBehavior.left = runIsAfterExpansion ? ExpansionBehavior::Behavior::Forbid : ExpansionBehavior::Behavior::Allow;
expansionBehavior.right = ExpansionBehavior::Behavior::Allow;
auto& textContent = *run.textContent();
// Trailing hanging whitespace sequence is ignored when computing the expansion opportunities.
auto hangingContentInCurrentRun = std::min(textContent.length, hangingContentLength);
auto length = textContent.length - hangingContentInCurrentRun;
hangingContentLength -= hangingContentInCurrentRun;
auto length = textContent.length;
if (lastTextRunIndexForTrimming && runIndex == *lastTextRunIndexForTrimming) {
// Trailing hanging whitespace sequence is ignored when computing the expansion opportunities.
length -= hangingTrailingWhitespaceLength;
}
std::tie(expansionOpportunitiesInRun, runIsAfterExpansion) = FontCascade::expansionOpportunityCount(StringView(downcast<InlineTextBox>(run.layoutBox()).content()).substring(textContent.start, length), run.inlineDirection(), expansionBehavior);
}
} else if (run.isBox())
Expand Down
4 changes: 3 additions & 1 deletion Source/WebCore/layout/formattingContexts/inline/InlineLine.h
Expand Up @@ -243,11 +243,13 @@ class Line {
void setTrailingWhitespace(size_t length, InlineLayoutUnit logicalWidth);

void resetTrailingContent() { m_trailingContent = { }; }

InlineLayoutUnit trailingWidth() const { return m_trailingContent ? m_trailingContent->width : 0.f; }
InlineLayoutUnit trailingWhitespaceWidth() const { return m_trailingContent && m_trailingContent->type == TrailingContent::Type::Whitespace ? m_trailingContent->width : 0.f; }

InlineLayoutUnit width() const { return m_leadingPunctuationWidth + trailingWidth(); }

size_t length() const;
size_t trailingWhitespaceLength() const { return m_trailingContent && m_trailingContent->type == TrailingContent::Type::Whitespace ? m_trailingContent->length : 0; }

bool isTrailingContentPunctuation() const { return m_trailingContent && m_trailingContent->type == TrailingContent::Type::Punctuation; }
bool isTrailingContentConditional() const { return m_trailingContent && m_trailingContent->isConditional == TrailingContent::IsConditional::Yes; }
Expand Down

0 comments on commit c604535

Please sign in to comment.