From ef49f2e0eb28f3eb6445eff3aa095edc4b8a64d8 Mon Sep 17 00:00:00 2001 From: Dmitry Kolupaev Date: Tue, 28 Jan 2020 10:34:10 +0300 Subject: [PATCH] Implement dirname for form submit and directionality for element --- Cargo.lock | 6 +- components/constellation/constellation.rs | 2 +- components/embedder_traits/lib.rs | 2 +- components/script/Cargo.toml | 1 + components/script/dom/element.rs | 64 +++++++++++++++++++ components/script/dom/htmlelement.rs | 5 ++ components/script/dom/htmlformelement.rs | 18 +++++- components/script/dom/htmlinputelement.rs | 36 +++++++++++ components/script/dom/htmltextareaelement.rs | 9 +++ .../script/dom/webidls/HTMLElement.webidl | 4 +- components/script/dom/window.rs | 1 + .../dirname-ltr.html.ini | 5 -- .../dirname-ltr.html | 12 ++-- .../dirname-rtl.html | 32 ++++++++++ 14 files changed, 178 insertions(+), 19 deletions(-) delete mode 100644 tests/wpt/metadata/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html.ini create mode 100644 tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl.html diff --git a/Cargo.lock b/Cargo.lock index 0aebb0c0e24b..07524b670c20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4783,6 +4783,7 @@ dependencies = [ "tendril", "time", "tinyfiledialogs", + "unicode-bidi", "unicode-segmentation", "url", "utf-8", @@ -6291,13 +6292,12 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" dependencies = [ "matches", "serde", - "serde_derive", ] [[package]] diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 0df1a28c15c0..629921035f0f 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1614,7 +1614,7 @@ where Some(ctx) => ctx.pipeline_id, None => { return warn!( - "LoadUrl for unknow browsing context: {:?}", + "LoadUrl for unknown browsing context: {:?}", top_level_browsing_context_id ); }, diff --git a/components/embedder_traits/lib.rs b/components/embedder_traits/lib.rs index 246ef63f2504..c13ad617920e 100644 --- a/components/embedder_traits/lib.rs +++ b/components/embedder_traits/lib.rs @@ -149,7 +149,7 @@ pub enum EmbedderMsg { ResizeTo(DeviceIntSize), /// Show dialog to user Prompt(PromptDefinition, PromptOrigin), - /// Wether or not to allow a pipeline to load a url. + /// Whether or not to allow a pipeline to load a url. AllowNavigationRequest(PipelineId, ServoUrl), /// Whether or not to allow script to open a new tab/browser AllowOpeningBrowser(IpcSender), diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 93813953aace..03eac6cae656 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -110,6 +110,7 @@ style_traits = {path = "../style_traits"} swapper = "0.1" tendril = {version = "0.4.1", features = ["encoding_rs"]} time = "0.1.12" +unicode-bidi = "0.3.4" unicode-segmentation = "1.1.0" url = "2.0" utf-8 = "0.7" diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index eecff289cdb0..bb51ee432fd4 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -12,6 +12,7 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use crate::dom::bindings::codegen::Bindings::ElementBinding; use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function; +use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementBinding::HTMLElementMethods; use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods; @@ -540,6 +541,69 @@ impl Element { } true // whatwg/html#5239 } + + /// https://html.spec.whatwg.org/#the-directionality + pub fn directionality(&self) -> String { + if self.is::() { + let htmlElement = self.downcast::().unwrap(); + self.html_element_directionality(&htmlElement.Dir()) + } else { + let node = self.upcast::(); + self.parent_directionality(node) + } + } + + fn html_element_directionality(&self, element_direction: &str) -> String { + if element_direction == "ltr" { + return "ltr".to_owned(); + } + + if element_direction == "rtl" { + return "rtl".to_owned(); + } + + if self.is::() { + let input = self.downcast::().unwrap(); + return input.directionality(element_direction); + } + + if self.is::() { + let area = self.downcast::().unwrap(); + return area.directionality(element_direction); + } + + // TODO(dmitry.klpv): Implement condition + // If the element's dir attribute is in the auto state OR + // If the element is a bdi element and the dir attribute is not in a defined state + // (i.e. it is not present or has an invalid value) + // Requires bdi element implementation (https://html.spec.whatwg.org/#the-bdi-element) + + let node = self.upcast::(); + self.parent_directionality(node) + } + + fn parent_directionality(&self, node: &Node) -> String { + if !node.has_parent() { + return "ltr".to_owned(); + } + + let parent = node.GetParentNode(); + match parent { + Some(parent) => { + if parent.is::() { + return "ltr".to_owned(); + } + + return if parent.is::() { + let parentHtml = parent.downcast::().unwrap(); + parentHtml.directionality() + } else { + self.parent_directionality(&*parent) + }; + }, + None => "ltr".to_owned(), + } + } } #[allow(unsafe_code)] diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index ac0f99416c26..48401acc3fd8 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -170,6 +170,11 @@ impl HTMLElementMethods for HTMLElement { // https://html.spec.whatwg.org/multipage/#dom-hidden make_bool_setter!(SetHidden, "hidden"); + // https://html.spec.whatwg.org/multipage/dom.html#the-dir-attribute + make_getter!(Dir, "dir"); + // https://html.spec.whatwg.org/multipage/dom.html#the-dir-attribute + make_setter!(SetDir, "dir"); + // https://html.spec.whatwg.org/multipage/#globaleventhandlers global_event_handlers!(NoOnload); diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index adbb790a181b..ffd0d111cad8 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -745,6 +745,8 @@ impl HTMLFormElement { .map(|field| (&*field.name, field.replace_value(charset))), ); + println!("New URL: {url}", url = &load_data.url); + self.plan_to_navigate(load_data, target); } @@ -952,6 +954,20 @@ impl HTMLFormElement { let input = child.downcast::().unwrap(); data_set.append(&mut input.form_datums(submitter, encoding)); + + // TODO: probably move to input.form_datums(...) function + // 4.10.18.2 https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#submitting-element-directionality:-the-dirname-attribute + let dirname: DOMString = input.DirName(); + let dirname_str: &str = &*dirname; + if !dirname_str.is_empty() { + data_set.push(FormDatum { + ty: input.Type(), + name: DOMString::from_string(dirname_str.to_owned()), + value: FormDatumValue::String(DOMString::from( + input.directionality("auto"), + )), + }); + } }, HTMLElementTypeId::HTMLButtonElement => { let button = child.downcast::().unwrap(); @@ -983,8 +999,6 @@ impl HTMLFormElement { } } data_set - // TODO: Handle `dirnames` (needs directionality support) - // https://html.spec.whatwg.org/multipage/#the-directionality } /// diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 441206c9dada..298af937a322 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -75,6 +75,7 @@ use std::ptr::NonNull; use style::attr::AttrValue; use style::element_state::ElementState; use style::str::{split_commas, str_join}; +use unicode_bidi::{bidi_class, BidiClass}; const DEFAULT_SUBMIT_VALUE: &'static str = "Submit"; const DEFAULT_RESET_VALUE: &'static str = "Reset"; @@ -327,6 +328,41 @@ impl HTMLInputElement { ) } + pub fn directionality(&self, element_direction: &str) -> String { + match self.input_type() { + InputType::Tel => return "ltr".to_owned(), + InputType::Text | InputType::Search | InputType::Url | InputType::Email => { + if element_direction == "auto" { + let value: String = self.Value().to_string(); + return HTMLInputElement::auto_directionality(&value); + } + }, + _ => {}, + } + + return "ltr".to_owned(); + } + + pub fn auto_directionality(value: &str) -> String { + if HTMLInputElement::first_strong_character_is_rtl(value) { + "rtl".to_owned() + } else { + "ltr".to_owned() + } + } + + fn first_strong_character_is_rtl(value: &str) -> bool { + for ch in value.chars() { + return match bidi_class(ch) { + BidiClass::L => false, + BidiClass::AL => true, + BidiClass::R => true, + _ => continue, + }; + } + false + } + // https://html.spec.whatwg.org/multipage/#dom-input-value // https://html.spec.whatwg.org/multipage/#concept-input-apply fn value_mode(&self) -> ValueMode { diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 9fd316e3a18b..0cc174cc3c1f 100755 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -22,6 +22,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlfieldsetelement::HTMLFieldSetElement; use crate::dom::htmlformelement::{FormControl, HTMLFormElement}; +use crate::dom::htmlinputelement::HTMLInputElement; use crate::dom::keyboardevent::KeyboardEvent; use crate::dom::node::{document_from_node, window_from_node}; use crate::dom::node::{ @@ -173,6 +174,14 @@ impl HTMLTextAreaElement { ) } + pub fn directionality(&self, element_direction: &str) -> String { + if element_direction == "auto" { + let value: String = self.Value().to_string(); + return HTMLInputElement::auto_directionality(&value); + } + return "ltr".to_owned(); + } + fn update_placeholder_shown_state(&self) { let has_placeholder = !self.placeholder.borrow().is_empty(); let has_value = !self.textinput.borrow().is_empty(); diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl index ef529dc80af0..5300ca8b2a0a 100644 --- a/components/script/dom/webidls/HTMLElement.webidl +++ b/components/script/dom/webidls/HTMLElement.webidl @@ -14,8 +14,8 @@ interface HTMLElement : Element { attribute DOMString lang; [CEReactions] attribute boolean translate; - // [CEReactions] - // attribute DOMString dir; + [CEReactions] + attribute DOMString dir; readonly attribute DOMStringMap dataset; // microdata diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index ce290caabf7c..724a44e9869b 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -2017,6 +2017,7 @@ impl Window { } // TODO: step 11, navigationType. // Step 12, 13 + println!("ScriptThread::navigate"); ScriptThread::navigate(pipeline_id, load_data, replace); }; } diff --git a/tests/wpt/metadata/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html.ini b/tests/wpt/metadata/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html.ini deleted file mode 100644 index 13a9c4d09183..000000000000 --- a/tests/wpt/metadata/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[dirname-ltr.html] - type: testharness - [submit element directionality] - expected: FAIL - diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html b/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html index 28d1c150b372..6420b5b0c76a 100644 --- a/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html +++ b/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html @@ -20,10 +20,12 @@ } var t = async_test("submit element directionality"); - document.querySelector("input").value="foobar"; - document.querySelector("button").click(); + setTimeout(function() { + document.querySelector("input").value="foobar"; + document.querySelector("button").click(); - document.querySelector("iframe").onload = t.step_func_done(function() { - assert_equals(getParameterByName("comment.dir"), "ltr"); - }); + document.querySelector("iframe").onload = t.step_func_done(function() { + assert_equals(getParameterByName("comment.dir"), "ltr"); + }); + }, 3000); diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl.html b/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl.html new file mode 100644 index 000000000000..69eb45c992c6 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl.html @@ -0,0 +1,32 @@ + + +Submitting element directionality: the dirname attribute + + + + +
+
+

+

+
+ +