From 32aad0838e63728f7dbe485d5b8858d4991a1dde Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 1 Apr 2016 20:18:28 -0700 Subject: [PATCH] Draw insertion point even for empty input fields This allows text layout to generate an empty text fragment if the fragment contains the insertion point for a text input box. --- components/layout/display_list_builder.rs | 19 ++++++++++++------- components/layout/fragment.rs | 3 +++ components/layout/text.rs | 12 ++++++++---- .../mozilla/tests/css/focus_selector_ref.html | 3 +++ 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 0c04c839450..8832eac31bc 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -1014,13 +1014,9 @@ impl FragmentDisplayListBuilding for Fragment { // display list items. let mut clip = (*clip).clone(); self.adjust_clip_for_style(&mut clip, &stacking_relative_border_box); - if !clip.might_intersect_rect(&stacking_relative_border_box) { - return; - } + let empty_rect = !clip.might_intersect_rect(&stacking_relative_border_box); - debug!("Fragment::build_display_list: intersected. Adding display item..."); - - if self.is_primary_fragment() { + if self.is_primary_fragment() && !empty_rect { // Add shadows, background, borders, and outlines, if applicable. if let Some(ref inline_context) = self.inline_context { for node in inline_context.nodes.iter().rev() { @@ -1080,14 +1076,23 @@ impl FragmentDisplayListBuilding for Fragment { &stacking_relative_border_box, &clip); } + } - // Paint the selection point if necessary. + if self.is_primary_fragment() { + // Paint the selection point if necessary. Even an empty text fragment may have an + // insertion point, so we do this even if `empty_rect` is true. self.build_display_items_for_selection_if_necessary(state, &stacking_relative_border_box, display_list_section, &clip); } + if empty_rect { + return; + } + + debug!("Fragment::build_display_list: intersected. Adding display item..."); + // Create special per-fragment-type display items. self.build_fragment_type_specific_display_items(state, &stacking_relative_border_box, diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index bb761603f2f..42fe28d29e9 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -1709,6 +1709,9 @@ impl Fragment { if other_info.requires_line_break_afterward_if_wrapping_on_newlines() { this_info.flags.insert(REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES); } + if other_info.insertion_point.is_some() { + this_info.insertion_point = other_info.insertion_point; + } self.border_padding.inline_end = next_fragment.border_padding.inline_end; } _ => panic!("Can only merge two scanned-text fragments!"), diff --git a/components/layout/text.rs b/components/layout/text.rs index 731891e68b3..99fd9ca8a4f 100644 --- a/components/layout/text.rs +++ b/components/layout/text.rs @@ -239,6 +239,7 @@ impl TextRunScanner { mapping.flush(&mut mappings, &mut run_info, &**text, + insertion_point, compression, text_transform, &mut last_whitespace, @@ -268,6 +269,7 @@ impl TextRunScanner { mapping.flush(&mut mappings, &mut run_info, &**text, + insertion_point, compression, text_transform, &mut last_whitespace, @@ -336,6 +338,7 @@ impl TextRunScanner { let scanned_run = runs[mapping.text_run_index].clone(); let requires_line_break_afterward_if_wrapping_on_newlines = + !mapping.byte_range.is_empty() && scanned_run.run.text.char_at_reverse(mapping.byte_range.end()) == '\n'; if requires_line_break_afterward_if_wrapping_on_newlines { mapping.char_range.extend_by(CharIndex(-1)); @@ -575,12 +578,13 @@ impl RunMapping { mappings: &mut Vec, run_info: &mut RunInfo, text: &str, + insertion_point: Option, compression: CompressionMode, text_transform: text_transform::T, last_whitespace: &mut bool, start_position: &mut usize, end_position: usize) { - if *start_position == end_position { + if *start_position == end_position && insertion_point.is_none() { return; } let old_byte_length = run_info.text.len(); @@ -601,9 +605,9 @@ impl RunMapping { run_info.character_length = run_info.character_length + character_count; *start_position = end_position; - // Don't flush empty mappings. - if character_count == 0 { - return + // Don't flush mappings that contain no characters and no insertion_point. + if character_count == 0 && !self.contains_insertion_point(insertion_point) { + return; } let new_byte_length = run_info.text.len(); diff --git a/tests/wpt/mozilla/tests/css/focus_selector_ref.html b/tests/wpt/mozilla/tests/css/focus_selector_ref.html index 8f91987a976..6ea1f341313 100644 --- a/tests/wpt/mozilla/tests/css/focus_selector_ref.html +++ b/tests/wpt/mozilla/tests/css/focus_selector_ref.html @@ -11,5 +11,8 @@ +