Diff
Modified: trunk/LayoutTests/ChangeLog (251014 => 251015)
--- trunk/LayoutTests/ChangeLog 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/ChangeLog 2019-10-11 19:03:37 UTC (rev 251015)
@@ -1,3 +1,27 @@
+2019-10-11 Antti Koivisto <[email protected]>
+
+ Position::upstream/downstream should not need to call ensureLineBoxes
+ https://bugs.webkit.org/show_bug.cgi?id=202203
+
+ Reviewed by Zalan Bujtas.
+
+ Some additional end of line whitespaces.
+
+ * TestExpectations:
+
+ Skip imported/w3c/web-platform-tests/css/css-text/white-space/pre-wrap-013.html.
+
+ This test starts failing because soft linebreak clears the trailing whitespace run.
+ The failing behavior aligns simple path with the complex path. The existing textarea-pre-wrap-013.html
+ test (which takes the complex path) is already skipped because of this.
+
+ * platform/mac/fast/forms/targeted-frame-submission-expected.txt:
+ * platform/mac/fast/forms/textarea-scroll-height-expected.txt:
+ * platform/mac/fast/loader/text-document-wrapping-expected.txt:
+ * platform/mac/fast/parser/open-comment-in-textarea-expected.txt:
+ * platform/mac/http/tests/misc/acid3-expected.txt:
+ * platform/mac/http/tests/navigation/_javascript_link-frames-expected.txt:
+
2019-10-11 Dean Jackson <[email protected]>
Layout test fast/events/touch/ios/passive-by-default-on-document-and-window.html is a flaky failure on Internal iOS Testers
Modified: trunk/LayoutTests/TestExpectations (251014 => 251015)
--- trunk/LayoutTests/TestExpectations 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/TestExpectations 2019-10-11 19:03:37 UTC (rev 251015)
@@ -2463,6 +2463,7 @@
webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/text-transform/text-transform-upperlower-039.html [ ImageOnlyFailure ]
webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/text-transform/text-transform-upperlower-103.html [ ImageOnlyFailure Pass ]
webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/text-transform/text-transform-upperlower-104.html [ ImageOnlyFailure Pass ]
+webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/white-space/pre-wrap-013.html [ ImageOnlyFailure ]
webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/white-space/textarea-pre-wrap-012.html [ ImageOnlyFailure ]
webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/white-space/textarea-pre-wrap-013.html [ ImageOnlyFailure ]
webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/word-break/word-break-break-all-004.html [ ImageOnlyFailure ]
Modified: trunk/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.txt (251014 => 251015)
--- trunk/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.txt 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.txt 2019-10-11 19:03:37 UTC (rev 251015)
@@ -24,4 +24,5 @@
RenderBlock {PRE} at (0,0) size 284x15
RenderText {#text} at (0,0) size 55x15
text run at (0,0) width 55: "SUCCESS"
+ text run at (54,0) width 1: " "
RenderText {#text} at (0,0) size 0x0
Modified: trunk/LayoutTests/platform/mac/fast/forms/textarea-scroll-height-expected.txt (251014 => 251015)
--- trunk/LayoutTests/platform/mac/fast/forms/textarea-scroll-height-expected.txt 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/platform/mac/fast/forms/textarea-scroll-height-expected.txt 2019-10-11 19:03:37 UTC (rev 251015)
@@ -12,26 +12,42 @@
RenderBlock {DIV} at (3,3) size 179x312
RenderText {#text} at (0,0) size 83x299
text run at (0,0) width 83: "Lots of content."
+ text run at (82,0) width 1: " "
text run at (0,13) width 83: "Lots of content."
+ text run at (82,13) width 1: " "
text run at (0,26) width 83: "Lots of content."
+ text run at (82,26) width 1: " "
text run at (0,39) width 83: "Lots of content."
+ text run at (82,39) width 1: " "
text run at (0,52) width 0: " "
text run at (0,65) width 83: "Lots of content."
+ text run at (82,65) width 1: " "
text run at (0,78) width 83: "Lots of content."
+ text run at (82,78) width 1: " "
text run at (0,91) width 0: " "
text run at (0,104) width 83: "Lots of content."
+ text run at (82,104) width 1: " "
text run at (0,117) width 83: "Lots of content."
+ text run at (82,117) width 1: " "
text run at (0,130) width 0: " "
text run at (0,143) width 83: "Lots of content."
+ text run at (82,143) width 1: " "
text run at (0,156) width 83: "Lots of content."
+ text run at (82,156) width 1: " "
text run at (0,169) width 0: " "
text run at (0,182) width 83: "Lots of content."
+ text run at (82,182) width 1: " "
text run at (0,195) width 83: "Lots of content."
+ text run at (82,195) width 1: " "
text run at (0,208) width 0: " "
text run at (0,221) width 83: "Lots of content."
+ text run at (82,221) width 1: " "
text run at (0,234) width 83: "Lots of content."
+ text run at (82,234) width 1: " "
text run at (0,247) width 0: " "
text run at (0,260) width 83: "Lots of content."
+ text run at (82,260) width 1: " "
text run at (0,273) width 83: "Lots of content."
+ text run at (82,273) width 1: " "
text run at (0,286) width 0: " "
RenderBR {BR} at (0,299) size 0x13
Modified: trunk/LayoutTests/platform/mac/fast/loader/text-document-wrapping-expected.txt (251014 => 251015)
--- trunk/LayoutTests/platform/mac/fast/loader/text-document-wrapping-expected.txt 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/platform/mac/fast/loader/text-document-wrapping-expected.txt 2019-10-11 19:03:37 UTC (rev 251015)
@@ -12,7 +12,9 @@
RenderBlock {PRE} at (0,0) size 784x75
RenderText {#text} at (0,0) size 781x75
text run at (0,0) width 406: "This line should wrap with no horizontal scroll bar:"
+ text run at (405,0) width 1: " "
text run at (0,15) width 0: " "
text run at (0,30) width 781: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv"
text run at (0,45) width 781: "wxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr"
text run at (0,60) width 469: "stuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
+ text run at (468,60) width 1: " "
Modified: trunk/LayoutTests/platform/mac/fast/parser/open-comment-in-textarea-expected.txt (251014 => 251015)
--- trunk/LayoutTests/platform/mac/fast/parser/open-comment-in-textarea-expected.txt 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/platform/mac/fast/parser/open-comment-in-textarea-expected.txt 2019-10-11 19:03:37 UTC (rev 251015)
@@ -8,8 +8,10 @@
layer at (10,10) size 161x32 clip at (11,11) size 144x30 scrollHeight 56
RenderTextControl {TEXTAREA} at (2,2) size 161x32 [bgcolor=#FFFFFF] [border: (1px solid #000000)]
RenderBlock {DIV} at (3,3) size 140x52
- RenderText {#text} at (0,0) size 136x39
+ RenderText {#text} at (0,0) size 139x39
text run at (0,0) width 22: "<!--"
- text run at (0,13) width 136: "This should be part of the"
+ text run at (21,0) width 1: " "
+ text run at (0,13) width 139: "This should be part of the "
text run at (0,26) width 47: "textarea."
+ text run at (46,26) width 1: " "
RenderBR {BR} at (0,39) size 0x13
Modified: trunk/LayoutTests/platform/mac/http/tests/misc/acid3-expected.txt (251014 => 251015)
--- trunk/LayoutTests/platform/mac/http/tests/misc/acid3-expected.txt 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/platform/mac/http/tests/misc/acid3-expected.txt 2019-10-11 19:03:37 UTC (rev 251015)
@@ -54,7 +54,7 @@
text run at (0,90) width 8: "Y"
text run at (0,105) width 8: "P"
text run at (0,120) width 8: "E"
- text run at (0,135) width 8: " "
+ text run at (0,135) width 0: " "
text run at (0,150) width 8: "h"
text run at (0,165) width 8: "t"
text run at (0,180) width 8: "m"
Modified: trunk/LayoutTests/platform/mac/http/tests/navigation/_javascript_link-frames-expected.txt (251014 => 251015)
--- trunk/LayoutTests/platform/mac/http/tests/navigation/_javascript_link-frames-expected.txt 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/platform/mac/http/tests/navigation/_javascript_link-frames-expected.txt 2019-10-11 19:03:37 UTC (rev 251015)
@@ -108,6 +108,7 @@
RenderBlock {DIV} at (3,3) size 225x26
RenderText {#text} at (0,0) size 178x13
text run at (0,0) width 178: "More initial text before user input."
+ text run at (177,0) width 1: " "
RenderBR {BR} at (0,13) size 0x13
RenderFrame {FRAME} at (0,540) size 800x60
layer at (0,0) size 785x90
Modified: trunk/LayoutTests/platform/mac-highsierra/fast/forms/targeted-frame-submission-expected.txt (251014 => 251015)
--- trunk/LayoutTests/platform/mac-highsierra/fast/forms/targeted-frame-submission-expected.txt 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/platform/mac-highsierra/fast/forms/targeted-frame-submission-expected.txt 2019-10-11 19:03:37 UTC (rev 251015)
@@ -24,4 +24,5 @@
RenderBlock {PRE} at (0,0) size 284x15
RenderText {#text} at (0,0) size 55x15
text run at (0,0) width 55: "SUCCESS"
+ text run at (54,0) width 1: " "
RenderText {#text} at (0,0) size 0x0
Modified: trunk/LayoutTests/platform/mac-highsierra/http/tests/navigation/_javascript_link-frames-expected.txt (251014 => 251015)
--- trunk/LayoutTests/platform/mac-highsierra/http/tests/navigation/_javascript_link-frames-expected.txt 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/LayoutTests/platform/mac-highsierra/http/tests/navigation/_javascript_link-frames-expected.txt 2019-10-11 19:03:37 UTC (rev 251015)
@@ -108,6 +108,7 @@
RenderBlock {DIV} at (3,3) size 225x26
RenderText {#text} at (0,0) size 178x13
text run at (0,0) width 178: "More initial text before user input."
+ text run at (177,0) width 1: " "
RenderBR {BR} at (0,13) size 0x13
RenderFrame {FRAME} at (0,540) size 800x60
layer at (0,0) size 785x90
Modified: trunk/Source/WebCore/ChangeLog (251014 => 251015)
--- trunk/Source/WebCore/ChangeLog 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/Source/WebCore/ChangeLog 2019-10-11 19:03:37 UTC (rev 251015)
@@ -1,3 +1,50 @@
+2019-10-11 Antti Koivisto <[email protected]>
+
+ Position::upstream/downstream should not need to call ensureLineBoxes
+ https://bugs.webkit.org/show_bug.cgi?id=202203
+
+ Reviewed by Zalan Bujtas.
+
+ This avoids forced switch to complex text layout path by Position constructor and will allow future cleanups.
+
+ Currently simple line path strips end of line whitespace when white-space:pre-wrap is set.
+ These are don't affect rendering but they are needed for editing positions.
+ This patch makes simple line path match the complex path by generating runs for these whitespaces.
+
+ * dom/Position.cpp:
+ (WebCore::Position::upstream const):
+ (WebCore::Position::downstream const):
+ (WebCore::ensureLineBoxesIfNeeded): Deleted.
+ * rendering/SimpleLineLayout.cpp:
+ (WebCore::SimpleLineLayout::LineState::appendFragmentAndCreateRunIfNeeded):
+
+ Create a new run if isLineBreak bit is set.
+
+ (WebCore::SimpleLineLayout::LineState::removeTrailingWhitespace):
+ (WebCore::SimpleLineLayout::LineState::trailingWhitespaceWidth const):
+ (WebCore::SimpleLineLayout::computeLineLeft):
+
+ Also compute width of the hanging whitespace when aligning the line. This matches the code
+ in updateLogicalWidthForLeft/Right/CenterAlignedBlock in the complex path.
+
+ (WebCore::SimpleLineLayout::preWrap):
+
+ breakSpaces implies preWrap is off.
+
+ (WebCore::SimpleLineLayout::firstFragment):
+ (WebCore::SimpleLineLayout::createLineRuns):
+
+ Crete runs also for soft linebreaks in pre-wrap.
+ Add whitespace runs to the end of the line in pre-wrap.
+
+ (WebCore::SimpleLineLayout::closeLineEndingAndAdjustRuns):
+
+ Hang the whitespace run when wrapping.
+
+ (WebCore::SimpleLineLayout::removeTrailingWhitespace): Deleted.
+
+ Remainging logic moved to the callsite.
+
2019-10-11 Jonathan Bedard <[email protected]>
Unreviewed, rolling out r250945.
Modified: trunk/Source/WebCore/dom/Position.cpp (251014 => 251015)
--- trunk/Source/WebCore/dom/Position.cpp 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/Source/WebCore/dom/Position.cpp 2019-10-11 19:03:37 UTC (rev 251015)
@@ -657,13 +657,6 @@
return pos.atStartOfNode();
}
-static void ensureLineBoxesIfNeeded(RenderObject& renderer)
-{
- if (!is<RenderText>(renderer) && !is<RenderLineBreak>(renderer))
- return;
- is<RenderText>(renderer) ? downcast<RenderText>(renderer).ensureLineBoxes() : downcast<RenderLineBreak>(renderer).ensureLineBoxes();
-}
-
// This function and downstream() are used for moving back and forth between visually equivalent candidates.
// For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
// that map to the VisiblePosition between 'b' and the space. This function will return the left candidate
@@ -710,9 +703,6 @@
if (!renderer || renderer->style().visibility() != Visibility::Visible)
continue;
- // FIXME: The code below doesn't need line boxes.
- ensureLineBoxesIfNeeded(*renderer);
-
if (rule == CanCrossEditingBoundary && boundaryCrossed) {
lastVisible = currentPosition;
break;
@@ -825,9 +815,6 @@
if (!renderer || renderer->style().visibility() != Visibility::Visible)
continue;
- // FIXME: The code below doesn't need line boxes.
- ensureLineBoxesIfNeeded(*renderer);
-
if (rule == CanCrossEditingBoundary && boundaryCrossed) {
lastVisible = currentPosition;
break;
Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.cpp (251014 => 251015)
--- trunk/Source/WebCore/rendering/SimpleLineLayout.cpp 2019-10-11 18:47:34 UTC (rev 251014)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.cpp 2019-10-11 19:03:37 UTC (rev 251015)
@@ -355,30 +355,6 @@
return canUseForWithReason(flow, IncludeReasons::First) == NoReason;
}
-static float computeLineLeft(TextAlignMode textAlign, float availableWidth, float committedWidth, float logicalLeftOffset)
-{
- float remainingWidth = availableWidth - committedWidth;
- float left = logicalLeftOffset;
- switch (textAlign) {
- case TextAlignMode::Left:
- case TextAlignMode::WebKitLeft:
- case TextAlignMode::Start:
- return left;
- case TextAlignMode::Right:
- case TextAlignMode::WebKitRight:
- case TextAlignMode::End:
- return left + std::max<float>(remainingWidth, 0);
- case TextAlignMode::Center:
- case TextAlignMode::WebKitCenter:
- return left + std::max<float>(remainingWidth / 2, 0);
- case TextAlignMode::Justify:
- ASSERT_NOT_REACHED();
- break;
- }
- ASSERT_NOT_REACHED();
- return 0;
-}
-
static void revertAllRunsOnCurrentLine(Layout::RunVector& runs)
{
while (!runs.isEmpty() && !runs.last().isEndOfLine)
@@ -491,10 +467,10 @@
// This fragment is collapsed completely. No run is needed.
return;
}
- if (m_lastFragment.isLastInRenderer() || m_lastFragment.isCollapsed())
+ Run& lastRun = runs.last();
+ if (m_lastFragment.isLastInRenderer() || m_lastFragment.isCollapsed() || fragment.isLineBreak() || lastRun.isLineBreak)
runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false, fragment.hasHyphen(), fragment.isLineBreak()));
else {
- Run& lastRun = runs.last();
lastRun.end = endPosition;
lastRun.logicalRight += fragment.width();
ASSERT(!lastRun.hasHyphen);
@@ -534,7 +510,7 @@
void removeTrailingWhitespace(Layout::RunVector& runs)
{
- if (m_lastFragment.type() != TextFragmentIterator::TextFragment::Whitespace)
+ if (!hasTrailingWhitespace())
return;
if (m_lastNonWhitespaceFragment) {
auto needsReverting = m_lastNonWhitespaceFragment->end() != m_lastFragment.end();
@@ -556,6 +532,8 @@
m_lastFragment = TextFragmentIterator::TextFragment();
}
+ float trailingWhitespaceWidth() const { return m_trailingWhitespaceWidth; }
+
private:
bool expansionOpportunity(TextFragmentIterator::TextFragment::Type currentFragmentType, TextFragmentIterator::TextFragment::Type previousFragmentType) const
{
@@ -581,24 +559,37 @@
Optional<Vector<TextFragmentIterator::TextFragment, 30>> m_fragments;
};
-static bool preWrap(const TextFragmentIterator::Style& style)
+static float computeLineLeft(const LineState& line, TextAlignMode textAlign, float& hangingWhitespaceWidth)
{
- return style.wrapLines && !style.collapseWhitespace;
+ float totalWidth = line.width() - hangingWhitespaceWidth;
+ float remainingWidth = line.availableWidth() - totalWidth;
+ float left = line.logicalLeftOffset();
+ switch (textAlign) {
+ case TextAlignMode::Left:
+ case TextAlignMode::WebKitLeft:
+ case TextAlignMode::Start:
+ hangingWhitespaceWidth = std::max(0.f, std::min(hangingWhitespaceWidth, remainingWidth));
+ return left;
+ case TextAlignMode::Right:
+ case TextAlignMode::WebKitRight:
+ case TextAlignMode::End:
+ hangingWhitespaceWidth = 0;
+ return left + std::max<float>(remainingWidth, 0);
+ case TextAlignMode::Center:
+ case TextAlignMode::WebKitCenter:
+ hangingWhitespaceWidth = std::max(0.f, std::min(hangingWhitespaceWidth, (remainingWidth + 1) / 2));
+ return left + std::max<float>(remainingWidth / 2, 0);
+ case TextAlignMode::Justify:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ return 0;
}
-
-static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& runs, const TextFragmentIterator& textFragmentIterator)
+
+static bool preWrap(const TextFragmentIterator::Style& style)
{
- if (!lineState.hasTrailingWhitespace())
- return;
- // Remove collapsed whitespace, or non-collapsed pre-wrap whitespace, unless it's the only content on the line -so removing the whitesapce
- // would produce an empty line.
- const auto& style = textFragmentIterator.style();
- bool collapseWhitespace = style.collapseWhitespace || (!style.breakSpaces && preWrap(style));
- if (!collapseWhitespace)
- return;
- if (preWrap(style) && lineState.isWhitespaceOnly())
- return;
- lineState.removeTrailingWhitespace(runs);
+ return style.wrapLines && !style.collapseWhitespace && !style.breakSpaces;
}
static void updateLineConstrains(const RenderBlockFlow& flow, LineState& line, const LineState& previousLine, unsigned& numberOfPrecedingLinesWithHyphen, const TextFragmentIterator::Style& style, bool isFirstLine)
@@ -758,11 +749,10 @@
}
// Special overflow pre-wrap whitespace handling: skip the overflowed whitespace (even when style says not-collapsible)
// if we manage to fit at least one character on the previous line.
- auto preWrapIsOn = preWrap(style);
- if ((style.collapseWhitespace || preWrapIsOn) && previousLine.firstCharacterFits()) {
+ if ((style.collapseWhitespace || style.wrapLines) && previousLine.firstCharacterFits()) {
// If skipping the whitespace puts us on a newline, skip the newline too as we already wrapped the line.
auto firstFragmentCandidate = consumeLineBreakIfNeeded(textFragmentIterator.nextTextFragment(), textFragmentIterator, currentLine, runs,
- preWrapIsOn ? PreWrapLineBreakRule::Ignore : PreWrapLineBreakRule::Preserve);
+ preWrap(style) ? PreWrapLineBreakRule::Ignore : PreWrapLineBreakRule::Preserve);
return skipWhitespaceIfNeeded(firstFragmentCandidate, textFragmentIterator);
}
return skipWhitespaceIfNeeded(overflowedFragment, textFragmentIterator);
@@ -799,7 +789,7 @@
// Hard and soft linebreaks.
if (fragment.isLineBreak()) {
// Add the new line fragment only if there's nothing on the line. (otherwise the extra new line character would show up at the end of the content.)
- if (line.isEmpty() || fragment.type() == TextFragmentIterator::TextFragment::HardLineBreak) {
+ if (line.isEmpty() || fragment.type() == TextFragmentIterator::TextFragment::HardLineBreak || preWrap(style)) {
if (style.textAlign == TextAlignMode::Right || style.textAlign == TextAlignMode::WebKitRight)
line.removeTrailingWhitespace(runs);
line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
@@ -826,6 +816,14 @@
textFragmentIterator.revertToEndOfFragment(line.revertToLastCompleteFragment(runs));
break;
}
+ if (preWrap(style)) {
+ line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
+ fragment = textFragmentIterator.nextTextFragment(line.width());
+ if (fragment.isLineBreak())
+ continue;
+ line.setOverflowedFragment(fragment);
+ break;
+ }
// Split the whitespace; left part stays on this line, right is pushed to next line.
line.setOverflowedFragment(splitFragmentToFitLine(fragment, line, textFragmentIterator));
line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
@@ -931,22 +929,38 @@
{
if (!runs.size() || (lastRunIndexOfPreviousLine && runs.size() - 1 == lastRunIndexOfPreviousLine.value()))
return;
- removeTrailingWhitespace(line, runs, textFragmentIterator);
+
+ const auto& style = textFragmentIterator.style();
+
+ if (style.collapseWhitespace)
+ line.removeTrailingWhitespace(runs);
+
if (!runs.size())
return;
+
// Adjust runs' position by taking line's alignment into account.
- const auto& style = textFragmentIterator.style();
auto firstRunIndex = lastRunIndexOfPreviousLine ? lastRunIndexOfPreviousLine.value() + 1 : 0;
auto lineLogicalLeft = line.logicalLeftOffset();
auto textAlign = textAlignForLine(style, lastLineInFlow || (line.lastFragment().isValid() && line.lastFragment().type() == TextFragmentIterator::TextFragment::HardLineBreak));
- if (textAlign == TextAlignMode::Justify)
+
+ // https://www.w3.org/TR/css-text-3/#white-space-phase-2
+ bool shouldHangTrailingWhitespace = style.wrapLines && line.trailingWhitespaceWidth();
+ auto hangingWhitespaceWidth = shouldHangTrailingWhitespace ? line.trailingWhitespaceWidth() : 0;
+
+ if (textAlign == TextAlignMode::Justify) {
justifyRuns(line, runs, firstRunIndex);
- else
- lineLogicalLeft = computeLineLeft(textAlign, line.availableWidth(), line.width(), line.logicalLeftOffset());
+ hangingWhitespaceWidth = 0;
+ } else
+ lineLogicalLeft = computeLineLeft(line, textAlign, hangingWhitespaceWidth);
+
for (auto i = firstRunIndex; i < runs.size(); ++i) {
runs[i].logicalLeft += lineLogicalLeft;
runs[i].logicalRight += lineLogicalLeft;
}
+
+ if (shouldHangTrailingWhitespace && hangingWhitespaceWidth < line.trailingWhitespaceWidth())
+ runs.last().logicalRight = runs.last().logicalRight - (line.trailingWhitespaceWidth() - hangingWhitespaceWidth);
+
runs.last().isEndOfLine = true;
++lineCount;
}