Extend character-based soft wrap prevention to before atomics (#30800)

The changes in #30740, fixed an issue where certain characters should
prevent line break opportunity after atomics. This change extends that
to also apply to before atomics, which is what the specification says
should happen.
This commit is contained in:
Martin Robinson 2023-12-01 10:26:49 +01:00 committed by GitHub
parent b125bb6b6a
commit cdbd60fe53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 41 additions and 38 deletions

View file

@ -375,6 +375,12 @@ struct InlineFormattingContextState<'a, 'b> {
/// is encountered. /// is encountered.
have_deferred_soft_wrap_opportunity: bool, have_deferred_soft_wrap_opportunity: bool,
/// Whether or not a soft wrap opportunity should be prevented before the next atomic
/// element encountered in the inline formatting context. See
/// `char_prevents_soft_wrap_opportunity_when_before_or_after_atomic` for more
/// details.
prevent_soft_wrap_opportunity_before_next_atomic: bool,
/// The currently white-space setting of this line. This is stored on the /// The currently white-space setting of this line. This is stored on the
/// [`InlineFormattingContextState`] because when a soft wrap opportunity is defined /// [`InlineFormattingContextState`] because when a soft wrap opportunity is defined
/// by the boundary between two characters, the white-space property of their nearest /// by the boundary between two characters, the white-space property of their nearest
@ -1260,6 +1266,7 @@ impl InlineFormattingContext {
white_space: containing_block.style.get_inherited_text().white_space, white_space: containing_block.style.get_inherited_text().white_space,
linebreaker: None, linebreaker: None,
have_deferred_soft_wrap_opportunity: false, have_deferred_soft_wrap_opportunity: false,
prevent_soft_wrap_opportunity_before_next_atomic: false,
root_nesting_level: InlineContainerState { root_nesting_level: InlineContainerState {
nested_block_size: line_height_from_style(layout_context, &containing_block.style), nested_block_size: line_height_from_style(layout_context, &containing_block.style),
has_content: false, has_content: false,
@ -1541,7 +1548,11 @@ impl IndependentFormattingContext {
}, },
}; };
if ifc.white_space.allow_wrap() { let soft_wrap_opportunity_prevented = mem::replace(
&mut ifc.prevent_soft_wrap_opportunity_before_next_atomic,
false,
);
if ifc.white_space.allow_wrap() && !soft_wrap_opportunity_prevented {
ifc.process_soft_wrap_opportunity(); ifc.process_soft_wrap_opportunity();
} }
@ -1683,25 +1694,20 @@ impl TextRun {
mem::replace(&mut ifc.have_deferred_soft_wrap_opportunity, false); mem::replace(&mut ifc.have_deferred_soft_wrap_opportunity, false);
let mut break_at_start = break_at_start || have_deferred_soft_wrap_opportunity; let mut break_at_start = break_at_start || have_deferred_soft_wrap_opportunity;
// From https://www.w3.org/TR/css-text-3/#line-break-details:
//
// > For Web-compatibility there is a soft wrap opportunity before and after each
// > replaced element or other atomic inline, even when adjacent to a character that
// > would normally suppress them, including U+00A0 NO-BREAK SPACE. However, with
// > the exception of U+00A0 NO-BREAK SPACE, there must be no soft wrap opportunity
// > between atomic inlines and adjacent characters belonging to the Unicode GL, WJ,
// > or ZWJ line breaking classes.
if have_deferred_soft_wrap_opportunity { if have_deferred_soft_wrap_opportunity {
if let Some(first_character) = self.text.chars().nth(0) { if let Some(first_character) = self.text.chars().nth(0) {
let class = linebreak_property(first_character);
break_at_start = break_at_start && break_at_start = break_at_start &&
(first_character == '\u{00A0}' || !char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(
(class != XI_LINE_BREAKING_CLASS_GL && first_character,
class != XI_LINE_BREAKING_CLASS_WJ && )
class != XI_LINE_BREAKING_CLASS_ZWJ));
} }
} }
if let Some(last_character) = self.text.chars().last() {
ifc.prevent_soft_wrap_opportunity_before_next_atomic =
char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(last_character);
}
for (run_index, run) in runs.into_iter().enumerate() { for (run_index, run) in runs.into_iter().enumerate() {
ifc.possibly_flush_deferred_forced_line_break(); ifc.possibly_flush_deferred_forced_line_break();
@ -2286,3 +2292,24 @@ impl FloatLineItem {
self.fragment self.fragment
} }
} }
/// Whether or not this character prevents a soft line wrap opportunity when it
/// comes before or after an atomic inline element.
///
/// From https://www.w3.org/TR/css-text-3/#line-break-details:
///
/// > For Web-compatibility there is a soft wrap opportunity before and after each
/// > replaced element or other atomic inline, even when adjacent to a character that
/// > would normally suppress them, including U+00A0 NO-BREAK SPACE. However, with
/// > the exception of U+00A0 NO-BREAK SPACE, there must be no soft wrap opportunity
/// > between atomic inlines and adjacent characters belonging to the Unicode GL, WJ,
/// > or ZWJ line breaking classes.
fn char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character: char) -> bool {
if character == '\u{00A0}' {
return false;
}
let class = linebreak_property(character);
class == XI_LINE_BREAKING_CLASS_GL ||
class == XI_LINE_BREAKING_CLASS_WJ ||
class == XI_LINE_BREAKING_CLASS_ZWJ
}

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-003.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-006.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-013.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-014.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-016.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-018.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-020.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-022.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-024.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-atomic-026.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-replaced-002.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[line-breaking-replaced-003.html]
expected: FAIL