From 23e7dfa57b6e4c8aa26dc74b742e65c31abbe50d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 15 Dec 2015 17:52:09 +0530 Subject: [PATCH 1/5] Relayout text input elements on blur --- components/layout/wrapper.rs | 7 ++++--- components/script/dom/document.rs | 3 +++ components/script/dom/htmlinputelement.rs | 10 ++++++++++ components/script/dom/htmltextareaelement.rs | 11 ++++++++--- components/script/dom/virtualmethods.rs | 8 ++++++++ 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 147fda916e3..f5ae6e23341 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -957,9 +957,10 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> { }; if let Some(area) = this.downcast::() { - let insertion_point = unsafe { area.get_absolute_insertion_point_for_layout() }; - let text = unsafe { area.get_value_for_layout() }; - return Some(CharIndex(search_index(insertion_point, text.char_indices()))); + if let Some(insertion_point) = unsafe { area.get_absolute_insertion_point_for_layout() } { + let text = unsafe { area.get_value_for_layout() }; + return Some(CharIndex(search_index(insertion_point, text.char_indices()))); + } } if let Some(input) = this.downcast::() { let insertion_point_index = unsafe { input.get_insertion_point_index_for_layout() }; diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index f2593121c6c..5bbbc4c1e62 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -72,6 +72,7 @@ use dom::touchevent::TouchEvent; use dom::touchlist::TouchList; use dom::treewalker::TreeWalker; use dom::uievent::UIEvent; +use dom::virtualmethods::{VirtualMethods, vtable_for}; use dom::window::{ReflowReason, Window}; use euclid::point::Point2D; use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks, QuirksMode}; @@ -593,6 +594,8 @@ impl Document { if let Some(ref elem) = self.focused.get() { elem.set_focus_state(false); + let node = vtable_for(&elem.upcast::()); + node.handle_blur(); } self.focused.set(self.possibly_focused.get().r()); diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index c94be647354..198fc302f94 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -208,6 +208,9 @@ impl LayoutHTMLInputElementHelpers for LayoutJS { #[allow(unrooted_must_root)] #[allow(unsafe_code)] unsafe fn get_insertion_point_index_for_layout(self) -> Option { + if !(*self.unsafe_get()).upcast::().get_focus_state() { + return None; + } match (*self.unsafe_get()).input_type.get() { InputType::InputText => { let raw = self.get_value_for_layout(); @@ -716,6 +719,13 @@ impl VirtualMethods for HTMLInputElement { } } } + + fn handle_blur(&self) { + if let Some(s) = self.super_type() { + s.handle_blur(); + } + self.force_relayout(); + } } impl FormControl for HTMLInputElement {} diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index b7d99f037c4..95f1438f6e3 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -45,7 +45,7 @@ pub trait LayoutHTMLTextAreaElementHelpers { #[allow(unsafe_code)] unsafe fn get_value_for_layout(self) -> String; #[allow(unsafe_code)] - unsafe fn get_absolute_insertion_point_for_layout(self) -> usize; + unsafe fn get_absolute_insertion_point_for_layout(self) -> Option; #[allow(unsafe_code)] fn get_cols(self) -> u32; #[allow(unsafe_code)] @@ -61,8 +61,13 @@ impl LayoutHTMLTextAreaElementHelpers for LayoutJS { #[allow(unrooted_must_root)] #[allow(unsafe_code)] - unsafe fn get_absolute_insertion_point_for_layout(self) -> usize { - (*self.unsafe_get()).textinput.borrow_for_layout().get_absolute_insertion_point() + unsafe fn get_absolute_insertion_point_for_layout(self) -> Option { + if (*self.unsafe_get()).upcast::().get_focus_state() { + Some((*self.unsafe_get()).textinput.borrow_for_layout() + .get_absolute_insertion_point()) + } else { + None + } } #[allow(unsafe_code)] diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index 3540fbddf0f..b60c805c444 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -102,6 +102,14 @@ pub trait VirtualMethods { } } + /// Called when a previously focused element is no longer focused. + /// Use this to trigger relayouts + fn handle_blur(&self) { + if let Some(s) = self.super_type() { + s.handle_blur(); + } + } + /// https://dom.spec.whatwg.org/#concept-node-adopt-ext fn adopting_steps(&self, old_doc: &Document) { if let Some(ref s) = self.super_type() { From 46a9c92b700fefac4d9d65e2845c41872ed2c7dd Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 15 Dec 2015 18:13:54 +0530 Subject: [PATCH 2/5] Avoid whitespace collapse for text inputs (fixes #8772) --- components/style/properties.mako.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 2b419180476..72b57a931ef 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -6993,6 +6993,10 @@ pub fn modify_style_for_input_text(style: &mut Arc) { margin_style.margin_right = computed::LengthOrPercentageOrAuto::Length(Au(0)); margin_style.margin_bottom = computed::LengthOrPercentageOrAuto::Length(Au(0)); margin_style.margin_left = computed::LengthOrPercentageOrAuto::Length(Au(0)); + + // whitespace inside text input should not be collapsed + let inherited_text = Arc::make_mut(&mut style.inheritedtext); + inherited_text.white_space = longhands::white_space::computed_value::T::pre; } /// Adjusts the `clip` property so that an inline absolute hypothetical fragment doesn't clip its From 77628df0b2db9a7a5a0d9cb760a796a2998749e3 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 15 Dec 2015 18:21:17 +0530 Subject: [PATCH 3/5] Add frewscxv's regression test for whitespace in --- tests/html/input_whitespace_regression.html | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/html/input_whitespace_regression.html diff --git a/tests/html/input_whitespace_regression.html b/tests/html/input_whitespace_regression.html new file mode 100644 index 00000000000..b66e0a6e62c --- /dev/null +++ b/tests/html/input_whitespace_regression.html @@ -0,0 +1,7 @@ + +Both input elements below should have more than one space between "foo" and "bar": + +
+ + +
\ No newline at end of file From 539ee18cf0e50ba0e2469d6706e9215bb637fc76 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 15 Dec 2015 21:30:21 +0530 Subject: [PATCH 4/5] Add reftest for whitespace in and + + \ No newline at end of file diff --git a/tests/wpt/mozilla/tests/css/input_whitespace_ref.html b/tests/wpt/mozilla/tests/css/input_whitespace_ref.html new file mode 100644 index 00000000000..6be82abad19 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/input_whitespace_ref.html @@ -0,0 +1,20 @@ + + + + + + + + +
+
+
+ + + \ No newline at end of file From f67e2086301e81138d198e427db794e431d5bfc0 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 7 Jan 2016 12:04:27 +0530 Subject: [PATCH 5/5] Remove virtual call and unconditionally dirty node on set_focus_state --- components/script/dom/document.rs | 3 --- components/script/dom/element.rs | 4 +++- components/script/dom/htmlinputelement.rs | 7 ------- components/script/dom/virtualmethods.rs | 8 -------- 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 5bbbc4c1e62..f2593121c6c 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -72,7 +72,6 @@ use dom::touchevent::TouchEvent; use dom::touchlist::TouchList; use dom::treewalker::TreeWalker; use dom::uievent::UIEvent; -use dom::virtualmethods::{VirtualMethods, vtable_for}; use dom::window::{ReflowReason, Window}; use euclid::point::Point2D; use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks, QuirksMode}; @@ -594,8 +593,6 @@ impl Document { if let Some(ref elem) = self.focused.get() { elem.set_focus_state(false); - let node = vtable_for(&elem.upcast::()); - node.handle_blur(); } self.focused.set(self.possibly_focused.get().r()); diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index ed901d5cdf8..848e2e2aa69 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -1903,7 +1903,9 @@ impl Element { } pub fn set_focus_state(&self, value: bool) { - self.set_state(IN_FOCUS_STATE, value) + self.set_state(IN_FOCUS_STATE, value); + let doc = document_from_node(self); + doc.content_changed(self.upcast(), NodeDamage::OtherNodeDamage); } pub fn get_hover_state(&self) -> bool { diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 198fc302f94..b7be50f2f73 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -719,13 +719,6 @@ impl VirtualMethods for HTMLInputElement { } } } - - fn handle_blur(&self) { - if let Some(s) = self.super_type() { - s.handle_blur(); - } - self.force_relayout(); - } } impl FormControl for HTMLInputElement {} diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index b60c805c444..3540fbddf0f 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -102,14 +102,6 @@ pub trait VirtualMethods { } } - /// Called when a previously focused element is no longer focused. - /// Use this to trigger relayouts - fn handle_blur(&self) { - if let Some(s) = self.super_type() { - s.handle_blur(); - } - } - /// https://dom.spec.whatwg.org/#concept-node-adopt-ext fn adopting_steps(&self, old_doc: &Document) { if let Some(ref s) = self.super_type() {