Commit 12d7f5b1 authored by Javier Fernández García-Boente's avatar Javier Fernández García-Boente Committed by Commit Bot

Reland "New TextBreakIterator's default behavior breaks after space run"

This is a reland of 1cb4c9a7

Rebaselined a few tests for mac 10.14 and 10.15.

Original change's description:
> New TextBreakIterator's default behavior breaks after space run
>
> Before this change, we were considering breaking opportunities before
> space runs. This approach allowed us to avoid re-shaping in many cases,
> which has an important advantage in terms of performance.
>
> However, the Unicode spec (UAX#14) state that breaking before a space
> character is not allowed [1], so we had to implement this logic after
> our TextBreakIterator had already determined the best breaking
> opportunity. This approach has been working fine so far for regular
> spaces (white-space, tabs, ...), but it doesn't work correctly for
> other BA [2] class characters; in the CSS Text specification, these are
> known as "other space separators" [3].
>
> In order to implement the correct behavior for any kind of space, we
> would need to change our TextBreakIterator implementation so that
> matches the Unicode rules, considering breaking opportunity after
> space runs. This change should also consider the performance impact
> of the extra re-shaping operations required to deal with trailing
> spaces.
>
> In order to prevent performance regressions, we'll store the position
> of the 'end of non-hangable run', which will be used in case of items
> with styles dictating rules to collapse trailing spaces.
>
> [1] https://unicode-org.atlassian.net/browse/ICU-20843
> [2] https://www.unicode.org/reports/tr14/tr14-39.html#BA
> [3] https://drafts.csswg.org/css-text-3/#other-space-separators
>
> Change-Id: Ie4a3890c75a3faff1a0155d4a40bcaa85bc6ac06
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2047943
> Commit-Queue: Javier Fernandez <jfernandez@igalia.com>
> Reviewed-by: Koji Ishii <kojii@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#806928}

Change-Id: I9b5204f0b2e49367ab7d7a2107900763844fd2bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2412307
Commit-Queue: Javier Fernandez <jfernandez@igalia.com>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807457}
parent 807acabd
......@@ -53,6 +53,9 @@ struct CORE_EXPORT NGInlineItemResult {
// The range of text content for this item.
NGTextOffset text_offset;
// Indicates the limits of the trailing space run.
base::Optional<unsigned> non_hangable_run_end;
// Inline size of this item.
LayoutUnit inline_size;
......
......@@ -198,7 +198,7 @@ NGLineBreaker::NGLineBreaker(NGInlineNode node,
handled_leading_floats_index_(handled_leading_floats_index),
base_direction_(node_.BaseDirection()) {
available_width_ = ComputeAvailableWidth();
break_iterator_.SetBreakSpace(BreakSpaceType::kBeforeSpaceRun);
break_iterator_.SetBreakSpace(BreakSpaceType::kAfterSpaceRun);
if (!break_token)
return;
......@@ -622,6 +622,17 @@ void NGLineBreaker::HandleText(const NGInlineItem& item,
return;
}
// Hanging trailing spaces may resolve the overflow.
if (item_result->has_only_trailing_spaces) {
if (item_result->item->Style()->WhiteSpace() == EWhiteSpace::kPreWrap &&
IsBreakableSpace(Text()[item_result->EndOffset() - 1])) {
unsigned end_index = item_result - line_info->Results().begin();
Rewind(end_index, line_info);
}
state_ = LineBreakState::kTrailing;
return;
}
// If this is all trailable spaces, this item is trailable, and next item
// maybe too. Don't go to |HandleOverflow()| yet.
if (IsAllBreakableSpaces(Text(), item_result->StartOffset(),
......@@ -760,6 +771,8 @@ NGLineBreaker::BreakResult NGLineBreaker::BreakText(
item_result->inline_size = inline_size;
item_result->text_offset.end = result.break_offset;
item_result->text_offset.AssertNotEmpty();
item_result->non_hangable_run_end = result.non_hangable_run_end;
item_result->has_only_trailing_spaces = result.has_trailing_spaces;
item_result->shape_result = std::move(shape_result);
break;
}
......@@ -884,20 +897,31 @@ bool NGLineBreaker::HandleTextForFastMinContent(NGInlineItemResult* item_result,
if (end_offset >= item.EndOffset())
break;
unsigned non_hangable_run_end = end_offset;
if (item.Style()->WhiteSpace() != EWhiteSpace::kBreakSpaces) {
while (non_hangable_run_end > item.StartOffset() &&
IsBreakableSpace(text[non_hangable_run_end - 1])) {
--non_hangable_run_end;
}
}
// Inserting a hyphenation character is not supported yet.
if (text[end_offset - 1] == kSoftHyphenCharacter)
// TODO (jfernandez): Maybe we need to use 'end_offset' here ?
if (text[non_hangable_run_end - 1] == kSoftHyphenCharacter)
return false;
float start_position = shape_result.CachedPositionForOffset(
start_offset - shape_result.StartIndex());
float end_position = shape_result.CachedPositionForOffset(
end_offset - shape_result.StartIndex());
non_hangable_run_end - shape_result.StartIndex());
float word_width = IsLtr(shape_result.Direction())
? end_position - start_position
: start_position - end_position;
min_width = std::max(word_width, min_width);
last_end_offset = end_offset;
last_end_offset = non_hangable_run_end;
// TODO (jfernandez): I think that having the non_hangable_run_end
// would make this loop unnecessary/redudant.
start_offset = end_offset;
while (start_offset < item.EndOffset() &&
IsBreakableSpace(text[start_offset])) {
......@@ -914,7 +938,8 @@ bool NGLineBreaker::HandleTextForFastMinContent(NGInlineItemResult* item_result,
return false;
// Create an NGInlineItemResult that has the max of widths of all words.
item_result->text_offset.end = last_end_offset;
item_result->text_offset.end =
std::max(last_end_offset, item_result->text_offset.start + 1);
item_result->text_offset.AssertNotEmpty();
item_result->inline_size = LayoutUnit::FromFloatCeil(min_width);
item_result->can_break_after = true;
......@@ -1026,6 +1051,9 @@ void NGLineBreaker::HandleTrailingSpaces(const NGInlineItem& item,
(item.Type() == NGInlineItem::kControl &&
Text()[item.StartOffset()] == kTabulationCharacter));
DCHECK(&shape_result);
bool is_control_tab = item.Type() == NGInlineItem::kControl &&
Text()[item.StartOffset()] == kTabulationCharacter;
DCHECK(item.Type() == NGInlineItem::kText || is_control_tab);
DCHECK_GE(offset_, item.StartOffset());
DCHECK_LT(offset_, item.EndOffset());
const String& text = Text();
......@@ -1039,6 +1067,8 @@ void NGLineBreaker::HandleTrailingSpaces(const NGInlineItem& item,
if (style.CollapseWhiteSpace()) {
if (text[offset_] != kSpaceCharacter) {
if (offset_ > 0 && IsBreakableSpace(text[offset_ - 1]))
trailing_whitespace_ = WhitespaceState::kCollapsible;
state_ = LineBreakState::kDone;
return;
}
......@@ -1060,18 +1090,29 @@ void NGLineBreaker::HandleTrailingSpaces(const NGInlineItem& item,
while (end < item.EndOffset() && IsBreakableSpace(text[end]))
end++;
if (end == offset_) {
if (IsBreakableSpace(text[end - 1]))
trailing_whitespace_ = WhitespaceState::kPreserved;
state_ = LineBreakState::kDone;
return;
}
// TODO (jfernandez): Could we just modify the last ItemResult
// instead of creating a new one ?
// Probably we can (koji). We would need to review usage of these
// item results, and change them to use "non_hangable_run_end"
// instead.
NGInlineItemResult* item_result = AddItem(item, end, line_info);
item_result->non_hangable_run_end = offset_;
item_result->has_only_trailing_spaces = true;
item_result->shape_result = ShapeResultView::Create(&shape_result);
if (item_result->StartOffset() == item.StartOffset() &&
item_result->EndOffset() == item.EndOffset())
item_result->inline_size = item_result->shape_result->SnappedWidth();
else
item_result->EndOffset() == item.EndOffset()) {
item_result->inline_size = item_result->shape_result
? item_result->shape_result->SnappedWidth()
: LayoutUnit();
} else {
UpdateShapeResult(*line_info, item_result);
}
position_ += item_result->inline_size;
item_result->can_break_after =
end < text.length() && !IsBreakableSpace(text[end]);
......@@ -1662,7 +1703,8 @@ void NGLineBreaker::HandleOpenTag(const NGInlineItem& item,
DCHECK(!item_result->can_break_after);
const NGInlineItemResults& item_results = line_info->Results();
if (UNLIKELY(!was_auto_wrap && auto_wrap_ && item_results.size() >= 2)) {
ComputeCanBreakAfter(std::prev(item_result), auto_wrap_, break_iterator_);
if (IsPreviousItemOfType(NGInlineItem::kText))
ComputeCanBreakAfter(std::prev(item_result), auto_wrap_, break_iterator_);
}
}
......@@ -1691,29 +1733,15 @@ void NGLineBreaker::HandleCloseTag(const NGInlineItem& item,
if (item_results.size() >= 2) {
NGInlineItemResult* last = std::prev(item_result);
if (was_auto_wrap || last->can_break_after) {
item_result->can_break_after = last->can_break_after;
item_result->can_break_after =
last->can_break_after ||
IsBreakableSpace(Text()[item_result->EndOffset()]);
last->can_break_after = false;
return;
}
if (auto_wrap_ && !IsBreakableSpace(Text()[item_result->EndOffset() - 1]))
ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_);
}
if (was_auto_wrap)
return;
DCHECK(!item_result->can_break_after);
if (!auto_wrap_)
return;
// When auto-wrap follows no-wrap, the boundary is determined by the break
// iterator. However, when space characters follow the boundary, the break
// iterator cannot compute this because it considers break opportunities are
// before a run of spaces.
const String& text = Text();
if (item_result->EndOffset() < text.length() &&
IsBreakableSpace(text[item_result->EndOffset()])) {
item_result->can_break_after = true;
return;
}
ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_);
}
// Handles when the last item overflows.
......@@ -2149,6 +2177,10 @@ void NGLineBreaker::SetCurrentStyle(const ComputedStyle& style) {
spacing_.SetSpacing(style.GetFont());
}
bool NGLineBreaker::IsPreviousItemOfType(NGInlineItem::NGInlineItemType type) {
return item_index_ > 0 ? Items().at(item_index_ - 1).Type() == type : false;
}
void NGLineBreaker::MoveToNextOf(const NGInlineItem& item) {
offset_ = item.EndOffset();
item_index_++;
......
......@@ -194,6 +194,7 @@ class CORE_EXPORT NGLineBreaker {
NGLineInfo*) const;
void SetCurrentStyle(const ComputedStyle&);
bool IsPreviousItemOfType(NGInlineItem::NGInlineItemType);
void MoveToNextOf(const NGInlineItem&);
void MoveToNextOf(const NGInlineItemResult&);
......
......@@ -53,9 +53,15 @@ class PLATFORM_EXPORT ShapingLineBreaker final {
STACK_ALLOCATED();
public:
// Indicates the limits of the space run.
base::Optional<unsigned> non_hangable_run_end;
// Indicates the resulting break offset.
unsigned break_offset;
// Indicates that the shape result contains trailing spaces
bool has_trailing_spaces;
// True if there were no break opportunities that can fit. When this is
// false, the result width should be smaller than or equal to the available
// space.
......@@ -107,7 +113,17 @@ class PLATFORM_EXPORT ShapingLineBreaker final {
STACK_ALLOCATED();
public:
BreakOpportunity(unsigned new_offset, bool hyphenated)
: offset(new_offset),
non_hangable_run_end(new_offset),
is_hyphenated(hyphenated) {}
BreakOpportunity(unsigned new_offset, unsigned run_end, bool hyphenated)
: offset(new_offset),
non_hangable_run_end(run_end),
is_hyphenated(hyphenated) {}
unsigned offset;
unsigned non_hangable_run_end;
bool is_hyphenated;
};
BreakOpportunity PreviousBreakOpportunity(unsigned offset,
......
......@@ -334,6 +334,12 @@ inline int LazyLineBreakIterator::NextBreakablePosition(
continue;
}
break;
case BreakSpaceType::kAfterSpaceRun:
if (is_space)
continue;
if (is_last_space)
return i;
break;
case BreakSpaceType::kAfterEverySpace:
if (is_last_space)
return i;
......@@ -398,6 +404,10 @@ inline int LazyLineBreakIterator::NextBreakablePosition(
return NextBreakablePosition<CharacterType, lineBreakType,
BreakSpaceType::kBeforeSpaceRun>(pos, str,
len);
case BreakSpaceType::kAfterSpaceRun:
return NextBreakablePosition<CharacterType, lineBreakType,
BreakSpaceType::kAfterSpaceRun>(pos, str,
len);
case BreakSpaceType::kAfterEverySpace:
return NextBreakablePosition<CharacterType, lineBreakType,
BreakSpaceType::kAfterEverySpace>(pos, str,
......@@ -516,6 +526,8 @@ std::ostream& operator<<(std::ostream& ostream, BreakSpaceType break_space) {
return ostream << "kAfterEverySpace";
case BreakSpaceType::kBeforeSpaceRun:
return ostream << "kBeforeSpaceRun";
case BreakSpaceType::kAfterSpaceRun:
return ostream << "kAfterSpaceRun";
}
NOTREACHED();
return ostream << "BreakSpaceType::" << static_cast<int>(break_space);
......
......@@ -111,6 +111,11 @@ enum class BreakSpaceType {
// LayoutNG line breaker uses this type.
kBeforeSpaceRun,
// Break after a run of white space characters.
// This mode enables the LazyLineBreakIterator to completely rely on
// ICU for determining the breaking opportunities.
kAfterSpaceRun,
// white-spaces:break-spaces allows breaking after any preserved white-space,
// even when these are leading spaces so that we can avoid breaking
// the word in case of overflow.
......
......@@ -208,6 +208,9 @@ crbug.com/591099 external/wpt/css/css-text/text-transform/text-transform-shaping
crbug.com/591099 external/wpt/css/css-text/white-space/control-chars-00C.html [ Failure ]
crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-001.html [ Failure ]
crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-002.html [ Failure ]
crbug.com/591099 external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-012.html [ Failure ]
crbug.com/591099 external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-013.html [ Failure ]
crbug.com/591099 external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-014.html [ Failure ]
### external/wpt/css/css-text/word-break/
crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Failure ]
......@@ -342,6 +345,9 @@ crbug.com/1012289 external/wpt/css/css-lists/list-style-type-string-005a.html [
crbug.com/1012289 external/wpt/css/css-lists/list-style-type-string-006.html [ Failure ]
crbug.com/1012294 external/wpt/css/css-lists/list-style-type-string-007.html [ Pass ]
### external/wpt/css/css-content/
crbug.com/591099 external/wpt/css/css-content/quotes-033.html [ Failure ]
### external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/
crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-horiz-002.xhtml [ Failure ]
crbug.com/886592 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-margin-002.html [ Failure ]
......@@ -378,6 +384,7 @@ crbug.com/875235 external/wpt/html/rendering/non-replaced-elements/the-fieldset-
### virtual/text-antialias/
crbug.com/591099 virtual/text-antialias/justify-ideograph-simple.html [ Failure ]
crbug.com/591099 virtual/text-antialias/apply-start-width-after-skipped-text.html [ Failure ]
### http/tests/
crbug.com/591099 http/tests/devtools/elements/highlight/highlight-node-vertical-rl.js [ Failure ]
......
......@@ -884,6 +884,7 @@ crbug.com/591099 fast/multicol/vertical-lr/nested-columns.html [ Failure ]
crbug.com/591099 fast/multicol/vertical-lr/unsplittable-inline-block.html [ Failure ]
crbug.com/591099 [ Win ] virtual/text-antialias/ellipsis-with-self-painting-layer.html [ Failure ]
crbug.com/591099 [ Mac ] fast/multicol/file-upload-as-multicol.html [ Failure ]
crbug.com/1098801 virtual/text-antialias/whitespace/whitespace-in-pre.html [ Failure ]
# LayoutNG failures that needs to be triaged
crbug.com/591099 virtual/text-antialias/selection/selection-rect-line-height-too-small.html [ Failure ]
......
<!doctype html>
<meta charset=utf-8>
<title>CSS test Reference</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
div {
font: 20px/1 Ahem;
white-space: pre;
}
span { background: blue; }
</style>
<p>This test passes if the line is broken after the 2nd white space, which hangs (blue).
<div>XX&#x0020;X<span>&#x0020;<br>X</span></div>
<!doctype html>
<meta charset=utf-8>
<meta http-equiv="content-language" content="en, ja" />
<title>CSS test Reference</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
<style>
div { white-space: pre; }
span { background: blue; }
</style>
<p>This test passes if the line is after the white space, which hangs (blue).
<div>ああ<span>&#x0020;<br>X</span></div>
<!doctype html>
<meta charset=utf-8>
<title>CSS test Reference</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
div {
font: 20px/1 Ahem;
white-space: pre;
}
span { background: blue; }
</style>
<p>This test passes if the line is broken after the 2nd white space, which hangs (blue).
<div>XX&#x0020;<span>X&#x0020;<br>XXXX&#x0020;</span></div>
<!doctype html>
<meta charset=utf-8>
<title>CSS test Reference</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
div {
font: 20px/1 Ahem;
white-space: pre;
}
span { background: blue; }
</style>
<p>This test passes if the line is broken after the 2nd white space, which hangs (blue).
<div>XX&#x0020;X<span>X&#x0020;<br>X</span></div>
<!doctype html>
<meta charset=utf-8>
<title>CSS test Reference</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
div {
font: 20px/1 Ahem;
white-space: pre;
}
span { background: blue; }
</style>
<p>This test passes if the line is broken after the 2nd white space, which hangs (blue).
<div>XX&#x0020;X<span><br>X</span></div>
<!doctype html>
<meta charset=utf-8>
<meta http-equiv="content-language" content="en, ja" />
<title>CSS test Reference</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
<style>
div { white-space: pre; }
span { background: blue; }
</style>
<p>This test passes if the line is after the white space, which hangs (blue).
<div>ああ<span><br>X</span></div>
<!doctype html>
<meta charset=utf-8>
<title>CSS test Reference</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
div {
font: 20px/1 Ahem;
white-space: pre;
}
span { background: blue; }
</style>
<p>This test passes if the line is broken after the 2nd white space, which hangs (blue).
<div>XX&#x0020;<span>X<br>XXXX</span></div>
<!doctype html>
<meta charset=utf-8>
<title>CSS test Reference</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
div {
font: 20px/1 Ahem;
white-space: pre;
}
span { background: blue; }
</style>
<p>This test passes if the line is broken after the 2nd white space, which hangs (blue).
<div>XX&#x0020;X<span>X<br>X</span></div>
......@@ -24,7 +24,5 @@ div {
<section class="ideo">
<div><br></div>
<div><br></div>
<div><br></div>
<div><br></div>
</section>
</body>
<!doctype html>
<meta charset=utf-8>
<title>CSS Text test: hanging trailing spaces with white-space:pre-wrap</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap">
<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
<link rel="help" title="5.2. Breaking Rules for Letters: the word-break property" href="https://drafts.csswg.org/css-text-3/#word-break-property">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-word-break-normal">
<link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-012-ref.html">
<link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-alt-012-ref.html">
<meta name="assert" content="Previous breaking opportunities are not considered if the overflow is caused by hanging trailing spaces.">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
<style>
div {
font: 20px/1 Ahem;
width: 4ch;
white-space: pre-wrap;
}
span { background: blue; } /* If the space is removed instead of hanging, there will be no blue box*/
</style>
<p>This test passes if the line is broken after the 2nd white space, which hangs (blue).
<div>XX X<span> X</span></div>
<!doctype html>
<meta charset=utf-8>
<meta http-equiv="content-language" content="en, ja" />
<title>CSS Text test: hanging trailing spaces with white-space:pre-wrap</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap">
<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
<link rel="help" title="5.2. Breaking Rules for Letters: the word-break property" href="https://drafts.csswg.org/css-text-3/#word-break-property">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-word-break-normal">
<link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-013-ref.html">
<link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-alt-013-ref.html">
<meta name="assert" content="Previous breaking opportunities are not considered if the overflow is caused by hanging trailing spaces.">
<style>
div {
width: 2em;
white-space: pre-wrap;
}
span { background: blue; } /* If the space is removed instead of hanging, there will be no blue box*/
</style>
<p>This test passes if the line is after the white space, which hangs (blue).
<div>ああ<span>&#x0020;X<span></div>
<!doctype html>
<meta charset=utf-8>
<title>CSS Text test: hanging trailing spaces with white-space:pre-wrap</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap">
<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
<link rel="help" title="5.2. Breaking Rules for Letters: the word-break property" href="https://drafts.csswg.org/css-text-3/#word-break-property">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-word-break-normal">
<link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-014-ref.html">
<link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-alt-014-ref.html">
<meta name="assert" content="Previous breaking opportunities are not considered if the overflow is caused by hanging trailing spaces.">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
<style>
div {
font: 20px/1 Ahem;
width: 4ch;
white-space: pre-wrap;
}
span { background: blue; } /* If the space is removed instead of hanging, there will be no blue box */
</style>
<p>This test passes if the line is broken after the 2nd white space, which hangs (blue).
<div>XX <span>X </span>X<span>XXX </span></div>
<!doctype html>
<meta charset=utf-8>
<title>CSS Text test: hanging trailing spaces with white-space:pre-wrap</title>
<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap">
<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
<link rel="help" title="5.2. Breaking Rules for Letters: the word-break property" href="https://drafts.csswg.org/css-text-3/#word-break-property">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-word-break-normal">
<link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-015-ref.html">
<link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-alt-015-ref.html">
<meta name="assert" content="Previous breaking opportunities are not considered if the overflow is caused by hanging trailing spaces.">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
<style>
div {
font: 20px/1 Ahem;
width: 5ch;
white-space: pre-wrap;
}
span { background: blue; } /* If the space is removed instead of hanging, there will be no blue box */
</style>
<p>This test passes if the line is broken after the 2nd white space, which hangs (blue).
<div>XX X<span>X X</span></div>
......@@ -35,7 +35,5 @@ div {
<section class="ideo">
<div><span class="nowrap"></span></div>
<div><span class="nowrap"></span><span class="normal"></span></div>
<div><span class="nowrap"><span class="normal"></span></span></div>
<div class="nowrap"><span class="normal"></span></div>
</section>
</body>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment