Skip to content

Commit

Permalink
[IFC][hanging punctuation] Move trailing hanging content handling fro…
Browse files Browse the repository at this point in the history
…m LineBuilder to Line

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

Reviewed by Antti Koivisto.

1. reset trailing punctuation if the current line is not the last formatted line (trailing punctuation is not supposed to be hanging)
2. shrink the content logical width by the hanging content if in preferred width computation mode

* Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp:
(WebCore::Layout::Line::handleTrailingHangingContent):
(WebCore::Layout::Line::removeHangingGlyphs): Deleted.
* Source/WebCore/layout/formattingContexts/inline/InlineLine.h:
* Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp:
(WebCore::Layout::LineBuilder::close):
* Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp:
(WebCore::Layout::TextUtil::hangablePunctuationStartWidth): off-by-one fix.
(WebCore::Layout::TextUtil::hasHangablePunctuationEnd):
(WebCore::Layout::TextUtil::hangablePunctuationEndWidth):
(WebCore::Layout::TextUtil::hangableStopOrCommaEndWidth):

Canonical link: https://commits.webkit.org/258173@main
  • Loading branch information
alanbaradlay committed Dec 21, 2022
1 parent 1b00e98 commit e65bb2e
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 27 deletions.
44 changes: 40 additions & 4 deletions Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp
Expand Up @@ -253,11 +253,47 @@ void Line::handleOverflowingNonBreakingSpace(TrailingContentAction trailingConte
m_contentLogicalWidth -= removedOrCollapsedContentWidth;
}

void Line::removeHangingGlyphs()
void Line::handleTrailingHangingContent(std::optional<IntrinsicWidthMode> intrinsicWidthMode, InlineLayoutUnit horizontalAvailableSpaceForContent, bool isLastFormattedLine)
{
ASSERT(m_trimmableTrailingContent.isEmpty());
m_contentLogicalWidth -= m_hangingContent.width();
m_hangingContent.resetTrailingContent();
if (!isLastFormattedLine)
m_hangingContent.resetTrailingPunctuation();

auto trimmTrailingHangingGlyphsIfApplicable = [&] {
if (!m_hangingContent.trailingWidth()) {
// Nothing to trim here.
return;
}
if (!intrinsicWidthMode) {
// Only trim such content during preferred width computation.
return;
}

// 1. The hanging glyph is also not taken into account when computing intrinsic sizes (min-content size and max-content size)
// 2. Glyphs that conditionally hang are not taken into account when computing min-content sizes, but they are taken into account for max-content sizes.
// https://drafts.csswg.org/css-text/#hanging
auto trimmTrailingHangingGlyphs = [&] {
ASSERT(m_trimmableTrailingContent.isEmpty());
m_contentLogicalWidth -= m_hangingContent.trailingWidth();
m_hangingContent.resetTrailingContent();
};

if (*intrinsicWidthMode == IntrinsicWidthMode::Minimum)
trimmTrailingHangingGlyphs();
else {
// A glyph at the end of a line can conditionally hang: it hangs only if it does not otherwise fit in the line prior to justification
auto isTrailingHangingContentConditional = m_contentLogicalWidth > horizontalAvailableSpaceForContent;
// If white-space is set to pre-wrap, the UA must (unconditionally) hang this sequence, unless the sequence is followed
// by a forced line break, in which case it must conditionally hang the sequence is instead.
// Note that end of last line in a paragraph is considered a forced break.
auto lineEndsWithLineBreak = !runs().isEmpty() && runs().last().isLineBreak();
auto hasConditionalTrailingHangingWhitespace = m_hangingContent.trailingWhitespaceWidth() && (isLastFormattedLine || lineEndsWithLineBreak);

auto isConditionalHanging = hasConditionalTrailingHangingWhitespace || isTrailingHangingContentConditional;
if (!isConditionalHanging)
trimmTrailingHangingGlyphs();
}
};
trimmTrailingHangingGlyphsIfApplicable();
}

void Line::resetBidiLevelForTrailingWhitespace(UBiDiLevel rootBidiLevel)
Expand Down
3 changes: 2 additions & 1 deletion Source/WebCore/layout/formattingContexts/inline/InlineLine.h
Expand Up @@ -35,6 +35,7 @@ namespace Layout {

class InlineFormattingContext;
class InlineSoftLineBreakItem;
enum class IntrinsicWidthMode;

class Line {
public:
Expand Down Expand Up @@ -65,8 +66,8 @@ class Line {

enum class TrailingContentAction : uint8_t { Remove, Preserve };
void handleTrailingTrimmableContent(TrailingContentAction);
void handleTrailingHangingContent(std::optional<IntrinsicWidthMode>, InlineLayoutUnit horizontalAvailableSpace, bool isLastFormattedLine);
void handleOverflowingNonBreakingSpace(TrailingContentAction, InlineLayoutUnit overflowingWidth);
void removeHangingGlyphs();
void resetBidiLevelForTrailingWhitespace(UBiDiLevel rootBidiLevel);
void applyRunExpansion(InlineLayoutUnit horizontalAvailableSpace);
void truncate(InlineLayoutUnit logicalRight);
Expand Down
Expand Up @@ -544,7 +544,7 @@ LineBuilder::InlineItemRange LineBuilder::close(const InlineItemRange& needsLayo
auto isLastLine = isLastLineWithInlineContent(lineRange, needsLayoutRange.end, committedContent.partialTrailingContentLength);
auto horizontalAvailableSpace = m_lineLogicalRect.width();

auto trimTrailingContent = [&] {
auto handleTrailingContent = [&] {
auto& quirks = m_inlineFormattingContext.formattingQuirks();
auto lineHasOverflow = [&] {
return horizontalAvailableSpace < m_line.contentLogicalWidth();
Expand All @@ -563,20 +563,9 @@ LineBuilder::InlineItemRange LineBuilder::close(const InlineItemRange& needsLayo
if (quirks.trailingNonBreakingSpaceNeedsAdjustment(isInIntrinsicWidthMode(), lineHasOverflow()))
m_line.handleOverflowingNonBreakingSpace(isLineBreakAfterWhitespace() ? Line::TrailingContentAction::Preserve : Line::TrailingContentAction::Remove, m_line.contentLogicalWidth() - horizontalAvailableSpace);

if (isInIntrinsicWidthMode()) {
// 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.
// https://drafts.csswg.org/css-text/#hanging
if (*intrinsicWidthMode() == IntrinsicWidthMode::Minimum)
m_line.removeHangingGlyphs();
else {
// Glyphs that conditionally hang are not taken into account when computing min-content sizes and any sizes derived thereof, but they are taken into account for max-content sizes and any sizes derived thereof.
auto isConditionalHanging = isLastLine || lineEndsWithLineBreak();
if (!isConditionalHanging)
m_line.removeHangingGlyphs();
}
}
m_line.handleTrailingHangingContent(intrinsicWidthMode(), horizontalAvailableSpace, isLastLine);
};
trimTrailingContent();
handleTrailingContent();

// On each line, reset the embedding level of any sequence of whitespace characters at the end of the line
// to the paragraph embedding level
Expand Down
Expand Up @@ -446,16 +446,16 @@ float TextUtil::hangablePunctuationStartWidth(const InlineTextItem& inlineTextIt
ASSERT(inlineTextItem.length());
if (!hasHangablePunctuationStart(inlineTextItem, style))
return { };
auto startPosition = inlineTextItem.start();
return width(inlineTextItem, style.fontCascade(), startPosition, startPosition + 1, { });
auto leadingPosition = inlineTextItem.start();
return width(inlineTextItem, style.fontCascade(), leadingPosition, leadingPosition + 1, { });
}

bool TextUtil::hasHangablePunctuationEnd(const InlineTextItem& inlineTextItem, const RenderStyle& style)
{
ASSERT(inlineTextItem.length());
if (!style.hangingPunctuation().contains(HangingPunctuation::Last))
return false;
auto trailingCharacter = inlineTextItem.inlineTextBox().content()[inlineTextItem.end()];
auto trailingCharacter = inlineTextItem.inlineTextBox().content()[inlineTextItem.end() - 1];
return U_GET_GC_MASK(trailingCharacter) & (U_GC_PE_MASK | U_GC_PI_MASK | U_GC_PF_MASK);
}

Expand All @@ -464,14 +464,14 @@ float TextUtil::hangablePunctuationEndWidth(const InlineTextItem& inlineTextItem
ASSERT(inlineTextItem.length());
if (!hasHangablePunctuationEnd(inlineTextItem, style))
return { };
auto endPosition = inlineTextItem.end();
return width(inlineTextItem, style.fontCascade(), endPosition, endPosition + 1, { });
auto trailingPosition = inlineTextItem.end() - 1;
return width(inlineTextItem, style.fontCascade(), trailingPosition, trailingPosition + 1, { });
}

float TextUtil::hangableStopOrCommaEndWidth(const InlineTextItem& inlineTextItem, const RenderStyle& style)
{
auto endPosition = inlineTextItem.end();
auto trailingCharacter = inlineTextItem.inlineTextBox().content()[endPosition];
auto trailingPosition = inlineTextItem.end() - 1;
auto trailingCharacter = inlineTextItem.inlineTextBox().content()[trailingPosition];
auto isHangableStopOrComma = trailingCharacter == 0x002C
|| trailingCharacter == 0x002E || trailingCharacter == 0x060C
|| trailingCharacter == 0x06D4 || trailingCharacter == 0x3001
Expand All @@ -481,7 +481,7 @@ float TextUtil::hangableStopOrCommaEndWidth(const InlineTextItem& inlineTextItem
|| trailingCharacter == 0xFF61 || trailingCharacter == 0xFF64;
if (!isHangableStopOrComma)
return { };
return width(inlineTextItem, style.fontCascade(), endPosition, endPosition + 1, { });
return width(inlineTextItem, style.fontCascade(), trailingPosition, trailingPosition + 1, { });
}

}
Expand Down

0 comments on commit e65bb2e

Please sign in to comment.