diff options
author | rohan.prinja <rohan.prinja@samsung.com> | 2015-11-03 19:01:23 +0900 |
---|---|---|
committer | rohan.prinja <rohan.prinja@samsung.com> | 2015-11-03 19:01:23 +0900 |
commit | 6e774ea6eb6d719b98f924ab5bd0629d92fb27d0 (patch) | |
tree | fa48b89bb313a2e9514124b556bbcff5ed526a0f /components | |
parent | 7032a5d1dee9bb2ba0bee45f1fda984dadfa0609 (diff) | |
parent | 4f51710ed387baa1ad0a6e4cdb0fc5eee44093d5 (diff) | |
download | servo-6e774ea6eb6d719b98f924ab5bd0629d92fb27d0.tar.gz servo-6e774ea6eb6d719b98f924ab5bd0629d92fb27d0.zip |
merge from master
Diffstat (limited to 'components')
109 files changed, 1591 insertions, 924 deletions
diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index d0c5003f908..d578fac7832 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -1203,6 +1203,21 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { for frame in self.current_frame_tree_iter(self.root_frame_id) { let pipeline = self.pipeline(frame.current); + // Check to see if there are any webfonts still loading. + // + // If GetWebFontLoadState returns false, either there are no + // webfonts loading, or there's a WebFontLoaded message waiting in + // script_chan's message queue. Therefore, we need to check this + // before we check whether the document is ready; otherwise, + // there's a race condition where a webfont has finished loading, + // but hasn't yet notified the document. + let (sender, receiver) = ipc::channel().unwrap(); + let msg = LayoutControlMsg::GetWebFontLoadState(sender); + pipeline.layout_chan.0.send(msg).unwrap(); + if receiver.recv().unwrap() { + return false; + } + // Synchronously query the script task for this pipeline // to see if it is idle. let (sender, receiver) = channel(); @@ -1213,13 +1228,6 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { return false; } - let (sender, receiver) = ipc::channel().unwrap(); - let msg = LayoutControlMsg::GetWebFontLoadState(sender); - pipeline.layout_chan.0.send(msg).unwrap(); - if receiver.recv().unwrap() { - return false; - } - // Check the visible rectangle for this pipeline. If the constellation has received a // size for the pipeline, then its painting should be up to date. If the constellation // *hasn't* received a size, it could be that the layer was hidden by script before the diff --git a/components/layout/block.rs b/components/layout/block.rs index f580763e931..399b3e5a9f4 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -340,6 +340,10 @@ impl CandidateBSizeIterator { (LengthOrPercentageOrNone::Percentage(percent), Some(block_container_block_size)) => { Some(block_container_block_size.scale_by(percent)) } + (LengthOrPercentageOrNone::Calc(calc), Some(block_container_block_size)) => { + Some(block_container_block_size.scale_by(calc.percentage()) + calc.length()) + } + (LengthOrPercentageOrNone::Calc(_), _) | (LengthOrPercentageOrNone::Percentage(_), None) | (LengthOrPercentageOrNone::None, _) => None, (LengthOrPercentageOrNone::Length(length), _) => Some(length), @@ -1024,17 +1028,12 @@ impl BlockFlow { let mut candidate_block_size_iterator = CandidateBSizeIterator::new( &self.fragment, self.base.block_container_explicit_block_size); - loop { - match candidate_block_size_iterator.next() { - Some(candidate_block_size) => { - candidate_block_size_iterator.candidate_value = - match candidate_block_size { - MaybeAuto::Auto => block_size, - MaybeAuto::Specified(value) => value - } + while let Some(candidate_block_size) = candidate_block_size_iterator.next() { + candidate_block_size_iterator.candidate_value = + match candidate_block_size { + MaybeAuto::Auto => block_size, + MaybeAuto::Specified(value) => value } - None => break, - } } // Adjust `cur_b` as necessary to account for the explicitly-specified block-size. diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 5bd622871e1..8711881ffaf 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -27,6 +27,7 @@ use std::{fmt, isize, mem}; use style::computed_values::{display, overflow_x, position, text_align, text_justify}; use style::computed_values::{text_overflow, vertical_align, white_space}; use style::properties::ComputedValues; +use style::values::computed::LengthOrPercentage; use text; use unicode_bidi; use util; @@ -953,15 +954,15 @@ impl InlineFlow { offset_from_baseline = offset_from_baseline - *depth_below_baseline } }, - vertical_align::T::Length(length) => { + vertical_align::T::LengthOrPercentage(LengthOrPercentage::Length(length)) => { offset_from_baseline = offset_from_baseline - length } - vertical_align::T::Percentage(p) => { + vertical_align::T::LengthOrPercentage(LengthOrPercentage::Percentage(p)) => { let line_height = fragment.calculate_line_height(layout_context); let percent_offset = line_height.scale_by(p); offset_from_baseline = offset_from_baseline - percent_offset } - vertical_align::T::Calc(calc) => { + vertical_align::T::LengthOrPercentage(LengthOrPercentage::Calc(calc)) => { let line_height = fragment.calculate_line_height(layout_context); let percent_offset = line_height.scale_by(calc.percentage()); offset_from_baseline = offset_from_baseline - percent_offset - calc.length() diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 6e8c62b65f7..06c56110386 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -51,9 +51,7 @@ use profile_traits::time::{self, ProfilerMetadata, profile}; use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request}; use query::{MarginPadding, MarginRetrievingFragmentBorderBoxIterator, PositionProperty}; use query::{PositionRetrievingFragmentBorderBoxIterator, Side}; -use script::dom::bindings::js::LayoutJS; -use script::dom::document::Document; -use script::dom::node::{LayoutData, Node}; +use script::dom::node::LayoutData; use script::layout_interface::Animation; use script::layout_interface::{LayoutChan, LayoutRPC, OffsetParentResponse}; use script::layout_interface::{Msg, NewLayoutTaskInfo, Reflow, ReflowGoal, ReflowQueryType}; @@ -90,7 +88,7 @@ use util::opts; use util::task::spawn_named_with_send_on_failure; use util::task_state; use util::workqueue::WorkQueue; -use wrapper::{LayoutDocument, LayoutNode, ThreadSafeLayoutNode}; +use wrapper::{LayoutNode, ThreadSafeLayoutNode}; /// The number of screens of data we're allowed to generate display lists for in each direction. pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8; @@ -595,7 +593,7 @@ impl LayoutTask { profile(time::ProfilerCategory::LayoutPerform, self.profiler_metadata(), self.time_profiler_chan.clone(), - || self.handle_reflow(&*data, possibly_locked_rw_data)); + || self.handle_reflow(&data, possibly_locked_rw_data)); }, Msg::TickAnimations => self.tick_all_animations(possibly_locked_rw_data), Msg::ReflowWithNewlyLoadedWebFont => { @@ -892,17 +890,9 @@ impl LayoutTask { property: &Atom, layout_root: &mut FlowRef) -> Option<String> { - // FIXME: Isolate this transmutation into a "bridge" module. - // FIXME(rust#16366): The following line had to be moved because of a - // rustc bug. It should be in the next unsafe block. - let node: LayoutJS<Node> = unsafe { - LayoutJS::from_trusted_node_address(requested_node) - }; - let node: &LayoutNode = unsafe { - transmute(&node) - }; + let node = unsafe { LayoutNode::new(&requested_node) }; - let layout_node = ThreadSafeLayoutNode::new(node); + let layout_node = ThreadSafeLayoutNode::new(&node); let layout_node = match pseudo { &Some(PseudoElement::Before) => layout_node.get_before_pseudo(), &Some(PseudoElement::After) => layout_node.get_after_pseudo(), @@ -1133,15 +1123,9 @@ impl LayoutTask { }; let _ajst = AutoJoinScriptTask { data: data }; - // FIXME: Isolate this transmutation into a "bridge" module. - let mut doc: LayoutJS<Document> = unsafe { - LayoutJS::from_trusted_node_address(data.document).downcast::<Document>().unwrap() - }; - let doc: &mut LayoutDocument = unsafe { - transmute(&mut doc) - }; - - let mut node: LayoutNode = match doc.root_node() { + let document = unsafe { LayoutNode::new(&data.document) }; + let document = document.as_document().unwrap(); + let node: LayoutNode = match document.root_node() { None => return, Some(x) => x, }; @@ -1187,7 +1171,7 @@ impl LayoutTask { let needs_reflow = screen_size_changed && !needs_dirtying; unsafe { if needs_dirtying { - LayoutTask::dirty_all_nodes(&mut node); + LayoutTask::dirty_all_nodes(node); } } if needs_reflow { @@ -1196,11 +1180,12 @@ impl LayoutTask { } } - let event_state_changes = doc.drain_event_state_changes(); + let state_changes = document.drain_element_state_changes(); if !needs_dirtying { - for &(el, state) in event_state_changes.iter() { - assert!(!state.is_empty()); - el.note_event_state_change(); + for &(el, state_change) in state_changes.iter() { + debug_assert!(!state_change.is_empty()); + let hint = rw_data.stylist.restyle_hint_for_state_change(&el, el.get_state(), state_change); + el.note_restyle_hint(hint); } } @@ -1229,7 +1214,7 @@ impl LayoutTask { }); // Retrieve the (possibly rebuilt) root flow. - rw_data.root_flow = self.try_get_layout_root(node.clone()); + rw_data.root_flow = self.try_get_layout_root(node); } // Send new canvas renderers to the paint task @@ -1459,7 +1444,7 @@ impl LayoutTask { } } - unsafe fn dirty_all_nodes(node: &mut LayoutNode) { + unsafe fn dirty_all_nodes(node: LayoutNode) { for node in node.traverse_preorder() { // TODO(cgaebel): mark nodes which are sensitive to media queries as // "changed": diff --git a/components/layout/lib.rs b/components/layout/lib.rs index f12335d9c04..fa8e939839c 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -47,7 +47,7 @@ extern crate net_traits; extern crate rustc_serialize; extern crate script; extern crate script_traits; -extern crate selectors; +#[macro_use(state_pseudo_classes)] extern crate selectors; extern crate serde; extern crate serde_json; extern crate smallvec; diff --git a/components/layout/model.rs b/components/layout/model.rs index 8ee98a39678..f49ac51ad21 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -411,6 +411,8 @@ pub fn specified_or_none(length: LengthOrPercentageOrNone, containing_length: Au match length { LengthOrPercentageOrNone::None => None, LengthOrPercentageOrNone::Percentage(percent) => Some(containing_length.scale_by(percent)), + LengthOrPercentageOrNone::Calc(calc) => + Some(containing_length.scale_by(calc.percentage()) + calc.length()), LengthOrPercentageOrNone::Length(length) => Some(length), } } diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index a7493f6e0c3..85351c5c126 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -42,8 +42,7 @@ use script::dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId}; use script::dom::bindings::js::LayoutJS; use script::dom::characterdata::LayoutCharacterDataHelpers; use script::dom::document::{Document, LayoutDocumentHelpers}; -use script::dom::element; -use script::dom::element::{Element, EventState, LayoutElementHelpers, RawLayoutElementHelpers}; +use script::dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers}; use script::dom::htmlcanvaselement::{LayoutHTMLCanvasElementHelpers, HTMLCanvasData}; use script::dom::htmliframeelement::HTMLIFrameElement; use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers; @@ -52,8 +51,10 @@ use script::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaEl use script::dom::node::{HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY}; use script::dom::node::{LayoutNodeHelpers, Node, SharedLayoutData}; use script::dom::text::Text; +use script::layout_interface::TrustedNodeAddress; use selectors::matching::DeclarationBlock; use selectors::parser::{AttrSelector, NamespaceConstraint}; +use selectors::states::*; use smallvec::VecLike; use std::borrow::ToOwned; use std::cell::{Ref, RefMut}; @@ -68,6 +69,7 @@ use style::legacy::UnsignedIntegerAttribute; use style::node::TElementAttributes; use style::properties::ComputedValues; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock}; +use style::restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint}; use url::Url; use util::str::{is_whitespace, search_index}; @@ -79,7 +81,7 @@ pub struct LayoutNode<'a> { node: LayoutJS<Node>, /// Being chained to a PhantomData prevents `LayoutNode`s from escaping. - pub chain: PhantomData<&'a ()>, + chain: PhantomData<&'a ()>, } impl<'a> PartialEq for LayoutNode<'a> { @@ -90,6 +92,14 @@ impl<'a> PartialEq for LayoutNode<'a> { } impl<'ln> LayoutNode<'ln> { + pub unsafe fn new(address: &TrustedNodeAddress) -> LayoutNode { + let node = LayoutJS::from_trusted_node_address(*address); + LayoutNode { + node: node, + chain: PhantomData, + } + } + /// Creates a new layout node with the same lifetime as this layout node. pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> LayoutNode<'ln> { LayoutNode { @@ -205,6 +215,15 @@ impl<'ln> LayoutNode<'ln> { as_element(self.node) } + pub fn as_document(&self) -> Option<LayoutDocument<'ln>> { + self.node.downcast().map(|document| { + LayoutDocument { + document: document, + chain: PhantomData, + } + }) + } + fn parent_node(&self) -> Option<LayoutNode<'ln>> { unsafe { self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node)) @@ -353,16 +372,12 @@ impl<'le> LayoutDocument<'le> { } pub fn root_node(&self) -> Option<LayoutNode<'le>> { - let mut node = self.as_node().first_child(); - while node.is_some() && !node.unwrap().is_element() { - node = node.unwrap().next_sibling(); - } - node + self.as_node().children().find(LayoutNode::is_element) } - pub fn drain_event_state_changes(&self) -> Vec<(LayoutElement, EventState)> { + pub fn drain_element_state_changes(&self) -> Vec<(LayoutElement, ElementState)> { unsafe { - let changes = self.document.drain_event_state_changes(); + let changes = self.document.drain_element_state_changes(); Vec::from_iter(changes.iter().map(|&(el, state)| (LayoutElement { element: el, @@ -393,38 +408,57 @@ impl<'le> LayoutElement<'le> { } } - /// Properly marks nodes as dirty in response to event state changes. - /// - /// Currently this implementation is very conservative, and basically mirrors node::dirty_impl. - /// With restyle hints, we can do less work here. - pub fn note_event_state_change(&self) { - let node = self.as_node(); + pub fn get_state(&self) -> ElementState { + self.element.get_state_for_layout() + } - // Bail out if we're already dirty. This won't be valid when we start doing more targeted - // dirtying with restyle hints. - if node.is_dirty() { return } + /// Properly marks nodes as dirty in response to restyle hints. + pub fn note_restyle_hint(&self, hint: RestyleHint) { + // Bail early if there's no restyling to do. + if hint.is_empty() { + return; + } - // Dirty descendants. - fn dirty_subtree(node: LayoutNode) { - // Stop if this subtree is already dirty. This won't be valid with restyle hints, see above. - if node.is_dirty() { return } + // If the restyle hint is non-empty, we need to restyle either this element + // or one of its siblings. Mark our ancestor chain as having dirty descendants. + let node = self.as_node(); + let mut curr = node; + while let Some(parent) = curr.parent_node() { + if parent.has_dirty_descendants() { break } + unsafe { parent.set_dirty_descendants(true); } + curr = parent; + } + // Set up our helpers. + fn dirty_node(node: &LayoutNode) { unsafe { node.set_dirty(true); node.set_dirty_descendants(true); } - - for kid in node.children() { - dirty_subtree(kid); + } + fn dirty_descendants(node: &LayoutNode) { + for ref child in node.children() { + dirty_node(child); + dirty_descendants(child); } } - dirty_subtree(node); - let mut curr = node; - while let Some(parent) = curr.parent_node() { - if parent.has_dirty_descendants() { break } - unsafe { parent.set_dirty_descendants(true); } - curr = parent; + // Process hints. + if hint.contains(RESTYLE_SELF) { + dirty_node(&node); + } + if hint.contains(RESTYLE_DESCENDANTS) { + unsafe { node.set_dirty_descendants(true); } + dirty_descendants(&node); + } + if hint.contains(RESTYLE_LATER_SIBLINGS) { + let mut next = ::selectors::Element::next_sibling_element(self); + while let Some(sib) = next { + let sib_node = sib.as_node(); + dirty_node(&sib_node); + dirty_descendants(&sib_node); + next = ::selectors::Element::next_sibling_element(&sib); + } } } } @@ -438,6 +472,15 @@ fn as_element<'le>(node: LayoutJS<Node>) -> Option<LayoutElement<'le>> { }) } +macro_rules! state_getter { + ($( + $(#[$Flag_attr: meta])* + state $css: expr => $variant: ident / $method: ident / + $flag: ident = $value: expr, + )+) => { + $( fn $method(&self) -> bool { self.element.get_state_for_layout().contains($flag) } )+ + } +} impl<'le> ::selectors::Element for LayoutElement<'le> { fn parent_element(&self) -> Option<LayoutElement<'le>> { @@ -529,20 +572,7 @@ impl<'le> ::selectors::Element for LayoutElement<'le> { false } - #[inline] - fn get_hover_state(&self) -> bool { - self.element.get_event_state_for_layout().contains(element::IN_HOVER_STATE) - } - - #[inline] - fn get_focus_state(&self) -> bool { - self.element.get_event_state_for_layout().contains(element::IN_FOCUS_STATE) - } - - #[inline] - fn get_active_state(&self) -> bool { - self.element.get_event_state_for_layout().contains(element::IN_ACTIVE_STATE) - } + state_pseudo_classes!(state_getter); #[inline] fn get_id(&self) -> Option<Atom> { @@ -552,26 +582,6 @@ impl<'le> ::selectors::Element for LayoutElement<'le> { } #[inline] - fn get_disabled_state(&self) -> bool { - self.element.get_event_state_for_layout().contains(element::IN_DISABLED_STATE) - } - - #[inline] - fn get_enabled_state(&self) -> bool { - self.element.get_event_state_for_layout().contains(element::IN_ENABLED_STATE) - } - - #[inline] - fn get_checked_state(&self) -> bool { - self.element.get_checked_state_for_layout() - } - - #[inline] - fn get_indeterminate_state(&self) -> bool { - self.element.get_indeterminate_state_for_layout() - } - - #[inline] fn has_class(&self, name: &Atom) -> bool { unsafe { self.element.has_class_for_layout(name) diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml index 51573136d4e..620a10ca1b6 100644 --- a/components/net/Cargo.toml +++ b/components/net/Cargo.toml @@ -16,6 +16,9 @@ path = "../util" [dependencies.devtools_traits] path = "../devtools_traits" +[dependencies.brotli] +git = "https://github.com/ende76/brotli-rs" + [dependencies.plugins] path = "../plugins" diff --git a/components/net/about_loader.rs b/components/net/about_loader.rs index 4308b4a8ccc..04878fed70b 100644 --- a/components/net/about_loader.rs +++ b/components/net/about_loader.rs @@ -9,7 +9,7 @@ use hyper::mime::{Mime, SubLevel, TopLevel}; use mime_classifier::MIMEClassifier; use net_traits::ProgressMsg::Done; use net_traits::{LoadConsumer, LoadData, Metadata}; -use resource_task::{send_error, start_sending}; +use resource_task::{send_error, start_sending_sniffed_opt}; use std::fs::PathExt; use std::sync::Arc; use url::Url; @@ -18,14 +18,16 @@ use util::resource_files::resources_dir_path; pub fn factory(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Arc<MIMEClassifier>) { match load_data.url.non_relative_scheme_data().unwrap() { "blank" => { - let chan = start_sending(start_chan, Metadata { + let metadata = Metadata { final_url: load_data.url, content_type: Some(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![]))), charset: Some("utf-8".to_owned()), headers: None, status: Some(RawStatus(200, "OK".into())), - }); - chan.send(Done(Ok(()))).unwrap(); + }; + if let Ok(chan) = start_sending_sniffed_opt(start_chan, metadata, classifier, &[]) { + let _ = chan.send(Done(Ok(()))); + } return } "crash" => panic!("Loading the about:crash URL."), diff --git a/components/net/data_loader.rs b/components/net/data_loader.rs index f9276d8f0a2..f2f72bac88e 100644 --- a/components/net/data_loader.rs +++ b/components/net/data_loader.rs @@ -6,21 +6,21 @@ use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value}; use mime_classifier::MIMEClassifier; use net_traits::ProgressMsg::{Done, Payload}; use net_traits::{LoadConsumer, LoadData, Metadata}; -use resource_task::{send_error, start_sending}; +use resource_task::{send_error, start_sending_sniffed_opt}; use rustc_serialize::base64::FromBase64; use std::sync::Arc; use url::SchemeData; use url::percent_encoding::percent_decode; -pub fn factory(load_data: LoadData, senders: LoadConsumer, _classifier: Arc<MIMEClassifier>) { +pub fn factory(load_data: LoadData, senders: LoadConsumer, classifier: Arc<MIMEClassifier>) { // NB: we don't spawn a new task. // Hypothesis: data URLs are too small for parallel base64 etc. to be worth it. // Should be tested at some point. // Left in separate function to allow easy moving to a task, if desired. - load(load_data, senders) + load(load_data, senders, classifier) } -pub fn load(load_data: LoadData, start_chan: LoadConsumer) { +pub fn load(load_data: LoadData, start_chan: LoadConsumer, classifier: Arc<MIMEClassifier>) { let url = load_data.url; assert!(&*url.scheme == "data"); @@ -62,27 +62,25 @@ pub fn load(load_data: LoadData, start_chan: LoadConsumer) { content_type = Some(Mime(TopLevel::Text, SubLevel::Plain, vec!((Attr::Charset, Value::Ext("US-ASCII".to_owned()))))); } - let mut metadata = Metadata::default(url); - metadata.set_content_type(content_type.as_ref()); - let progress_chan = start_sending(start_chan, metadata); let bytes = percent_decode(parts[1].as_bytes()); - if is_base64 { + let bytes = if is_base64 { // FIXME(#2909): It’s unclear what to do with non-alphabet characters, // but Acid 3 apparently depends on spaces being ignored. let bytes = bytes.into_iter().filter(|&b| b != ' ' as u8).collect::<Vec<u8>>(); match bytes.from_base64() { - Err(..) => { - progress_chan.send(Done(Err("non-base64 data uri".to_owned()))).unwrap(); - } - Ok(data) => { - progress_chan.send(Payload(data)).unwrap(); - progress_chan.send(Done(Ok(()))).unwrap(); - } + Err(..) => return send_error(url, "non-base64 data uri".to_owned(), start_chan), + Ok(data) => data, } } else { - progress_chan.send(Payload(bytes)).unwrap(); - progress_chan.send(Done(Ok(()))).unwrap(); + bytes + }; + + let mut metadata = Metadata::default(url); + metadata.set_content_type(content_type.as_ref()); + if let Ok(chan) = start_sending_sniffed_opt(start_chan, metadata, classifier, &bytes) { + let _ = chan.send(Payload(bytes)); + let _ = chan.send(Done(Ok(()))); } } diff --git a/components/net/file_loader.rs b/components/net/file_loader.rs index f1ffe9c957f..c41f382f949 100644 --- a/components/net/file_loader.rs +++ b/components/net/file_loader.rs @@ -5,7 +5,7 @@ use mime_classifier::MIMEClassifier; use net_traits::ProgressMsg::{Done, Payload}; use net_traits::{LoadConsumer, LoadData, Metadata}; -use resource_task::{ProgressSender, send_error, start_sending, start_sending_sniffed}; +use resource_task::{ProgressSender, send_error, start_sending_sniffed, start_sending_sniffed_opt}; use std::borrow::ToOwned; use std::error::Error; use std::fs::File; @@ -52,19 +52,28 @@ pub fn factory(load_data: LoadData, senders: LoadConsumer, classifier: Arc<MIMEC Ok(file_path) => { match File::open(&file_path) { Ok(ref mut reader) => { - let metadata = Metadata::default(url); - let res = read_block(reader); - let (res, progress_chan) = match res { + match read_block(reader) { Ok(ReadStatus::Partial(buf)) => { + let metadata = Metadata::default(url); let progress_chan = start_sending_sniffed(senders, metadata, classifier, &buf); progress_chan.send(Payload(buf)).unwrap(); - (read_all(reader, &progress_chan), progress_chan) + let res = read_all(reader, &progress_chan); + let _ = progress_chan.send(Done(res)); + } + Ok(ReadStatus::EOF) => { + let metadata = Metadata::default(url); + if let Ok(chan) = start_sending_sniffed_opt(senders, + metadata, + classifier, + &[]) { + let _ = chan.send(Done(Ok(()))); + } + } + Err(e) => { + send_error(url, e, senders); } - Ok(ReadStatus::EOF) | Err(_) => - (res.map(|_| ()), start_sending(senders, metadata)), }; - progress_chan.send(Done(res)).unwrap(); } Err(e) => { send_error(url, e.description().to_owned(), senders); diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 521af527a37..62e461dbc21 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use brotli::Decompressor; use cookie; use cookie_storage::CookieStorage; use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest}; @@ -154,10 +155,9 @@ pub trait HttpResponse: Read { Some(Encoding::Gzip) } else if encodings.contains(&Encoding::Deflate) { Some(Encoding::Deflate) - } else { - // TODO: Is this the correct behaviour? - None - } + } else if encodings.contains(&Encoding::EncodingExt("br".to_owned())) { + Some(Encoding::EncodingExt("br".to_owned())) + } else { None } } } }) @@ -302,7 +302,8 @@ fn set_default_accept_encoding(headers: &mut Headers) { headers.set(AcceptEncoding(vec![ qitem(Encoding::Gzip), - qitem(Encoding::Deflate) + qitem(Encoding::Deflate), + qitem(Encoding::EncodingExt("br".to_owned())) ])); } @@ -394,6 +395,7 @@ impl<R: HttpResponse> Read for StreamedResponse<R> { match self.decoder { Decoder::Gzip(ref mut d) => d.read(buf), Decoder::Deflate(ref mut d) => d.read(buf), + Decoder::Brotli(ref mut d) => d.read(buf), Decoder::Plain(ref mut d) => d.read(buf) } } @@ -421,6 +423,10 @@ impl<R: HttpResponse> StreamedResponse<R> { let response_decoding = DeflateDecoder::new(response); Ok(StreamedResponse::new(m, Decoder::Deflate(response_decoding))) } + Some(Encoding::EncodingExt(ref ext)) if ext == "br" => { + let response_decoding = Decompressor::new(response); + Ok(StreamedResponse::new(m, Decoder::Brotli(response_decoding))) + } _ => { Ok(StreamedResponse::new(m, Decoder::Plain(response))) } @@ -431,6 +437,7 @@ impl<R: HttpResponse> StreamedResponse<R> { enum Decoder<R: Read> { Gzip(GzDecoder<R>), Deflate(DeflateDecoder<R>), + Brotli(Decompressor<R>), Plain(R) } diff --git a/components/net/lib.rs b/components/net/lib.rs index d09d28fa5ba..e0bae6b829d 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -17,6 +17,7 @@ extern crate cookie as cookie_rs; extern crate devtools_traits; extern crate euclid; extern crate flate2; +extern crate brotli; extern crate hyper; extern crate ipc_channel; extern crate net_traits; diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 9fef339e838..529f79b448e 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -59,11 +59,6 @@ pub fn send_error(url: Url, err: String, start_chan: LoadConsumer) { } } -/// For use by loaders in responding to a Load message. -pub fn start_sending(start_chan: LoadConsumer, metadata: Metadata) -> ProgressSender { - start_sending_opt(start_chan, metadata).ok().unwrap() -} - /// For use by loaders in responding to a Load message that allows content sniffing. pub fn start_sending_sniffed(start_chan: LoadConsumer, metadata: Metadata, classifier: Arc<MIMEClassifier>, partial_body: &[u8]) @@ -122,7 +117,7 @@ fn apache_bug_predicate(last_raw_content_type: &[u8]) -> ApacheBugFlag { } /// For use by loaders in responding to a Load message. -pub fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata) -> Result<ProgressSender, ()> { +fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata) -> Result<ProgressSender, ()> { match start_chan { LoadConsumer::Channel(start_chan) => { let (progress_chan, progress_port) = ipc::channel().unwrap(); @@ -253,8 +248,7 @@ impl ResourceManager { "about" => from_factory(about_loader::factory), _ => { debug!("resource_task: no loader for scheme {}", load_data.url.scheme); - start_sending(consumer, Metadata::default(load_data.url)) - .send(ProgressMsg::Done(Err("no loader for scheme".to_owned()))).unwrap(); + send_error(load_data.url, "no loader for scheme".to_owned(), consumer); return } }; diff --git a/components/profile/heartbeats.rs b/components/profile/heartbeats.rs index 6eaff00e79f..0101f62e25b 100644 --- a/components/profile/heartbeats.rs +++ b/components/profile/heartbeats.rs @@ -11,6 +11,8 @@ use std::env::var_os; use std::error::Error; use std::fs::File; use std::mem; +use std::path::Path; +use util::opts; static mut HBS: Option<*mut HashMap<ProfilerCategory, Heartbeat>> = None; @@ -72,6 +74,7 @@ pub fn cleanup() { } } +/// Check if a heartbeat exists for the given category pub fn is_heartbeat_enabled(category: &ProfilerCategory) -> bool { unsafe { HBS.map_or(false, |m| (*m).contains_key(category)) @@ -93,22 +96,51 @@ pub fn maybe_heartbeat(category: &ProfilerCategory, } } -/// Create a heartbeat if the correct environment variable is set +// TODO(cimes): Android doesn't really do environment variables. Need a better way to configure dynamically. + +fn is_create_heartbeat(category: &ProfilerCategory) -> bool { + opts::get().profile_heartbeats || var_os(format!("SERVO_HEARTBEAT_ENABLE_{:?}", category)).is_some() +} + +fn open_heartbeat_log<P: AsRef<Path>>(name: P) -> Option<File> { + match File::create(name) { + Ok(f) => Some(f), + Err(e) => { + warn!("Failed to open heartbeat log: {}", Error::description(&e)); + None + }, + } +} + +#[cfg(target_os = "android")] +fn get_heartbeat_log(category: &ProfilerCategory) -> Option<File> { + open_heartbeat_log(format!("/sdcard/servo/heartbeat-{:?}.log", category)) +} + +#[cfg(not(target_os = "android"))] +fn get_heartbeat_log(category: &ProfilerCategory) -> Option<File> { + var_os(format!("SERVO_HEARTBEAT_LOG_{:?}", category)).and_then(|name| open_heartbeat_log(&name)) +} + +fn get_heartbeat_window_size(category: &ProfilerCategory) -> usize { + const WINDOW_SIZE_DEFAULT: usize = 1; + match var_os(format!("SERVO_HEARTBEAT_WINDOW_{:?}", category)) { + Some(w) => match w.into_string() { + Ok(s) => s.parse::<usize>().unwrap_or(WINDOW_SIZE_DEFAULT), + _ => WINDOW_SIZE_DEFAULT, + }, + None => WINDOW_SIZE_DEFAULT, + } +} + +/// Possibly create a heartbeat fn maybe_create_heartbeat(hbs: &mut HashMap<ProfilerCategory, Heartbeat>, category: ProfilerCategory) { - static WINDOW_SIZE_DEFAULT: usize = 20; - if let Some(_) = var_os(format!("SERVO_HEARTBEAT_ENABLE_{:?}", category)) { + if is_create_heartbeat(&category) { // get optional log file - let logfile: Option<File> = var_os(format!("SERVO_HEARTBEAT_LOG_{:?}", category)) - .and_then(|name| File::create(name).ok()); - // get window size - let window_size: usize = match var_os(format!("SERVO_HEARTBEAT_WINDOW_{:?}", category)) { - Some(w) => match w.into_string() { - Ok(s) => s.parse::<usize>().unwrap_or(WINDOW_SIZE_DEFAULT), - _ => WINDOW_SIZE_DEFAULT, - }, - None => WINDOW_SIZE_DEFAULT, - }; + let logfile: Option<File> = get_heartbeat_log(&category); + // window size + let window_size: usize = get_heartbeat_window_size(&category); // create the heartbeat match Heartbeat::new(window_size, Some(heartbeat_window_callback), logfile) { Ok(hb) => { diff --git a/components/profile_traits/Cargo.toml b/components/profile_traits/Cargo.toml index 72c97f7f63e..90eb74479d2 100644 --- a/components/profile_traits/Cargo.toml +++ b/components/profile_traits/Cargo.toml @@ -19,7 +19,7 @@ features = [ "serde_serialization" ] [dependencies.energymon] git = "https://github.com/energymon/energymon-rust.git" -rev = "67f74732ac" +rev = "eba1d8a" optional = true [dependencies.energy-monitor] diff --git a/components/profile_traits/energy.rs b/components/profile_traits/energy.rs index a4b60e1316f..23554386f77 100644 --- a/components/profile_traits/energy.rs +++ b/components/profile_traits/energy.rs @@ -36,8 +36,8 @@ mod energymon { static mut EM: Option<*mut EnergyMon> = None; - /// Read energy from the energy monitor, otherwise return 0. - pub fn read_energy_uj() -> u64 { + fn init() { + // can't use lazy_static macro for EM (no Sync trait for EnergyMon) static ONCE: Once = ONCE_INIT; ONCE.call_once(|| { if let Ok(em) = EnergyMon::new() { @@ -47,7 +47,11 @@ mod energymon { } } }); + } + /// Read energy from the energy monitor, otherwise return 0. + pub fn read_energy_uj() -> u64 { + init(); unsafe { // EnergyMon implementations of EnergyMonitor always return a value EM.map_or(0, |em| (*em).read_uj().unwrap()) @@ -55,6 +59,7 @@ mod energymon { } pub fn get_min_interval_ms() -> u32 { + init(); unsafe { EM.map_or(0, |em| ((*em).interval_us() as f64 / 1000.0).ceil() as u32) } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index bd81592d43c..fe8e59d5f1e 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2000,6 +2000,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, config): 'dom::bindings::conversions::StringificationBehavior', 'dom::bindings::error::throw_not_in_union', 'dom::bindings::js::Root', + 'dom::bindings::str::USVString', 'dom::types::*', 'js::jsapi::JSContext', 'js::jsapi::{HandleValue, MutableHandleValue}', @@ -3492,6 +3493,9 @@ def getUnionTypeTemplateVars(type, descriptorProvider): elif type.isDOMString(): name = type.name typeName = "DOMString" + elif type.isUSVString(): + name = type.name + typeName = "USVString" elif type.isPrimitive(): name = type.name typeName = builtinNames[type.tag()] diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index 1f358048831..d89c1c21f32 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -230,8 +230,8 @@ impl GlobalField { /// Create a stack-bounded root for this reference. pub fn root(&self) -> GlobalRoot { match *self { - GlobalField::Window(ref window) => GlobalRoot::Window(window.root()), - GlobalField::Worker(ref worker) => GlobalRoot::Worker(worker.root()), + GlobalField::Window(ref window) => GlobalRoot::Window(Root::from_ref(window)), + GlobalField::Worker(ref worker) => GlobalRoot::Worker(Root::from_ref(worker)), } } } diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs index 09f1392b762..55491d5d624 100644 --- a/components/script/dom/bindings/js.rs +++ b/components/script/dom/bindings/js.rs @@ -74,10 +74,6 @@ impl<T> JS<T> { } impl<T: Reflectable> JS<T> { - /// Root this JS-owned value to prevent its collection as garbage. - pub fn root(&self) -> Root<T> { - Root::new(self.ptr) - } /// Create a JS<T> from a Root<T> /// XXX Not a great API. Should be a call on Root<T> instead #[allow(unrooted_must_root)] @@ -292,7 +288,7 @@ impl<T: Reflectable> MutHeap<JS<T>> { pub fn get(&self) -> Root<T> { debug_assert!(task_state::get().is_script()); unsafe { - ptr::read(self.val.get()).root() + Root::from_ref(&*ptr::read(self.val.get())) } } } @@ -370,7 +366,7 @@ impl<T: Reflectable> MutNullableHeap<JS<T>> { pub fn get(&self) -> Option<Root<T>> { debug_assert!(task_state::get().is_script()); unsafe { - ptr::read(self.ptr.get()).map(|o| o.root()) + ptr::read(self.ptr.get()).map(|o| Root::from_ref(&*o)) } } diff --git a/components/script/dom/bindings/num.rs b/components/script/dom/bindings/num.rs index ed5d78cdb6c..720aeb28557 100644 --- a/components/script/dom/bindings/num.rs +++ b/components/script/dom/bindings/num.rs @@ -4,7 +4,6 @@ //! The `Finite<T>` struct. -use core::nonzero::Zeroable; use num::Float; use std::ops::Deref; @@ -12,8 +11,6 @@ use std::ops::Deref; #[derive(JSTraceable, Clone, Copy, Eq, PartialEq)] pub struct Finite<T: Float>(T); -unsafe impl<T: Float> Zeroable for Finite<T> {} - impl<T: Float> Finite<T> { /// Create a new `Finite<T: Float>` safely. pub fn new(value: T) -> Option<Finite<T>> { diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 6ed7e45c45a..84869943239 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -63,10 +63,11 @@ use profile_traits::time::ProfilerChan as TimeProfilerChan; use script_task::ScriptChan; use script_traits::{TimerEventChan, TimerEventId, TimerSource, UntrustedNodeAddress}; use selectors::parser::PseudoElement; +use selectors::states::*; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use std::boxed::FnBox; -use std::cell::{Cell, RefCell, UnsafeCell}; +use std::cell::{Cell, UnsafeCell}; use std::collections::hash_state::HashState; use std::collections::{HashMap, HashSet}; use std::ffi::CString; @@ -139,12 +140,6 @@ pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JS } } -impl<T: JSTraceable> JSTraceable for RefCell<T> { - fn trace(&self, trc: *mut JSTracer) { - self.borrow().trace(trc) - } -} - impl<T: JSTraceable> JSTraceable for Rc<T> { fn trace(&self, trc: *mut JSTracer) { (**self).trace(trc) @@ -157,26 +152,6 @@ impl<T: JSTraceable> JSTraceable for Box<T> { } } -impl<T: JSTraceable> JSTraceable for *const T { - fn trace(&self, trc: *mut JSTracer) { - if !self.is_null() { - unsafe { - (**self).trace(trc) - } - } - } -} - -impl<T: JSTraceable> JSTraceable for *mut T { - fn trace(&self, trc: *mut JSTracer) { - if !self.is_null() { - unsafe { - (**self).trace(trc) - } - } - } -} - impl<T: JSTraceable + Copy> JSTraceable for Cell<T> { fn trace(&self, trc: *mut JSTracer) { self.get().trace(trc) @@ -309,6 +284,7 @@ no_jsmanaged_fields!(TimeProfilerChan); no_jsmanaged_fields!(MemProfilerChan); no_jsmanaged_fields!(PseudoElement); no_jsmanaged_fields!(Length); +no_jsmanaged_fields!(ElementState); impl JSTraceable for Box<ScriptChan + Send> { #[inline] diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 131dca45df8..f3d85c619a2 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -8,6 +8,7 @@ use canvas_traits::{CompositionOrBlending, LineCapStyle, LineJoinStyle}; use canvas_traits::{FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle, RepetitionStyle}; use cssparser::Color as CSSColor; use cssparser::{Parser, RGBA}; +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasWindingRule; @@ -37,7 +38,6 @@ use net_traits::image::base::PixelFormat; use net_traits::image_cache_task::ImageResponse; use num::{Float, ToPrimitive}; use std::borrow::ToOwned; -use std::cell::RefCell; use std::str::FromStr; use std::sync::mpsc::channel; use std::{cmp, fmt}; @@ -63,8 +63,8 @@ pub struct CanvasRenderingContext2D { #[ignore_heap_size_of = "Defined in ipc-channel"] ipc_renderer: IpcSender<CanvasMsg>, canvas: JS<HTMLCanvasElement>, - state: RefCell<CanvasContextState>, - saved_states: RefCell<Vec<CanvasContextState>>, + state: DOMRefCell<CanvasContextState>, + saved_states: DOMRefCell<Vec<CanvasContextState>>, } #[must_root] @@ -126,8 +126,8 @@ impl CanvasRenderingContext2D { renderer_id: renderer_id, ipc_renderer: ipc_renderer, canvas: JS::from_ref(canvas), - state: RefCell::new(CanvasContextState::new()), - saved_states: RefCell::new(Vec::new()), + state: DOMRefCell::new(CanvasContextState::new()), + saved_states: DOMRefCell::new(Vec::new()), } } @@ -148,7 +148,7 @@ impl CanvasRenderingContext2D { } fn mark_as_dirty(&self) { - self.canvas.root().upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); + self.canvas.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); } fn update_transform(&self) { @@ -290,7 +290,7 @@ impl CanvasRenderingContext2D { let smoothing_enabled = self.state.borrow().image_smoothing_enabled; // If the source and target canvas are the same - let msg = if self.canvas.root().r() == canvas { + let msg = if &*self.canvas == canvas { CanvasMsg::Canvas2d(Canvas2dMsg::DrawImageSelf(image_size, dest_rect, source_rect, smoothing_enabled)) } else { // Source and target canvases are different let context = match canvas.get_or_init_2d_context() { @@ -367,8 +367,7 @@ impl CanvasRenderingContext2D { #[inline] fn request_image_from_cache(&self, url: Url) -> ImageResponse { - let canvas = self.canvas.root(); - let window = window_from_node(canvas.r()); + let window = window_from_node(&*self.canvas); canvas_utils::request_image_from_cache(window.r(), url) } @@ -422,7 +421,7 @@ impl LayoutCanvasRenderingContext2DHelpers for LayoutJS<CanvasRenderingContext2D impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { // https://html.spec.whatwg.org/multipage/#dom-context-2d-canvas fn Canvas(&self) -> Root<HTMLCanvasElement> { - self.canvas.root() + Root::from_ref(&*self.canvas) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-save @@ -764,7 +763,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { StringOrCanvasGradientOrCanvasPattern::eString(result) }, CanvasFillOrStrokeStyle::Gradient(ref gradient) => { - StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient.root()) + StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(Root::from_ref(&*gradient)) }, } } @@ -804,7 +803,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { StringOrCanvasGradientOrCanvasPattern::eString(result) }, CanvasFillOrStrokeStyle::Gradient(ref gradient) => { - StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient.root()) + StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(Root::from_ref(&*gradient)) }, } } @@ -881,7 +880,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { let (sender, receiver) = ipc::channel::<Vec<u8>>().unwrap(); let dest_rect = Rect::new(Point2D::new(sx.to_i32().unwrap(), sy.to_i32().unwrap()), Size2D::new(sw as i32, sh as i32)); - let canvas_size = self.canvas.root().r().get_size(); + let canvas_size = self.canvas.get_size(); let canvas_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64); self.ipc_renderer .send(CanvasMsg::Canvas2d(Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender))) diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index da8dc78878e..c095931a95d 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -60,8 +60,8 @@ impl CSSStyleDeclaration { CSSStyleDeclaration { reflector_: Reflector::new(), owner: JS::from_ref(owner), - pseudo: pseudo, readonly: modification_access == CSSModificationAccess::Readonly, + pseudo: pseudo, } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index cd6ff08b262..3d0f2847cca 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -31,7 +31,7 @@ use dom::customevent::CustomEvent; use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; use dom::domimplementation::DOMImplementation; -use dom::element::{Element, ElementCreator, EventState}; +use dom::element::{Element, ElementCreator}; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::{EventTarget}; use dom::htmlanchorelement::HTMLAnchorElement; @@ -84,10 +84,11 @@ use net_traits::{AsyncResponseTarget, PendingAsyncLoad}; use num::ToPrimitive; use script_task::{MainThreadScriptMsg, Runnable}; use script_traits::{MouseButton, UntrustedNodeAddress}; +use selectors::states::*; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::boxed::FnBox; -use std::cell::{Cell, Ref, RefCell, RefMut}; +use std::cell::{Cell, Ref, RefMut}; use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::default::Default; @@ -161,7 +162,7 @@ pub struct Document { /// https://html.spec.whatwg.org/multipage/#list-of-animation-frame-callbacks /// List of animation frame callbacks #[ignore_heap_size_of = "closures are hard"] - animation_frame_list: RefCell<HashMap<u32, Box<FnBox(f64)>>>, + animation_frame_list: DOMRefCell<HashMap<u32, Box<FnBox(f64)>>>, /// Tracks all outstanding loads related to this document. loader: DOMRefCell<DocumentLoader>, /// The current active HTML parser, to allow resuming after interruptions. @@ -173,8 +174,8 @@ pub struct Document { /// This field is set to the document itself for inert documents. /// https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document appropriate_template_contents_owner_document: MutNullableHeap<JS<Document>>, - // The collection of EventStates that have been changed since the last restyle. - event_state_changes: DOMRefCell<HashMap<JS<Element>, EventState>>, + // The collection of ElementStates that have been changed since the last restyle. + element_state_changes: DOMRefCell<HashMap<JS<Element>, ElementState>>, } impl PartialEq for Document { @@ -304,7 +305,7 @@ impl Document { pub fn needs_reflow(&self) -> bool { self.GetDocumentElement().is_some() && - (self.upcast::<Node>().get_has_dirty_descendants() || !self.event_state_changes.borrow().is_empty()) + (self.upcast::<Node>().get_has_dirty_descendants() || !self.element_state_changes.borrow().is_empty()) } /// Returns the first `base` element in the DOM that has an `href` attribute. @@ -389,8 +390,7 @@ impl Document { None => false, Some(elements) => { let position = elements.iter() - .map(|elem| elem.root()) - .position(|element| element.r() == to_unregister) + .position(|element| &**element == to_unregister) .expect("This element should be in registered."); elements.remove(position); elements.is_empty() @@ -426,7 +426,7 @@ impl Document { let root = root.upcast::<Node>(); for node in root.traverse_preorder() { if let Some(elem) = node.downcast() { - if (*elements)[head].root().r() == elem { + if &*(*elements)[head] == elem { head += 1; } if new_node == node.r() || head == elements.len() { @@ -670,21 +670,19 @@ impl Document { prev_mouse_over_targets: &mut RootedVec<JS<Element>>) { // Build a list of elements that are currently under the mouse. let mouse_over_addresses = self.get_nodes_under_mouse(&point); - let mut mouse_over_targets: RootedVec<JS<Element>> = RootedVec::new(); - for node_address in &mouse_over_addresses { - let node = node::from_untrusted_node_address(js_runtime, *node_address); - mouse_over_targets.push(node.r().inclusive_ancestors() - .find(|node| node.is::<Element>()) - .map(|node| JS::from_ref(node.downcast::<Element>().unwrap())) - .unwrap()); - }; + let mut mouse_over_targets = mouse_over_addresses.iter().map(|node_address| { + node::from_untrusted_node_address(js_runtime, *node_address) + .inclusive_ancestors() + .filter_map(Root::downcast::<Element>) + .next() + .unwrap() + }).collect::<RootedVec<JS<Element>>>(); // Remove hover from any elements in the previous list that are no longer // under the mouse. for target in prev_mouse_over_targets.iter() { if !mouse_over_targets.contains(target) { - let target = target.root(); - let target_ref = target.r(); + let target_ref = &**target; if target_ref.get_hover_state() { target_ref.set_hover_state(false); @@ -747,27 +745,27 @@ impl Document { }, }; let target = el.upcast::<EventTarget>(); - let window = self.window.root(); + let window = &*self.window; let client_x = Finite::wrap(point.x as f64); let client_y = Finite::wrap(point.y as f64); let page_x = Finite::wrap(point.x as f64 + window.PageXOffset() as f64); let page_y = Finite::wrap(point.y as f64 + window.PageYOffset() as f64); - let touch = Touch::new(window.r(), identifier, target, + let touch = Touch::new(window, identifier, target, client_x, client_y, // TODO: Get real screen coordinates? client_x, client_y, page_x, page_y); let mut touches = RootedVec::new(); touches.push(JS::from_rooted(&touch)); - let touches = TouchList::new(window.r(), touches.r()); + let touches = TouchList::new(window, touches.r()); - let event = TouchEvent::new(window.r(), + let event = TouchEvent::new(window, event_name, EventBubbles::Bubbles, EventCancelable::Cancelable, - Some(window.r()), + Some(window), 0i32, &touches, &touches, &touches, // FIXME: modifier keys @@ -775,9 +773,9 @@ impl Document { let event = event.upcast::<Event>(); let result = event.fire(target); - window.r().reflow(ReflowGoal::ForDisplay, - ReflowQueryType::NoQuery, - ReflowReason::MouseEvent); + window.reflow(ReflowGoal::ForDisplay, + ReflowQueryType::NoQuery, + ReflowReason::MouseEvent); result } @@ -1087,13 +1085,15 @@ impl Document { } let mut deferred_scripts = self.deferred_scripts.borrow_mut(); while !deferred_scripts.is_empty() { - let script = deferred_scripts[0].root(); - // Part of substep 1. - if !script.is_ready_to_be_executed() { - return; + { + let script = &*deferred_scripts[0]; + // Part of substep 1. + if !script.is_ready_to_be_executed() { + return; + } + // Substep 2. + script.execute(); } - // Substep 2. - script.execute(); // Substep 3. deferred_scripts.remove(0); // Substep 4 (implicit). @@ -1108,7 +1108,7 @@ impl Document { // Execute the first in-order asap-executed script if it's ready, repeat as required. // Re-borrowing the list for each step because it can also be borrowed under execute. while self.asap_in_order_scripts_list.borrow().len() > 0 { - let script = self.asap_in_order_scripts_list.borrow()[0].root(); + let script = Root::from_ref(&*self.asap_in_order_scripts_list.borrow()[0]); if !script.r().is_ready_to_be_executed() { break; } @@ -1119,7 +1119,7 @@ impl Document { let mut idx = 0; // Re-borrowing the set for each step because it can also be borrowed under execute. while idx < self.asap_scripts_set.borrow().len() { - let script = self.asap_scripts_set.borrow()[idx].root(); + let script = Root::from_ref(&*self.asap_scripts_set.borrow()[idx]); if !script.r().is_ready_to_be_executed() { idx += 1; continue; @@ -1184,7 +1184,7 @@ pub enum DocumentSource { #[allow(unsafe_code)] pub trait LayoutDocumentHelpers { unsafe fn is_html_document_for_layout(&self) -> bool; - unsafe fn drain_event_state_changes(&self) -> Vec<(LayoutJS<Element>, EventState)>; + unsafe fn drain_element_state_changes(&self) -> Vec<(LayoutJS<Element>, ElementState)>; } #[allow(unsafe_code)] @@ -1196,8 +1196,8 @@ impl LayoutDocumentHelpers for LayoutJS<Document> { #[inline] #[allow(unrooted_must_root)] - unsafe fn drain_event_state_changes(&self) -> Vec<(LayoutJS<Element>, EventState)> { - let mut changes = (*self.unsafe_get()).event_state_changes.borrow_mut_for_layout(); + unsafe fn drain_element_state_changes(&self) -> Vec<(LayoutJS<Element>, ElementState)> { + let mut changes = (*self.unsafe_get()).element_state_changes.borrow_mut_for_layout(); let drain = changes.drain(); let layout_drain = drain.map(|(k, v)| (k.to_layout(), v)); Vec::from_iter(layout_drain) @@ -1261,13 +1261,13 @@ impl Document { asap_scripts_set: DOMRefCell::new(vec!()), scripting_enabled: Cell::new(true), animation_frame_ident: Cell::new(0), - animation_frame_list: RefCell::new(HashMap::new()), + animation_frame_list: DOMRefCell::new(HashMap::new()), loader: DOMRefCell::new(doc_loader), current_parser: Default::default(), reflow_timeout: Cell::new(None), base_element: Default::default(), appropriate_template_contents_owner_document: Default::default(), - event_state_changes: DOMRefCell::new(HashMap::new()), + element_state_changes: DOMRefCell::new(HashMap::new()), } } @@ -1330,15 +1330,15 @@ impl Document { } pub fn get_element_by_id(&self, id: &Atom) -> Option<Root<Element>> { - self.idmap.borrow().get(&id).map(|ref elements| (*elements)[0].root()) + self.idmap.borrow().get(&id).map(|ref elements| Root::from_ref(&*(*elements)[0])) } - pub fn record_event_state_change(&self, el: &Element, which: EventState) { - let mut map = self.event_state_changes.borrow_mut(); + pub fn record_element_state_change(&self, el: &Element, which: ElementState) { + let mut map = self.element_state_changes.borrow_mut(); let empty; { let states = map.entry(JS::from_ref(el)) - .or_insert(EventState::empty()); + .or_insert(ElementState::empty()); states.toggle(which); empty = states.is_empty(); } @@ -1923,7 +1923,7 @@ impl DocumentMethods for Document { // https://html.spec.whatwg.org/multipage/#dom-document-defaultview fn DefaultView(&self) -> Root<Window> { - self.window.root() + Root::from_ref(&*self.window) } // https://html.spec.whatwg.org/multipage/#dom-document-cookie diff --git a/components/script/dom/domrectlist.rs b/components/script/dom/domrectlist.rs index 1c9c92ca3e3..cd5bc11b25e 100644 --- a/components/script/dom/domrectlist.rs +++ b/components/script/dom/domrectlist.rs @@ -42,7 +42,7 @@ impl DOMRectListMethods for DOMRectList { fn Item(&self, index: u32) -> Option<Root<DOMRect>> { let rects = &self.rects; if index < rects.len() as u32 { - Some(rects[index as usize].root()) + Some(Root::from_ref(&*rects[index as usize])) } else { None } diff --git a/components/script/dom/domstringmap.rs b/components/script/dom/domstringmap.rs index 49b7d0f6cf8..b27f0eca4e0 100644 --- a/components/script/dom/domstringmap.rs +++ b/components/script/dom/domstringmap.rs @@ -61,7 +61,6 @@ impl DOMStringMapMethods for DOMStringMap { // https://html.spec.whatwg.org/multipage/#the-domstringmap-interface:supported-property-names fn SupportedPropertyNames(&self) -> Vec<DOMString> { - // FIXME: unimplemented (https://github.com/servo/servo/issues/7273) - vec![] + self.element.supported_prop_names_custom_attr().iter().cloned().collect() } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 67844b9231b..779b802fc26 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -19,12 +19,14 @@ use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementM use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId, NodeTypeId}; use dom::bindings::codegen::UnionTypes::NodeOrString; use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::global::GlobalRef; use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId}; use dom::bindings::js::{JS, LayoutJS, MutNullableHeap}; use dom::bindings::js::{Root, RootedReference}; +use dom::bindings::trace::JSTraceable; use dom::bindings::xmlname::XMLName::InvalidXMLName; use dom::bindings::xmlname::{namespace_from_domstring, validate_and_extract, xml_name_type}; use dom::characterdata::CharacterData; @@ -40,7 +42,8 @@ use dom::htmlcollection::HTMLCollection; use dom::htmlfieldsetelement::HTMLFieldSetElement; use dom::htmlfontelement::HTMLFontElement; use dom::htmliframeelement::HTMLIFrameElement; -use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers}; +use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers}; +use dom::htmllabelelement::HTMLLabelElement; use dom::htmllegendelement::HTMLLegendElement; use dom::htmloptgroupelement::HTMLOptGroupElement; use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementLayoutHelpers}; @@ -62,8 +65,8 @@ use html5ever::serialize::TraversalScope; use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode}; use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks}; use selectors::matching::{DeclarationBlock, matches}; -use selectors::parser::parse_author_origin_selector_list_from_str; -use selectors::parser::{AttrSelector, NamespaceConstraint}; +use selectors::parser::{AttrSelector, NamespaceConstraint, parse_author_origin_selector_list_from_str}; +use selectors::states::*; use smallvec::VecLike; use std::ascii::AsciiExt; use std::borrow::{Cow, ToOwned}; @@ -77,28 +80,14 @@ use style::properties::DeclaredValue; use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute}; use style::values::CSSFloat; -use style::values::specified::{self, CSSColor, CSSRGBA}; +use style::values::specified::{self, CSSColor, CSSRGBA, LengthOrPercentage}; use url::UrlParser; +use util::mem::HeapSizeOf; use util::str::{DOMString, LengthOrPercentageOrAuto}; -bitflags! { - #[doc = "Element Event States."] - #[derive(JSTraceable, HeapSizeOf)] - flags EventState: u8 { - #[doc = "The mouse is down on this element. \ - (https://html.spec.whatwg.org/multipage/#selector-active). \ - FIXME(#7333): set/unset this when appropriate"] - const IN_ACTIVE_STATE = 0x01, - #[doc = "This element has focus."] - const IN_FOCUS_STATE = 0x02, - #[doc = "The mouse is hovering over this element."] - const IN_HOVER_STATE = 0x04, - #[doc = "Content is enabled (and can be disabled)."] - const IN_ENABLED_STATE = 0x08, - #[doc = "Content is disabled."] - const IN_DISABLED_STATE = 0x10, - } -} +// TODO: Update focus state when the top-level browsing context gains or loses system focus, +// and when the element enters or leaves a browsing context container. +// https://html.spec.whatwg.org/multipage/#selector-focus #[dom_struct] pub struct Element { @@ -111,7 +100,7 @@ pub struct Element { style_attribute: DOMRefCell<Option<PropertyDeclarationBlock>>, attr_list: MutNullableHeap<JS<NamedNodeMap>>, class_list: MutNullableHeap<JS<DOMTokenList>>, - event_state: Cell<EventState>, + state: Cell<ElementState>, } impl PartialEq for Element { @@ -140,11 +129,11 @@ impl Element { pub fn new_inherited(local_name: DOMString, namespace: Namespace, prefix: Option<DOMString>, document: &Document) -> Element { - Element::new_inherited_with_state(EventState::empty(), local_name, + Element::new_inherited_with_state(ElementState::empty(), local_name, namespace, prefix, document) } - pub fn new_inherited_with_state(state: EventState, local_name: DOMString, + pub fn new_inherited_with_state(state: ElementState, local_name: DOMString, namespace: Namespace, prefix: Option<DOMString>, document: &Document) -> Element { @@ -154,11 +143,11 @@ impl Element { namespace: namespace, prefix: prefix, attrs: DOMRefCell::new(vec!()), - attr_list: Default::default(), - class_list: Default::default(), id_attribute: DOMRefCell::new(None), style_attribute: DOMRefCell::new(None), - event_state: Cell::new(state), + attr_list: Default::default(), + class_list: Default::default(), + state: Cell::new(state), } } @@ -188,7 +177,7 @@ pub unsafe fn get_attr_for_layout<'a>(elem: &'a Element, namespace: &Namespace, -> Option<LayoutJS<Attr>> { // cast to point to T in RefCell<T> directly let attrs = elem.attrs.borrow_for_layout(); - attrs.iter().find(|attr: & &JS<Attr>| { + attrs.iter().find(|attr| { let attr = attr.to_layout(); *name == attr.local_name_atom_forever() && (*attr.unsafe_get()).namespace() == namespace @@ -215,7 +204,7 @@ impl RawLayoutElementHelpers for Element { #[inline] unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &Atom) -> Vec<&'a str> { let attrs = self.attrs.borrow_for_layout(); - (*attrs).iter().filter_map(|attr: &JS<Attr>| { + attrs.iter().filter_map(|attr| { let attr = attr.to_layout(); if *name == attr.local_name_atom_forever() { Some(attr.value_ref_forever()) @@ -251,7 +240,7 @@ pub trait LayoutElementHelpers { fn get_checked_state_for_layout(&self) -> bool; fn get_indeterminate_state_for_layout(&self) -> bool; - fn get_event_state_for_layout(&self) -> EventState; + fn get_state_for_layout(&self) -> ElementState; } impl LayoutElementHelpers for LayoutJS<Element> { @@ -358,7 +347,8 @@ impl LayoutElementHelpers for LayoutJS<Element> { hints.push(from_declaration( PropertyDeclaration::FontSize( DeclaredValue::Value( - font_size::SpecifiedValue(font_size))))) + font_size::SpecifiedValue( + LengthOrPercentage::Length(font_size)))))) } let cellspacing = if let Some(this) = self.downcast::<HTMLTableElement>() { @@ -384,7 +374,7 @@ impl LayoutElementHelpers for LayoutJS<Element> { // a text field match (*self.unsafe_get()).get_attr_val_for_layout(&ns!(""), &atom!("type")) { Some("text") | Some("password") => { - match (*this.unsafe_get()).get_size_for_layout() { + match this.get_size_for_layout() { 0 => None, s => Some(s as i32), } @@ -584,7 +574,7 @@ impl LayoutElementHelpers for LayoutJS<Element> { // TODO option and menuitem can also have a checked state. match self.downcast::<HTMLInputElement>() { Some(input) => unsafe { - (*input.unsafe_get()).get_checked_state_for_layout() + input.get_checked_state_for_layout() }, None => false, } @@ -596,7 +586,7 @@ impl LayoutElementHelpers for LayoutJS<Element> { // TODO progress elements can also be matched with :indeterminate match self.downcast::<HTMLInputElement>() { Some(input) => unsafe { - (*input.unsafe_get()).get_indeterminate_state_for_layout() + input.get_indeterminate_state_for_layout() }, None => false, } @@ -604,9 +594,9 @@ impl LayoutElementHelpers for LayoutJS<Element> { #[inline] #[allow(unsafe_code)] - fn get_event_state_for_layout(&self) -> EventState { + fn get_state_for_layout(&self) -> ElementState { unsafe { - (*self.unsafe_get()).event_state.get() + (*self.unsafe_get()).state.get() } } } @@ -886,16 +876,15 @@ impl Element { } pub fn get_attribute(&self, namespace: &Namespace, local_name: &Atom) -> Option<Root<Attr>> { - self.attrs.borrow().iter().map(JS::root).find(|attr| { + self.attrs.borrow().iter().find(|attr| { attr.local_name() == local_name && attr.namespace() == namespace - }) + }).map(|js| Root::from_ref(&**js)) } // https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name pub fn get_attribute_by_name(&self, name: DOMString) -> Option<Root<Attr>> { let name = &self.parsed_name(name); - self.attrs.borrow().iter().map(JS::root) - .find(|a| a.r().name() == name) + self.attrs.borrow().iter().find(|a| a.name() == name).map(|js| Root::from_ref(&**js)) } pub fn set_attribute_from_parser(&self, @@ -903,8 +892,8 @@ impl Element { value: DOMString, prefix: Option<Atom>) { // Don't set if the attribute already exists, so we can handle add_attrs_if_missing - if self.attrs.borrow().iter().map(JS::root) - .any(|a| *a.r().local_name() == qname.local && *a.r().namespace() == qname.ns) { + if self.attrs.borrow().iter() + .any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns) { return; } @@ -954,7 +943,8 @@ impl Element { find: F) where F: Fn(&Attr) -> bool { - let attr = self.attrs.borrow().iter().map(JS::root).find(|attr| find(&attr)); + let attr = self.attrs.borrow().iter() + .find(|attr| find(&attr)).map(|js| Root::from_ref(&**js)); if let Some(attr) = attr { attr.set_value(value, self); } else { @@ -985,10 +975,10 @@ impl Element { fn remove_first_matching_attribute<F>(&self, find: F) -> Option<Root<Attr>> where F: Fn(&Attr) -> bool { - let idx = self.attrs.borrow().iter().map(JS::root).position(|attr| find(&attr)); + let idx = self.attrs.borrow().iter().position(|attr| find(&attr)); idx.map(|idx| { - let attr = (*self.attrs.borrow())[idx].root(); + let attr = Root::from_ref(&*(*self.attrs.borrow())[idx]); self.attrs.borrow_mut().remove(idx); attr.set_owner(None); if attr.namespace() == &ns!("") { @@ -1017,8 +1007,8 @@ impl Element { pub fn has_attribute(&self, local_name: &Atom) -> bool { assert!(local_name.bytes().all(|b| b.to_ascii_lowercase() == b)); - self.attrs.borrow().iter().map(JS::root).any(|attr| { - attr.r().local_name() == local_name && attr.r().namespace() == &ns!("") + self.attrs.borrow().iter().any(|attr| { + attr.local_name() == local_name && attr.namespace() == &ns!("") }) } @@ -1582,6 +1572,16 @@ impl VirtualMethods for Element { } } +macro_rules! state_getter { + ($( + $(#[$Flag_attr: meta])* + state $css: expr => $variant: ident / $method: ident / + $flag: ident = $value: expr, + )+) => { + $( fn $method(&self) -> bool { Element::get_state(self).contains($flag) } )+ + } +} + impl<'a> ::selectors::Element for Root<Element> { fn parent_element(&self) -> Option<Root<Element>> { self.upcast::<Node>().GetParentElement() @@ -1648,42 +1648,11 @@ impl<'a> ::selectors::Element for Root<Element> { self.namespace() } - fn get_hover_state(&self) -> bool { - Element::get_hover_state(self) - } - - fn get_active_state(&self) -> bool { - Element::get_active_state(self) - } - - fn get_focus_state(&self) -> bool { - // TODO: Also check whether the top-level browsing context has the system focus, - // and whether this element is a browsing context container. - // https://html.spec.whatwg.org/multipage/#selector-focus - Element::get_focus_state(self) - } + state_pseudo_classes!(state_getter); fn get_id(&self) -> Option<Atom> { self.id_attribute.borrow().clone() } - fn get_disabled_state(&self) -> bool { - Element::get_disabled_state(self) - } - fn get_enabled_state(&self) -> bool { - Element::get_enabled_state(self) - } - fn get_checked_state(&self) -> bool { - match self.downcast::<HTMLInputElement>() { - Some(input) => input.Checked(), - None => false, - } - } - fn get_indeterminate_state(&self) -> bool { - match self.downcast::<HTMLInputElement>() { - Some(input) => input.get_indeterminate_state(), - None => false, - } - } fn has_class(&self, name: &Atom) -> bool { Element::has_class(&**self, name) } @@ -1728,8 +1697,8 @@ impl<'a> ::selectors::Element for Root<Element> { }) }, NamespaceConstraint::Any => { - self.attrs.borrow().iter().map(JS::root).any(|attr| { - attr.local_name() == local_name && test(&attr.value()) + self.attrs.borrow().iter().any(|attr| { + attr.local_name() == local_name && test(&attr.value()) }) } } @@ -1752,6 +1721,10 @@ impl Element { let element = self.downcast::<HTMLAnchorElement>().unwrap(); Some(element as &Activatable) }, + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLabelElement)) => { + let element = self.downcast::<HTMLLabelElement>().unwrap(); + Some(element as &Activatable) + }, _ => { None } @@ -1833,8 +1806,12 @@ impl Element { self.set_click_in_progress(false); } - fn set_state(&self, which: EventState, value: bool) { - let mut state = self.event_state.get(); + pub fn get_state(&self) -> ElementState { + self.state.get() + } + + pub fn set_state(&self, which: ElementState, value: bool) { + let mut state = self.state.get(); if state.contains(which) == value { return } @@ -1842,14 +1819,14 @@ impl Element { true => state.insert(which), false => state.remove(which), }; - self.event_state.set(state); + self.state.set(state); let node = self.upcast::<Node>(); - node.owner_doc().record_event_state_change(self, which); + node.owner_doc().record_element_state_change(self, which); } pub fn get_active_state(&self) -> bool { - self.event_state.get().contains(IN_ACTIVE_STATE) + self.state.get().contains(IN_ACTIVE_STATE) } pub fn set_active_state(&self, value: bool) { @@ -1857,7 +1834,7 @@ impl Element { } pub fn get_focus_state(&self) -> bool { - self.event_state.get().contains(IN_FOCUS_STATE) + self.state.get().contains(IN_FOCUS_STATE) } pub fn set_focus_state(&self, value: bool) { @@ -1865,7 +1842,7 @@ impl Element { } pub fn get_hover_state(&self) -> bool { - self.event_state.get().contains(IN_HOVER_STATE) + self.state.get().contains(IN_HOVER_STATE) } pub fn set_hover_state(&self, value: bool) { @@ -1873,7 +1850,7 @@ impl Element { } pub fn get_enabled_state(&self) -> bool { - self.event_state.get().contains(IN_ENABLED_STATE) + self.state.get().contains(IN_ENABLED_STATE) } pub fn set_enabled_state(&self, value: bool) { @@ -1881,7 +1858,7 @@ impl Element { } pub fn get_disabled_state(&self) -> bool { - self.event_state.get().contains(IN_DISABLED_STATE) + self.state.get().contains(IN_DISABLED_STATE) } pub fn set_disabled_state(&self, value: bool) { diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs index 34db84f561c..c0a6a9a19aa 100644 --- a/components/script/dom/event.rs +++ b/components/script/dom/event.rs @@ -13,6 +13,7 @@ use dom::eventtarget::EventTarget; use std::borrow::ToOwned; use std::cell::Cell; use std::default::Default; +use string_cache::Atom; use time; use util::str::DOMString; @@ -43,7 +44,7 @@ pub struct Event { reflector_: Reflector, current_target: MutNullableHeap<JS<EventTarget>>, target: MutNullableHeap<JS<EventTarget>>, - type_: DOMRefCell<DOMString>, + type_: DOMRefCell<Atom>, phase: Cell<EventPhase>, canceled: Cell<bool>, stop_propagation: Cell<bool>, @@ -62,15 +63,15 @@ impl Event { reflector_: Reflector::new(), current_target: Default::default(), target: Default::default(), + type_: DOMRefCell::new(atom!("")), phase: Cell::new(EventPhase::None), - type_: DOMRefCell::new("".to_owned()), canceled: Cell::new(false), + stop_propagation: Cell::new(false), + stop_immediate: Cell::new(false), cancelable: Cell::new(false), bubbles: Cell::new(false), trusted: Cell::new(false), dispatching: Cell::new(false), - stop_propagation: Cell::new(false), - stop_immediate: Cell::new(false), initialized: Cell::new(false), timestamp: time::get_time().sec as u64, } @@ -153,6 +154,11 @@ impl Event { pub fn initialized(&self) -> bool { self.initialized.get() } + + #[inline] + pub fn type_(&self) -> Atom { + self.type_.borrow().clone() + } } impl EventMethods for Event { @@ -163,7 +169,7 @@ impl EventMethods for Event { // https://dom.spec.whatwg.org/#dom-event-type fn Type(&self) -> DOMString { - self.type_.borrow().clone() + (*self.type_()).to_owned() } // https://dom.spec.whatwg.org/#dom-event-target @@ -229,7 +235,7 @@ impl EventMethods for Event { self.canceled.set(false); self.trusted.set(false); self.target.set(None); - *self.type_.borrow_mut() = type_; + *self.type_.borrow_mut() = Atom::from_slice(&type_); self.bubbles.set(bubbles); self.cancelable.set(cancelable); } diff --git a/components/script/dom/eventdispatcher.rs b/components/script/dom/eventdispatcher.rs index 9faf31c6be6..589d5a53f8b 100644 --- a/components/script/dom/eventdispatcher.rs +++ b/components/script/dom/eventdispatcher.rs @@ -60,7 +60,7 @@ fn dispatch_to_listeners(event: &Event, target: &EventTarget, chain: &[&EventTar _ => None, }; - let type_ = event.Type(); + let type_ = event.type_(); /* capturing */ event.set_phase(EventPhase::Capturing); diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index 161e2315b3b..84f59d8c498 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -19,7 +19,6 @@ use js::jsapi::{HandleObject, JSContext, RootedFunction}; use js::jsapi::{JSAutoCompartment, JSAutoRequest}; use js::rust::{AutoObjectVectorWrapper, CompileOptionsWrapper}; use libc::{c_char, size_t}; -use std::borrow::ToOwned; use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_state::DefaultState; @@ -27,6 +26,7 @@ use std::default::Default; use std::ffi::CString; use std::rc::Rc; use std::{intrinsics, ptr}; +use string_cache::Atom; use url::Url; use util::mem::HeapSizeOf; use util::str::DOMString; @@ -114,7 +114,7 @@ pub struct EventListenerEntry { #[dom_struct] pub struct EventTarget { reflector_: Reflector, - handlers: DOMRefCell<HashMap<DOMString, Vec<EventListenerEntry>, DefaultState<FnvHasher>>>, + handlers: DOMRefCell<HashMap<Atom, Vec<EventListenerEntry>, DefaultState<FnvHasher>>>, } impl EventTarget { @@ -125,13 +125,13 @@ impl EventTarget { } } - pub fn get_listeners(&self, type_: &str) -> Option<Vec<EventListenerType>> { + pub fn get_listeners(&self, type_: &Atom) -> Option<Vec<EventListenerType>> { self.handlers.borrow().get(type_).map(|listeners| { listeners.iter().map(|entry| entry.listener.clone()).collect() }) } - pub fn get_listeners_for(&self, type_: &str, desired_phase: ListenerPhase) + pub fn get_listeners_for(&self, type_: &Atom, desired_phase: ListenerPhase) -> Option<Vec<EventListenerType>> { self.handlers.borrow().get(type_).map(|listeners| { let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase); @@ -150,8 +150,8 @@ impl EventTarget { } pub fn set_inline_event_listener(&self, - ty: DOMString, - listener: Option<Rc<EventHandler>>) { + ty: Atom, + listener: Option<Rc<EventHandler>>) { let mut handlers = self.handlers.borrow_mut(); let entries = match handlers.entry(ty) { Occupied(entry) => entry.into_mut(), @@ -185,9 +185,9 @@ impl EventTarget { } } - pub fn get_inline_event_listener(&self, ty: DOMString) -> Option<Rc<EventHandler>> { + pub fn get_inline_event_listener(&self, ty: &Atom) -> Option<Rc<EventHandler>> { let handlers = self.handlers.borrow(); - let entries = handlers.get(&ty); + let entries = handlers.get(ty); entries.and_then(|entries| entries.iter().filter_map(|entry| { match entry.listener { EventListenerType::Inline(ref handler) => Some(handler.clone()), @@ -243,11 +243,11 @@ impl EventTarget { { let event_listener = listener.map(|listener| EventHandlerNonNull::new(listener.callback())); - self.set_inline_event_listener(ty.to_owned(), event_listener); + self.set_inline_event_listener(Atom::from_slice(ty), event_listener); } pub fn get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<Rc<T>> { - let listener = self.get_inline_event_listener(ty.to_owned()); + let listener = self.get_inline_event_listener(&Atom::from_slice(ty)); listener.map(|listener| CallbackContainer::new(listener.parent.callback())) } @@ -265,7 +265,7 @@ impl EventTargetMethods for EventTarget { match listener { Some(listener) => { let mut handlers = self.handlers.borrow_mut(); - let entry = match handlers.entry(ty) { + let entry = match handlers.entry(Atom::from_slice(&ty)) { Occupied(entry) => entry.into_mut(), Vacant(entry) => entry.insert(vec!()), }; @@ -291,7 +291,7 @@ impl EventTargetMethods for EventTarget { match listener { Some(ref listener) => { let mut handlers = self.handlers.borrow_mut(); - let entry = handlers.get_mut(&ty); + let entry = handlers.get_mut(&Atom::from_slice(&ty)); for entry in entry { let phase = if capture { ListenerPhase::Capturing } else { ListenerPhase::Bubbling }; let old_entry = EventListenerEntry { diff --git a/components/script/dom/filelist.rs b/components/script/dom/filelist.rs index bed3d451b94..e60258fa330 100644 --- a/components/script/dom/filelist.rs +++ b/components/script/dom/filelist.rs @@ -40,7 +40,7 @@ impl FileListMethods for FileList { // https://w3c.github.io/FileAPI/#dfn-item fn Item(&self, index: u32) -> Option<Root<File>> { - Some(self.list[index as usize].root()) + Some(Root::from_ref(&*(self.list[index as usize]))) } // check-tidy: no specs after this line diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs index 8003208e5b2..e01c91def32 100644 --- a/components/script/dom/filereader.rs +++ b/components/script/dom/filereader.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::FileReaderBinding::{self, FileReaderConstants, FileReaderMethods}; @@ -23,7 +24,7 @@ use hyper::mime::{Attr, Mime}; use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64}; use script_task::ScriptTaskEventCategory::FileRead; use script_task::{CommonScriptMsg, Runnable, ScriptChan, ScriptPort}; -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use std::sync::mpsc; use std::sync::mpsc::Receiver; use util::str::DOMString; @@ -72,7 +73,7 @@ pub struct FileReader { global: GlobalField, ready_state: Cell<FileReaderReadyState>, error: MutNullableHeap<JS<DOMException>>, - result: RefCell<Option<DOMString>>, + result: DOMRefCell<Option<DOMString>>, generation_id: Cell<GenerationId>, } @@ -83,7 +84,7 @@ impl FileReader { global: GlobalField::from_rooted(&global), ready_state: Cell::new(FileReaderReadyState::Empty), error: MutNullableHeap::new(None), - result: RefCell::new(None), + result: DOMRefCell::new(None), generation_id: Cell::new(GenerationId(0)), } } diff --git a/components/script/dom/formdata.rs b/components/script/dom/formdata.rs index 27ba8ff4f0a..d37bbbc738e 100644 --- a/components/script/dom/formdata.rs +++ b/components/script/dom/formdata.rs @@ -90,7 +90,7 @@ impl FormDataMethods for FormData { .get(&name) .map(|entry| match entry[0] { FormDatum::StringData(ref s) => eString(s.clone()), - FormDatum::FileData(ref f) => eFile(f.root()), + FormDatum::FileData(ref f) => eFile(Root::from_ref(&*f)), }) } diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index 4ecb3d00225..b980e93dc5e 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -70,7 +70,7 @@ impl HTMLBodyElementMethods for HTMLBodyElement { fn SetText(&self, value: DOMString) { let element = self.upcast::<Element>(); let color = str::parse_legacy_color(&value).ok(); - element.set_attribute(&Atom::from_slice("text"), AttrValue::Color(value, color)); + element.set_attribute(&atom!("text"), AttrValue::Color(value, color)); } // https://html.spec.whatwg.org/multipage/#the-body-element diff --git a/components/script/dom/htmlbuttonelement.rs b/components/script/dom/htmlbuttonelement.rs index 5937f36d3dc..f42b6f307ad 100644 --- a/components/script/dom/htmlbuttonelement.rs +++ b/components/script/dom/htmlbuttonelement.rs @@ -9,7 +9,7 @@ use dom::bindings::codegen::Bindings::HTMLButtonElementBinding::HTMLButtonElemen use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::document::Document; -use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE}; +use dom::element::{AttributeMutation, Element}; use dom::event::Event; use dom::eventtarget::EventTarget; use dom::htmlelement::HTMLElement; @@ -17,8 +17,10 @@ use dom::htmlfieldsetelement::HTMLFieldSetElement; use dom::htmlformelement::{FormControl, FormSubmitter}; use dom::htmlformelement::{SubmittedFrom, HTMLFormElement}; use dom::node::{Node, document_from_node, window_from_node}; +use dom::nodelist::NodeList; use dom::validitystate::ValidityState; use dom::virtualmethods::VirtualMethods; +use selectors::states::*; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::Cell; @@ -81,15 +83,7 @@ impl HTMLButtonElementMethods for HTMLButtonElement { } // https://html.spec.whatwg.org/multipage/#dom-button-type - fn Type(&self) -> DOMString { - let mut ty = self.upcast::<Element>().get_string_attribute(&atom!("type")); - ty.make_ascii_lowercase(); - // https://html.spec.whatwg.org/multipage/#attr-button-type - match &*ty { - "reset" | "button" | "menu" => ty, - _ => "submit".to_owned() - } - } + make_enumerated_getter!(Type, "submit", ("reset") | ("button") | ("menu")); // https://html.spec.whatwg.org/multipage/#dom-button-type make_setter!(SetType, "type"); @@ -130,6 +124,11 @@ impl HTMLButtonElementMethods for HTMLButtonElement { // https://html.spec.whatwg.org/multipage/#dom-button-value make_setter!(SetValue, "value"); + + // https://html.spec.whatwg.org/multipage/#dom-lfe-labels + fn Labels(&self) -> Root<NodeList> { + self.upcast::<HTMLElement>().labels() + } } impl VirtualMethods for HTMLButtonElement { diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 51bc5536a3f..786ce9eaa16 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -153,7 +153,7 @@ impl HTMLCanvasElement { } match *self.context.borrow().as_ref().unwrap() { - CanvasContext::Context2d(ref context) => Some(context.root()), + CanvasContext::Context2d(ref context) => Some(Root::from_ref(&*context)), _ => None, } } @@ -182,7 +182,7 @@ impl HTMLCanvasElement { } if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() { - Some(context.root()) + Some(Root::from_ref(&*context)) } else { None } diff --git a/components/script/dom/htmlcollection.rs b/components/script/dom/htmlcollection.rs index b0949ea64e7..28cc9635052 100644 --- a/components/script/dom/htmlcollection.rs +++ b/components/script/dom/htmlcollection.rs @@ -165,7 +165,7 @@ impl HTMLCollection { pub fn elements_iter(&self) -> HTMLCollectionElementsIter { let ref filter = self.collection.1; - let root = self.collection.0.root(); + let root = Root::from_ref(&*self.collection.0); let mut node_iter = root.traverse_preorder(); let _ = node_iter.next(); // skip the root node HTMLCollectionElementsIter { diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 8836d3aae69..43c319678c9 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -4,6 +4,7 @@ use dom::attr::Attr; use dom::attr::AttrValue; +use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::HTMLElementBinding; use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods; @@ -12,21 +13,25 @@ use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::error::{Error, ErrorResult}; use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::{ElementTypeId, HTMLElementTypeId, NodeTypeId}; -use dom::bindings::js::{JS, MutNullableHeap, Root}; +use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference}; use dom::bindings::reflector::Reflectable; use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration}; use dom::document::Document; use dom::domstringmap::DOMStringMap; -use dom::element::{AttributeMutation, Element, EventState}; +use dom::element::{AttributeMutation, Element}; use dom::eventtarget::EventTarget; use dom::htmlbodyelement::HTMLBodyElement; use dom::htmlframesetelement::HTMLFrameSetElement; use dom::htmlhtmlelement::HTMLHtmlElement; use dom::htmlinputelement::HTMLInputElement; +use dom::htmllabelelement::HTMLLabelElement; use dom::node::{Node, SEQUENTIALLY_FOCUSABLE}; use dom::node::{document_from_node, window_from_node}; +use dom::nodelist::NodeList; use dom::virtualmethods::VirtualMethods; use msg::constellation_msg::FocusType; +use selectors::states::*; +use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::default::Default; use std::intrinsics; @@ -50,10 +55,10 @@ impl PartialEq for HTMLElement { impl HTMLElement { pub fn new_inherited(tag_name: DOMString, prefix: Option<DOMString>, document: &Document) -> HTMLElement { - HTMLElement::new_inherited_with_state(EventState::empty(), tag_name, prefix, document) + HTMLElement::new_inherited_with_state(ElementState::empty(), tag_name, prefix, document) } - pub fn new_inherited_with_state(state: EventState, tag_name: DOMString, + pub fn new_inherited_with_state(state: ElementState, tag_name: DOMString, prefix: Option<DOMString>, document: &Document) -> HTMLElement { HTMLElement { @@ -275,6 +280,45 @@ fn to_snake_case(name: DOMString) -> DOMString { attr_name } + +// https://html.spec.whatwg.org/multipage/#attr-data-* +// if this attribute is in snake case with a data- prefix, +// this function returns a name converted to camel case +// without the data prefix. + +fn to_camel_case(name: &str) -> Option<DOMString> { + if !name.starts_with("data-") { + return None; + } + let name = &name[5..]; + let has_uppercase = name.chars().any(|curr_char| { + curr_char.is_ascii() && curr_char.is_uppercase() + }); + if has_uppercase { + return None; + } + let mut result = "".to_owned(); + let mut name_chars = name.chars(); + while let Some(curr_char) = name_chars.next() { + //check for hyphen followed by character + if curr_char == '\x2d' { + if let Some(next_char) = name_chars.next() { + if next_char.is_ascii() && next_char.is_lowercase() { + result.push(next_char.to_ascii_uppercase()); + } else { + result.push(curr_char); + result.push(next_char); + } + } else { + result.push(curr_char); + } + } else { + result.push(curr_char); + } + } + Some(result) +} + impl HTMLElement { pub fn set_custom_attr(&self, name: DOMString, value: DOMString) -> ErrorResult { if name.chars() @@ -316,6 +360,53 @@ impl HTMLElement { _ => false, } } + + pub fn supported_prop_names_custom_attr(&self) -> Vec<DOMString> { + let element = self.upcast::<Element>(); + element.attrs().iter().filter_map(|attr| { + let raw_name = attr.local_name(); + to_camel_case(&raw_name) + }).collect() + } + + // https://html.spec.whatwg.org/multipage/#dom-lfe-labels + pub fn labels(&self) -> Root<NodeList> { + debug_assert!(self.is_labelable_element()); + + let element = self.upcast::<Element>(); + let window = window_from_node(element); + + // Traverse ancestors for implicitly associated <label> elements + // https://html.spec.whatwg.org/multipage/#the-label-element:attr-label-for-4 + let ancestors = + self.upcast::<Node>() + .ancestors() + .filter_map(Root::downcast::<HTMLElement>) + // If we reach a labelable element, we have a guarantee no ancestors above it + // will be a label for this HTMLElement + .take_while(|elem| !elem.is_labelable_element()) + .filter_map(Root::downcast::<HTMLLabelElement>) + .filter(|elem| !elem.upcast::<Element>().has_attribute(&atom!("for"))) + .filter(|elem| elem.first_labelable_descendant().r() == Some(self)) + .map(Root::upcast::<Node>); + + let id = element.Id(); + let id = match &id as &str { + "" => return NodeList::new_simple_list(window.r(), ancestors), + id => id, + }; + + // Traverse entire tree for <label> elements with `for` attribute matching `id` + let root_element = element.get_root_element(); + let root_node = root_element.upcast::<Node>(); + let children = root_node.traverse_preorder() + .filter_map(Root::downcast::<Element>) + .filter(|elem| elem.is::<HTMLLabelElement>()) + .filter(|elem| elem.get_string_attribute(&atom!("for")) == id) + .map(Root::upcast::<Node>); + + NodeList::new_simple_list(window.r(), children.chain(ancestors)) + } } impl VirtualMethods for HTMLElement { diff --git a/components/script/dom/htmlfieldsetelement.rs b/components/script/dom/htmlfieldsetelement.rs index d516a647055..db3845da73a 100644 --- a/components/script/dom/htmlfieldsetelement.rs +++ b/components/script/dom/htmlfieldsetelement.rs @@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::HTMLFieldSetElementBinding::HTMLFieldSetEl use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId}; use dom::bindings::js::{Root, RootedReference}; use dom::document::Document; -use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE}; +use dom::element::{AttributeMutation, Element}; use dom::htmlcollection::{CollectionFilter, HTMLCollection}; use dom::htmlelement::HTMLElement; use dom::htmlformelement::{FormControl, HTMLFormElement}; @@ -16,6 +16,7 @@ use dom::htmllegendelement::HTMLLegendElement; use dom::node::{Node, window_from_node}; use dom::validitystate::ValidityState; use dom::virtualmethods::VirtualMethods; +use selectors::states::*; use util::str::{DOMString, StaticStringVec}; #[dom_struct] diff --git a/components/script/dom/htmlfontelement.rs b/components/script/dom/htmlfontelement.rs index 0b5e700933f..61ac4f47797 100644 --- a/components/script/dom/htmlfontelement.rs +++ b/components/script/dom/htmlfontelement.rs @@ -4,7 +4,6 @@ use cssparser::RGBA; use dom::attr::{Attr, AttrValue}; -use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::HTMLFontElementBinding; use dom::bindings::codegen::Bindings::HTMLFontElementBinding::HTMLFontElementMethods; use dom::bindings::inheritance::Castable; @@ -23,7 +22,6 @@ use util::str::{self, DOMString, parse_legacy_font_size}; pub struct HTMLFontElement { htmlelement: HTMLElement, color: Cell<Option<RGBA>>, - face: DOMRefCell<Option<Atom>>, } @@ -32,7 +30,6 @@ impl HTMLFontElement { HTMLFontElement { htmlelement: HTMLElement::new_inherited(localName, prefix, document), color: Cell::new(None), - face: DOMRefCell::new(None), } } @@ -65,7 +62,7 @@ impl HTMLFontElementMethods for HTMLFontElement { fn SetSize(&self, value: DOMString) { let element = self.upcast::<Element>(); let length = parse_length(&value); - element.set_attribute(&Atom::from_slice("size"), AttrValue::Length(value, length)); + element.set_attribute(&atom!("size"), AttrValue::Length(value, length)); } } @@ -82,11 +79,6 @@ impl VirtualMethods for HTMLFontElement { str::parse_legacy_color(&value).ok() })); }, - &atom!(face) => { - *self.face.borrow_mut() = - mutation.new_value(attr) - .map(|value| value.as_atom().clone()) - }, _ => {}, } } @@ -111,10 +103,11 @@ impl HTMLFontElement { #[allow(unsafe_code)] pub fn get_face(&self) -> Option<Atom> { - let face = unsafe { self.face.borrow_for_layout() }; - match *face { - Some(ref s) => Some(s.clone()), - None => None, + unsafe { + self.upcast::<Element>() + .get_attr_for_layout(&ns!(""), &atom!("face")) + .map(AttrValue::as_atom) + .cloned() } } diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 95fb9bbf2f3..e123c101f6f 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -305,7 +305,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { fn Mozbrowser(&self) -> bool { if mozbrowser_enabled() { let element = self.upcast::<Element>(); - element.has_attribute(&Atom::from_slice("mozbrowser")) + element.has_attribute(&atom!("mozbrowser")) } else { false } @@ -315,7 +315,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { fn SetMozbrowser(&self, value: bool) -> ErrorResult { if mozbrowser_enabled() { let element = self.upcast::<Element>(); - element.set_bool_attribute(&Atom::from_slice("mozbrowser"), value); + element.set_bool_attribute(&atom!("mozbrowser"), value); } Ok(()) } diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 871e6335928..b059fe3ada3 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -14,7 +14,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::{LayoutJS, Root}; use dom::bindings::refcounted::Trusted; use dom::document::Document; -use dom::element::{AttributeMutation, Element}; +use dom::element::AttributeMutation; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::htmlelement::HTMLElement; use dom::node::{Node, NodeDamage, document_from_node, window_from_node}; @@ -196,11 +196,8 @@ impl HTMLImageElementMethods for HTMLImageElement { // https://html.spec.whatwg.org/multipage/#dom-img-ismap make_bool_getter!(IsMap); - // https://html.spec.whatwg.org/multipage/#dom-img-ismap - fn SetIsMap(&self, is_map: bool) { - self.upcast::<Element>().set_string_attribute(&atom!("ismap"), is_map.to_string()) - } + make_bool_setter!(SetIsMap, "ismap"); // https://html.spec.whatwg.org/multipage/#dom-img-width fn Width(&self) -> u32 { @@ -210,9 +207,7 @@ impl HTMLImageElementMethods for HTMLImageElement { } // https://html.spec.whatwg.org/multipage/#dom-img-width - fn SetWidth(&self, width: u32) { - self.upcast::<Element>().set_uint_attribute(&atom!("width"), width) - } + make_uint_setter!(SetWidth, "width"); // https://html.spec.whatwg.org/multipage/#dom-img-height fn Height(&self) -> u32 { @@ -222,9 +217,7 @@ impl HTMLImageElementMethods for HTMLImageElement { } // https://html.spec.whatwg.org/multipage/#dom-img-height - fn SetHeight(&self, height: u32) { - self.upcast::<Element>().set_uint_attribute(&atom!("height"), height) - } + make_uint_setter!(SetHeight, "height"); // https://html.spec.whatwg.org/multipage/#dom-img-naturalwidth fn NaturalWidth(&self) -> u32 { diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 0c262530f3f..195d137a24d 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -15,7 +15,7 @@ use dom::bindings::global::GlobalRef; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, LayoutJS, Root, RootedReference}; use dom::document::Document; -use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE, RawLayoutElementHelpers}; +use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers, LayoutElementHelpers}; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; use dom::htmlelement::HTMLElement; @@ -25,8 +25,10 @@ use dom::htmlformelement::{ResetFrom, SubmittedFrom}; use dom::keyboardevent::KeyboardEvent; use dom::node::{Node, NodeDamage}; use dom::node::{document_from_node, window_from_node}; +use dom::nodelist::NodeList; use dom::virtualmethods::VirtualMethods; use msg::constellation_msg::ConstellationChan; +use selectors::states::*; use std::borrow::ToOwned; use std::cell::Cell; use string_cache::Atom; @@ -57,10 +59,8 @@ enum InputType { pub struct HTMLInputElement { htmlelement: HTMLElement, input_type: Cell<InputType>, - checked: Cell<bool>, checked_changed: Cell<bool>, placeholder: DOMRefCell<DOMString>, - indeterminate: Cell<bool>, value_changed: Cell<bool>, size: Cell<u32>, #[ignore_heap_size_of = "#7193"] @@ -111,9 +111,7 @@ impl HTMLInputElement { HTMLElement::new_inherited_with_state(IN_ENABLED_STATE, localName, prefix, document), input_type: Cell::new(InputType::InputText), - checked: Cell::new(false), placeholder: DOMRefCell::new("".to_owned()), - indeterminate: Cell::new(false), checked_changed: Cell::new(false), value_changed: Cell::new(false), size: Cell::new(DEFAULT_INPUT_SIZE), @@ -138,15 +136,10 @@ pub trait LayoutHTMLInputElementHelpers { unsafe fn get_size_for_layout(self) -> u32; #[allow(unsafe_code)] unsafe fn get_insertion_point_for_layout(self) -> Option<TextPoint>; -} - -pub trait RawLayoutHTMLInputElementHelpers { - #[allow(unsafe_code)] - unsafe fn get_checked_state_for_layout(&self) -> bool; #[allow(unsafe_code)] - unsafe fn get_indeterminate_state_for_layout(&self) -> bool; + unsafe fn get_checked_state_for_layout(self) -> bool; #[allow(unsafe_code)] - unsafe fn get_size_for_layout(&self) -> u32; + unsafe fn get_indeterminate_state_for_layout(self) -> bool; } impl LayoutHTMLInputElementHelpers for LayoutJS<HTMLInputElement> { @@ -186,7 +179,7 @@ impl LayoutHTMLInputElementHelpers for LayoutJS<HTMLInputElement> { #[allow(unrooted_must_root)] #[allow(unsafe_code)] unsafe fn get_size_for_layout(self) -> u32 { - (*self.unsafe_get()).get_size_for_layout() + (*self.unsafe_get()).size.get() } #[allow(unrooted_must_root)] @@ -198,25 +191,17 @@ impl LayoutHTMLInputElementHelpers for LayoutJS<HTMLInputElement> { _ => None } } -} - -impl RawLayoutHTMLInputElementHelpers for HTMLInputElement { - #[allow(unrooted_must_root)] - #[allow(unsafe_code)] - unsafe fn get_checked_state_for_layout(&self) -> bool { - self.checked.get() - } #[allow(unrooted_must_root)] #[allow(unsafe_code)] - unsafe fn get_indeterminate_state_for_layout(&self) -> bool { - self.indeterminate.get() + unsafe fn get_checked_state_for_layout(self) -> bool { + self.upcast::<Element>().get_state_for_layout().contains(IN_CHECKED_STATE) } #[allow(unrooted_must_root)] #[allow(unsafe_code)] - unsafe fn get_size_for_layout(&self) -> u32 { - self.size.get() + unsafe fn get_indeterminate_state_for_layout(self) -> bool { + self.upcast::<Element>().get_state_for_layout().contains(IN_INDETERMINATE_STATE) } } @@ -240,7 +225,7 @@ impl HTMLInputElementMethods for HTMLInputElement { // https://html.spec.whatwg.org/multipage/#dom-input-checked fn Checked(&self) -> bool { - self.checked.get() + self.upcast::<Element>().get_state().contains(IN_CHECKED_STATE) } // https://html.spec.whatwg.org/multipage/#dom-input-checked @@ -329,12 +314,22 @@ impl HTMLInputElementMethods for HTMLInputElement { // https://html.spec.whatwg.org/multipage/#dom-input-indeterminate fn Indeterminate(&self) -> bool { - self.indeterminate.get() + self.upcast::<Element>().get_state().contains(IN_INDETERMINATE_STATE) } // https://html.spec.whatwg.org/multipage/#dom-input-indeterminate fn SetIndeterminate(&self, val: bool) { - self.indeterminate.set(val) + self.upcast::<Element>().set_state(IN_INDETERMINATE_STATE, val) + } + + // https://html.spec.whatwg.org/multipage/#dom-lfe-labels + fn Labels(&self) -> Root<NodeList> { + if self.Type() == "hidden" { + let window = window_from_node(self); + NodeList::empty(&window) + } else { + self.upcast::<HTMLElement>().labels() + } } } @@ -443,7 +438,7 @@ impl HTMLInputElement { } fn update_checked_state(&self, checked: bool, dirty: bool) { - self.checked.set(checked); + self.upcast::<Element>().set_state(IN_CHECKED_STATE, checked); if dirty { self.checked_changed.set(true); @@ -459,7 +454,7 @@ impl HTMLInputElement { } pub fn get_indeterminate_state(&self) -> bool { - self.indeterminate.get() + self.Indeterminate() } // https://html.spec.whatwg.org/multipage/#concept-fe-mutable @@ -610,7 +605,7 @@ impl VirtualMethods for HTMLInputElement { s.handle_event(event); } - if &*event.Type() == "click" && !event.DefaultPrevented() { + if event.type_() == atom!("click") && !event.DefaultPrevented() { match self.input_type.get() { InputType::InputRadio => self.update_checked_state(true, true), _ => {} @@ -622,7 +617,7 @@ impl VirtualMethods for HTMLInputElement { //TODO: set the editing position for text inputs document_from_node(self).request_focus(self.upcast()); - } else if &*event.Type() == "keydown" && !event.DefaultPrevented() && + } else if event.type_() == atom!("keydown") && !event.DefaultPrevented() && (self.input_type.get() == InputType::InputText || self.input_type.get() == InputType::InputPassword) { if let Some(keyevent) = event.downcast::<KeyboardEvent>() { diff --git a/components/script/dom/htmllabelelement.rs b/components/script/dom/htmllabelelement.rs index fba46fa4a56..f64633082b4 100644 --- a/components/script/dom/htmllabelelement.rs +++ b/components/script/dom/htmllabelelement.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::activation::Activatable; use dom::attr::AttrValue; use dom::bindings::codegen::Bindings::HTMLLabelElementBinding; use dom::bindings::codegen::Bindings::HTMLLabelElementBinding::HTMLLabelElementMethods; @@ -9,6 +10,8 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::document::Document; use dom::element::Element; +use dom::event::Event; +use dom::eventtarget::EventTarget; use dom::htmlelement::HTMLElement; use dom::htmlformelement::{FormControl, HTMLFormElement}; use dom::node::{document_from_node, Node}; @@ -40,6 +43,40 @@ impl HTMLLabelElement { } } +impl Activatable for HTMLLabelElement { + fn as_element(&self) -> &Element { + self.upcast::<Element>() + } + + fn is_instance_activatable(&self) -> bool { + return true; + } + + // https://html.spec.whatwg.org/multipage/#run-pre-click-activation-steps + // https://html.spec.whatwg.org/multipage/#the-button-element:activation-behavior + fn pre_click_activation(&self) { + } + + // https://html.spec.whatwg.org/multipage/#run-canceled-activation-steps + fn canceled_activation(&self) { + } + + // https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps + fn activation_behavior(&self, _event: &Event, _target: &EventTarget) { + self.upcast::<Element>() + .as_maybe_activatable() + .map(|a| a.synthetic_click_activation(false, false, false, false)); + } + + // https://html.spec.whatwg.org/multipage/#implicit-submission + fn implicit_submission(&self, _ctrlKey: bool, _shiftKey: bool, _altKey: bool, _metaKey: bool) { + //FIXME: Investigate and implement implicit submission for label elements + // Issue filed at https://github.com/servo/servo/issues/8263 + } + + +} + impl HTMLLabelElementMethods for HTMLLabelElement { // https://html.spec.whatwg.org/multipage/#dom-fae-form fn GetForm(&self) -> Option<Root<HTMLFormElement>> { @@ -86,7 +123,7 @@ impl VirtualMethods for HTMLLabelElement { } impl HTMLLabelElement { - fn first_labelable_descendant(&self) -> Option<Root<HTMLElement>> { + pub fn first_labelable_descendant(&self) -> Option<Root<HTMLElement>> { self.upcast::<Node>() .traverse_preorder() .filter_map(Root::downcast::<HTMLElement>) diff --git a/components/script/dom/htmlmeterelement.rs b/components/script/dom/htmlmeterelement.rs index cfe1a4eb5d2..74b48434339 100644 --- a/components/script/dom/htmlmeterelement.rs +++ b/components/script/dom/htmlmeterelement.rs @@ -2,11 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use dom::bindings::codegen::Bindings::HTMLMeterElementBinding; +use dom::bindings::codegen::Bindings::HTMLMeterElementBinding::{self, HTMLMeterElementMethods}; +use dom::bindings::conversions::Castable; use dom::bindings::js::Root; use dom::document::Document; use dom::htmlelement::HTMLElement; use dom::node::Node; +use dom::nodelist::NodeList; use util::str::DOMString; #[dom_struct] @@ -31,3 +33,10 @@ impl HTMLMeterElement { Node::reflect_node(box element, document, HTMLMeterElementBinding::Wrap) } } + +impl HTMLMeterElementMethods for HTMLMeterElement { + // https://html.spec.whatwg.org/multipage/#dom-lfe-labels + fn Labels(&self) -> Root<NodeList> { + self.upcast::<HTMLElement>().labels() + } +} diff --git a/components/script/dom/htmloptgroupelement.rs b/components/script/dom/htmloptgroupelement.rs index c63d02788d9..b44bad67b91 100644 --- a/components/script/dom/htmloptgroupelement.rs +++ b/components/script/dom/htmloptgroupelement.rs @@ -8,11 +8,12 @@ use dom::bindings::codegen::Bindings::HTMLOptGroupElementBinding::HTMLOptGroupEl use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::document::Document; -use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE}; +use dom::element::{AttributeMutation, Element}; use dom::htmlelement::HTMLElement; use dom::htmloptionelement::HTMLOptionElement; use dom::node::Node; use dom::virtualmethods::VirtualMethods; +use selectors::states::*; use util::str::DOMString; #[dom_struct] diff --git a/components/script/dom/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs index 62241f7c4f0..873745dd6a7 100644 --- a/components/script/dom/htmloptionelement.rs +++ b/components/script/dom/htmloptionelement.rs @@ -11,13 +11,14 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::characterdata::CharacterData; use dom::document::Document; -use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE}; +use dom::element::{AttributeMutation, Element}; use dom::htmlelement::HTMLElement; use dom::htmlscriptelement::HTMLScriptElement; use dom::htmlselectelement::HTMLSelectElement; use dom::node::Node; use dom::text::Text; use dom::virtualmethods::VirtualMethods; +use selectors::states::*; use std::cell::Cell; use util::str::{DOMString, split_html_space_chars, str_join}; @@ -91,9 +92,7 @@ impl HTMLOptionElementMethods for HTMLOptionElement { make_bool_getter!(Disabled); // https://html.spec.whatwg.org/multipage/#dom-option-disabled - fn SetDisabled(&self, disabled: bool) { - self.upcast::<Element>().set_bool_attribute(&atom!("disabled"), disabled) - } + make_bool_setter!(SetDisabled, "disabled"); // https://html.spec.whatwg.org/multipage/#dom-option-text fn Text(&self) -> DOMString { diff --git a/components/script/dom/htmloutputelement.rs b/components/script/dom/htmloutputelement.rs index 26c5b9c6bae..937fcea3919 100644 --- a/components/script/dom/htmloutputelement.rs +++ b/components/script/dom/htmloutputelement.rs @@ -4,11 +4,13 @@ use dom::bindings::codegen::Bindings::HTMLOutputElementBinding; use dom::bindings::codegen::Bindings::HTMLOutputElementBinding::HTMLOutputElementMethods; +use dom::bindings::conversions::Castable; use dom::bindings::js::Root; use dom::document::Document; use dom::htmlelement::HTMLElement; use dom::htmlformelement::{FormControl, HTMLFormElement}; use dom::node::{Node, window_from_node}; +use dom::nodelist::NodeList; use dom::validitystate::ValidityState; use util::str::DOMString; @@ -47,6 +49,11 @@ impl HTMLOutputElementMethods for HTMLOutputElement { fn GetForm(&self) -> Option<Root<HTMLFormElement>> { self.form_owner() } + + // https://html.spec.whatwg.org/multipage/#dom-lfe-labels + fn Labels(&self) -> Root<NodeList> { + self.upcast::<HTMLElement>().labels() + } } impl FormControl for HTMLOutputElement {} diff --git a/components/script/dom/htmlprogresselement.rs b/components/script/dom/htmlprogresselement.rs index 7bee428c8f4..669f25942b6 100644 --- a/components/script/dom/htmlprogresselement.rs +++ b/components/script/dom/htmlprogresselement.rs @@ -2,11 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use dom::bindings::codegen::Bindings::HTMLProgressElementBinding; +use dom::bindings::codegen::Bindings::HTMLProgressElementBinding::{self, HTMLProgressElementMethods}; +use dom::bindings::conversions::Castable; use dom::bindings::js::Root; use dom::document::Document; use dom::htmlelement::HTMLElement; use dom::node::Node; +use dom::nodelist::NodeList; use util::str::DOMString; #[dom_struct] @@ -32,3 +34,10 @@ impl HTMLProgressElement { Node::reflect_node(box element, document, HTMLProgressElementBinding::Wrap) } } + +impl HTMLProgressElementMethods for HTMLProgressElement { + // https://html.spec.whatwg.org/multipage/#dom-lfe-labels + fn Labels(&self) -> Root<NodeList> { + self.upcast::<HTMLElement>().labels() + } +} diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index eed34d14bfd..6f2cb5de84e 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -37,7 +37,7 @@ use network_listener::{NetworkListener, PreInvoke}; use script_task::ScriptTaskEventCategory::ScriptEvent; use script_task::{CommonScriptMsg, Runnable, ScriptChan}; use std::ascii::AsciiExt; -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use std::mem; use std::sync::{Arc, Mutex}; use url::{Url, UrlParser}; @@ -65,7 +65,7 @@ pub struct HTMLScriptElement { parser_document: JS<Document>, /// The source this script was loaded from - load: RefCell<Option<ScriptOrigin>>, + load: DOMRefCell<Option<ScriptOrigin>>, #[ignore_heap_size_of = "Defined in rust-encoding"] /// https://html.spec.whatwg.org/multipage/#concept-script-encoding @@ -83,7 +83,7 @@ impl HTMLScriptElement { non_blocking: Cell::new(creator != ElementCreator::ParserCreated), ready_to_be_parser_executed: Cell::new(false), parser_document: JS::from_ref(document), - load: RefCell::new(None), + load: DOMRefCell::new(None), block_character_encoding: DOMRefCell::new(UTF_8 as EncodingRef), } } @@ -364,7 +364,7 @@ impl HTMLScriptElement { // Step 1. let doc = document_from_node(self); - if self.parser_inserted.get() && doc.r() != self.parser_document.root().r() { + if self.parser_inserted.get() && &*doc != &*self.parser_document { return; } @@ -562,8 +562,8 @@ impl VirtualMethods for HTMLScriptElement { fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { self.super_type().unwrap().attribute_mutated(attr, mutation); - match attr.local_name() { - &atom!("src") => { + match *attr.local_name() { + atom!("src") => { if let AttributeMutation::Set(_) = mutation { if !self.parser_inserted.get() && self.upcast::<Node>().is_in_doc() { self.prepare(); diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index 2df77b10719..8ff563dfef1 100644 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -11,14 +11,16 @@ use dom::bindings::codegen::UnionTypes::HTMLOptionElementOrHTMLOptGroupElement; use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::document::Document; -use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE}; +use dom::element::{AttributeMutation, Element}; use dom::htmlelement::HTMLElement; use dom::htmlfieldsetelement::HTMLFieldSetElement; use dom::htmlformelement::{FormControl, HTMLFormElement}; use dom::htmloptionelement::HTMLOptionElement; use dom::node::{Node, window_from_node}; +use dom::nodelist::NodeList; use dom::validitystate::ValidityState; use dom::virtualmethods::VirtualMethods; +use selectors::states::*; use std::borrow::ToOwned; use string_cache::Atom; use util::str::DOMString; @@ -157,6 +159,11 @@ impl HTMLSelectElementMethods for HTMLSelectElement { "select-one".to_owned() } } + + // https://html.spec.whatwg.org/multipage/#dom-lfe-labels + fn Labels(&self) -> Root<NodeList> { + self.upcast::<HTMLElement>().labels() + } } impl VirtualMethods for HTMLSelectElement { @@ -205,8 +212,8 @@ impl VirtualMethods for HTMLSelectElement { } fn parse_plain_attribute(&self, local_name: &Atom, value: DOMString) -> AttrValue { - match local_name { - &atom!("size") => AttrValue::from_u32(value, DEFAULT_SELECT_SIZE), + match *local_name { + atom!("size") => AttrValue::from_u32(value, DEFAULT_SELECT_SIZE), _ => self.super_type().unwrap().parse_plain_attribute(local_name, value), } } diff --git a/components/script/dom/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs index c0d04f6f77d..d95d663ffee 100644 --- a/components/script/dom/htmltablecellelement.rs +++ b/components/script/dom/htmltablecellelement.rs @@ -53,7 +53,7 @@ impl HTMLTableCellElementMethods for HTMLTableCellElement { make_uint_getter!(ColSpan, "colspan", DEFAULT_COLSPAN); // https://html.spec.whatwg.org/multipage/#dom-tdth-colspan - make_uint_setter!(SetColSpan, "colspan"); + make_uint_setter!(SetColSpan, "colspan", DEFAULT_COLSPAN); // https://html.spec.whatwg.org/multipage/#dom-tdth-cellindex fn CellIndex(&self) -> i32 { @@ -107,18 +107,18 @@ impl VirtualMethods for HTMLTableCellElement { fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { self.super_type().unwrap().attribute_mutated(attr, mutation); - match attr.local_name() { - &atom!(bgcolor) => { + match *attr.local_name() { + atom!(bgcolor) => { self.background_color.set(mutation.new_value(attr).and_then(|value| { str::parse_legacy_color(&value).ok() })); }, - &atom!(colspan) => { + atom!(colspan) => { self.colspan.set(mutation.new_value(attr).map(|value| { max(DEFAULT_COLSPAN, value.as_uint()) })); }, - &atom!(width) => { + atom!(width) => { let width = mutation.new_value(attr).map(|value| { str::parse_length(&value) }); @@ -129,8 +129,8 @@ impl VirtualMethods for HTMLTableCellElement { } fn parse_plain_attribute(&self, local_name: &Atom, value: DOMString) -> AttrValue { - match local_name { - &atom!("colspan") => AttrValue::from_u32(value, DEFAULT_COLSPAN), + match *local_name { + atom!("colspan") => AttrValue::from_u32(value, DEFAULT_COLSPAN), _ => self.super_type().unwrap().parse_plain_attribute(local_name, value), } } diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs index de3a4cf0631..2ad152c65ef 100644 --- a/components/script/dom/htmltableelement.rs +++ b/components/script/dom/htmltableelement.rs @@ -141,24 +141,24 @@ impl VirtualMethods for HTMLTableElement { fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { self.super_type().unwrap().attribute_mutated(attr, mutation); - match attr.local_name() { - &atom!(bgcolor) => { + match *attr.local_name() { + atom!(bgcolor) => { self.background_color.set(mutation.new_value(attr).and_then(|value| { str::parse_legacy_color(&value).ok() })); }, - &atom!(border) => { + atom!(border) => { // According to HTML5 § 14.3.9, invalid values map to 1px. self.border.set(mutation.new_value(attr).map(|value| { str::parse_unsigned_integer(value.chars()).unwrap_or(1) })); } - &atom!(cellspacing) => { + atom!(cellspacing) => { self.cellspacing.set(mutation.new_value(attr).and_then(|value| { str::parse_unsigned_integer(value.chars()) })); }, - &atom!(width) => { + atom!(width) => { let width = mutation.new_value(attr).map(|value| { str::parse_length(&value) }); @@ -169,8 +169,8 @@ impl VirtualMethods for HTMLTableElement { } fn parse_plain_attribute(&self, local_name: &Atom, value: DOMString) -> AttrValue { - match local_name { - &atom!("border") => AttrValue::from_u32(value, 1), + match *local_name { + atom!("border") => AttrValue::from_u32(value, 1), _ => self.super_type().unwrap().parse_plain_attribute(local_name, value), } } diff --git a/components/script/dom/htmltablerowelement.rs b/components/script/dom/htmltablerowelement.rs index 726ad915982..224252d3506 100644 --- a/components/script/dom/htmltablerowelement.rs +++ b/components/script/dom/htmltablerowelement.rs @@ -102,8 +102,8 @@ impl VirtualMethods for HTMLTableRowElement { fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { self.super_type().unwrap().attribute_mutated(attr, mutation); - match attr.local_name() { - &atom!(bgcolor) => { + match *attr.local_name() { + atom!(bgcolor) => { self.background_color.set(mutation.new_value(attr).and_then(|value| { str::parse_legacy_color(&value).ok() })); diff --git a/components/script/dom/htmltablesectionelement.rs b/components/script/dom/htmltablesectionelement.rs index 50b9f1fc3d0..af7bf7b9727 100644 --- a/components/script/dom/htmltablesectionelement.rs +++ b/components/script/dom/htmltablesectionelement.rs @@ -87,8 +87,8 @@ impl VirtualMethods for HTMLTableSectionElement { fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { self.super_type().unwrap().attribute_mutated(attr, mutation); - match attr.local_name() { - &atom!(bgcolor) => { + match *attr.local_name() { + atom!(bgcolor) => { self.background_color.set(mutation.new_value(attr).and_then(|value| { str::parse_legacy_color(&value).ok() })); diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 37617ccc0a6..2c6a2fde20c 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -13,7 +13,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::{LayoutJS, Root}; use dom::bindings::refcounted::Trusted; use dom::document::Document; -use dom::element::{AttributeMutation, IN_ENABLED_STATE, Element}; +use dom::element::{AttributeMutation, Element}; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; use dom::htmlelement::HTMLElement; @@ -22,10 +22,12 @@ use dom::htmlformelement::{FormControl, HTMLFormElement}; use dom::keyboardevent::KeyboardEvent; use dom::node::{ChildrenMutation, Node, NodeDamage}; use dom::node::{document_from_node, window_from_node}; +use dom::nodelist::NodeList; use dom::virtualmethods::VirtualMethods; use msg::constellation_msg::ConstellationChan; use script_task::ScriptTaskEventCategory::InputEvent; use script_task::{CommonScriptMsg, Runnable}; +use selectors::states::*; use std::borrow::ToOwned; use std::cell::Cell; use string_cache::Atom; @@ -204,6 +206,11 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement { self.force_relayout(); } + + // https://html.spec.whatwg.org/multipage/#dom-lfe-labels + fn Labels(&self) -> Root<NodeList> { + self.upcast::<HTMLElement>().labels() + } } @@ -246,8 +253,8 @@ impl VirtualMethods for HTMLTextAreaElement { fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { self.super_type().unwrap().attribute_mutated(attr, mutation); - match attr.local_name() { - &atom!(disabled) => { + match *attr.local_name() { + atom!(disabled) => { let el = self.upcast::<Element>(); match mutation { AttributeMutation::Set(_) => { @@ -261,13 +268,13 @@ impl VirtualMethods for HTMLTextAreaElement { } } }, - &atom!(cols) => { + atom!(cols) => { let cols = mutation.new_value(attr).map(|value| { value.as_uint() }); self.cols.set(cols.unwrap_or(DEFAULT_COLS)); }, - &atom!(rows) => { + atom!(rows) => { let rows = mutation.new_value(attr).map(|value| { value.as_uint() }); @@ -286,9 +293,9 @@ impl VirtualMethods for HTMLTextAreaElement { } fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue { - match name { - &atom!("cols") => AttrValue::from_limited_u32(value, DEFAULT_COLS), - &atom!("rows") => AttrValue::from_limited_u32(value, DEFAULT_ROWS), + match *name { + atom!("cols") => AttrValue::from_limited_u32(value, DEFAULT_COLS), + atom!("rows") => AttrValue::from_limited_u32(value, DEFAULT_ROWS), _ => self.super_type().unwrap().parse_plain_attribute(name, value), } } @@ -322,11 +329,11 @@ impl VirtualMethods for HTMLTextAreaElement { s.handle_event(event); } - if &*event.Type() == "click" && !event.DefaultPrevented() { + if event.type_() == atom!("click") && !event.DefaultPrevented() { //TODO: set the editing position for text inputs document_from_node(self).request_focus(self.upcast()); - } else if &*event.Type() == "keydown" && !event.DefaultPrevented() { + } else if event.type_() == atom!("keydown") && !event.DefaultPrevented() { if let Some(kevent) = event.downcast::<KeyboardEvent>() { match self.textinput.borrow_mut().handle_keydown(kevent) { KeyReaction::TriggerDefaultAction => (), diff --git a/components/script/dom/keyboardevent.rs b/components/script/dom/keyboardevent.rs index 6fbbf1d97db..9fea1da5b6f 100644 --- a/components/script/dom/keyboardevent.rs +++ b/components/script/dom/keyboardevent.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::KeyboardEventBinding; use dom::bindings::codegen::Bindings::KeyboardEventBinding::{KeyboardEventConstants, KeyboardEventMethods}; use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods; @@ -17,7 +18,7 @@ use msg::constellation_msg; use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; use msg::constellation_msg::{Key, KeyModifiers}; use std::borrow::ToOwned; -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use util::str::DOMString; no_jsmanaged_fields!(Key); @@ -26,8 +27,8 @@ no_jsmanaged_fields!(Key); pub struct KeyboardEvent { uievent: UIEvent, key: Cell<Option<Key>>, - key_string: RefCell<DOMString>, - code: RefCell<DOMString>, + key_string: DOMRefCell<DOMString>, + code: DOMRefCell<DOMString>, location: Cell<u32>, ctrl: Cell<bool>, alt: Cell<bool>, @@ -44,8 +45,8 @@ impl KeyboardEvent { KeyboardEvent { uievent: UIEvent::new_inherited(), key: Cell::new(None), - key_string: RefCell::new("".to_owned()), - code: RefCell::new("".to_owned()), + key_string: DOMRefCell::new("".to_owned()), + code: DOMRefCell::new("".to_owned()), location: Cell::new(0), ctrl: Cell::new(false), alt: Cell::new(false), diff --git a/components/script/dom/namednodemap.rs b/components/script/dom/namednodemap.rs index e3115223931..3d6c3c4535c 100644 --- a/components/script/dom/namednodemap.rs +++ b/components/script/dom/namednodemap.rs @@ -43,7 +43,7 @@ impl NamedNodeMapMethods for NamedNodeMap { // https://dom.spec.whatwg.org/#dom-namednodemap-item fn Item(&self, index: u32) -> Option<Root<Attr>> { - self.owner.attrs().get(index as usize).map(JS::root) + self.owner.attrs().get(index as usize).map(|js| Root::from_ref(&**js)) } // https://dom.spec.whatwg.org/#dom-namednodemap-getnameditem @@ -86,8 +86,10 @@ impl NamedNodeMapMethods for NamedNodeMap { item } + // https://heycam.github.io/webidl/#dfn-supported-property-names fn SupportedPropertyNames(&self) -> Vec<DOMString> { - // FIXME: unimplemented (https://github.com/servo/servo/issues/7273) - vec![] + self.owner.attrs().iter().map(|attr| { + (**attr.name()).to_owned() + }).collect() } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index f12fe53f1c4..02e929be155 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -886,8 +886,8 @@ fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<Root<No { nodes.find(|node| { not_in.iter().all(|n| { - match n { - &NodeOrString::eNode(ref n) => n != node, + match *n { + NodeOrString::eNode(ref n) => n != node, _ => true, } }) @@ -1649,7 +1649,7 @@ impl Node { let node_elem = node.downcast::<Element>().unwrap(); let copy_elem = copy.downcast::<Element>().unwrap(); - for attr in node_elem.attrs().iter().map(JS::root) { + for attr in node_elem.attrs().iter() { copy_elem.push_new_attribute(attr.local_name().clone(), attr.value().clone(), attr.name().clone(), @@ -1720,12 +1720,10 @@ impl Node { let prefix_atom = prefix.as_ref().map(|s| Atom::from_slice(s)); // Step 2. - let namespace_attr = - element.attrs() - .iter() - .map(|attr| attr.root()) - .find(|attr| attr_defines_namespace(attr.r(), - &prefix_atom)); + let attrs = element.attrs(); + let namespace_attr = attrs.iter().find(|attr| { + attr_defines_namespace(attr, &prefix_atom) + }); // Steps 2.1-2. if let Some(attr) = namespace_attr { @@ -2155,12 +2153,10 @@ impl NodeMethods for Node { // FIXME(https://github.com/rust-lang/rust/issues/23338) let attrs = element.attrs(); attrs.iter().all(|attr| { - let attr = attr.root(); other_element.attrs().iter().any(|other_attr| { - let other_attr = other_attr.root(); - (*attr.r().namespace() == *other_attr.r().namespace()) && - (attr.r().local_name() == other_attr.r().local_name()) && - (**attr.r().value() == **other_attr.r().value()) + (*attr.namespace() == *other_attr.namespace()) && + (attr.local_name() == other_attr.local_name()) && + (**attr.value() == **other_attr.value()) }) }) } diff --git a/components/script/dom/nodeiterator.rs b/components/script/dom/nodeiterator.rs index 379ce5a3743..76c8e536e2b 100644 --- a/components/script/dom/nodeiterator.rs +++ b/components/script/dom/nodeiterator.rs @@ -67,7 +67,7 @@ impl NodeIterator { impl NodeIteratorMethods for NodeIterator { // https://dom.spec.whatwg.org/#dom-nodeiterator-root fn Root(&self) -> Root<Node> { - self.root_node.root() + Root::from_ref(&*self.root_node) } // https://dom.spec.whatwg.org/#dom-nodeiterator-whattoshow diff --git a/components/script/dom/nodelist.rs b/components/script/dom/nodelist.rs index cf5da3b0a3f..6747ee5a948 100644 --- a/components/script/dom/nodelist.rs +++ b/components/script/dom/nodelist.rs @@ -51,6 +51,10 @@ impl NodeList { pub fn new_child_list(window: &Window, node: &Node) -> Root<NodeList> { NodeList::new(window, NodeListType::Children(ChildrenList::new(node))) } + + pub fn empty(window: &Window) -> Root<NodeList> { + NodeList::new(window, NodeListType::Simple(vec![])) + } } impl NodeListMethods for NodeList { @@ -66,7 +70,7 @@ impl NodeListMethods for NodeList { fn Item(&self, index: u32) -> Option<Root<Node>> { match self.list_type { NodeListType::Simple(ref elems) => { - elems.get(index as usize).map(|node| node.root()) + elems.get(index as usize).map(|node| Root::from_ref(&**node)) }, NodeListType::Children(ref list) => list.item(index), } diff --git a/components/script/dom/performance.rs b/components/script/dom/performance.rs index ffcdc7a170e..07ddbe2c312 100644 --- a/components/script/dom/performance.rs +++ b/components/script/dom/performance.rs @@ -46,7 +46,7 @@ impl Performance { impl PerformanceMethods for Performance { // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#performance-timing-attribute fn Timing(&self) -> Root<PerformanceTiming> { - self.timing.root() + Root::from_ref(&*self.timing) } // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HighResolutionTime/Overview.html#dom-performance-now diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 3ac23d7e4d6..fbef27341ec 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -809,7 +809,7 @@ fn bp_position(a_node: &Node, a_offset: u32, } else if position & NodeConstants::DOCUMENT_POSITION_CONTAINS != 0 { // Step 3-1, 3-2. let mut b_ancestors = b_node.inclusive_ancestors(); - let ref child = b_ancestors.find(|child| { + let child = b_ancestors.find(|child| { child.r().GetParentNode().unwrap().r() == a_node }).unwrap(); // Step 3-3. diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs index 5f113c4dd54..3465dc723fc 100644 --- a/components/script/dom/servohtmlparser.rs +++ b/components/script/dom/servohtmlparser.rs @@ -45,7 +45,7 @@ impl Sink { #[allow(unrooted_must_root)] // method is only run at parse time pub fn get_or_create(&self, child: NodeOrText<JS<Node>>) -> Root<Node> { match child { - NodeOrText::AppendNode(n) => n.root(), + NodeOrText::AppendNode(n) => Root::from_ref(&*n), NodeOrText::AppendText(t) => { let text = Text::new(t.into(), &self.document); Root::upcast(text) @@ -68,8 +68,8 @@ pub type Tokenizer = tokenizer::Tokenizer<TreeBuilder<JS<Node>, Sink>>; pub struct ParserContext { /// The parser that initiated the request. parser: Option<Trusted<ServoHTMLParser>>, - /// Is this document a synthesized document for a single image? - is_image_document: bool, + /// Is this a synthesized document + is_synthesized_document: bool, /// The pipeline associated with this document. id: PipelineId, /// The subpage associated with this document. @@ -85,7 +85,7 @@ impl ParserContext { url: Url) -> ParserContext { ParserContext { parser: None, - is_image_document: false, + is_synthesized_document: false, id: id, subpage: subpage, script_chan: script_chan, @@ -111,12 +111,12 @@ impl AsyncResponseListener for ParserContext { match content_type { Some(ContentType(Mime(TopLevel::Image, _, _))) => { - self.is_image_document = true; + self.is_synthesized_document = true; let page = format!("<html><body><img src='{}' /></body></html>", self.url.serialize()); parser.pending_input.borrow_mut().push(page); parser.parse_sync(); - } + }, Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => { // FIXME: When servo/html5ever#109 is fixed remove <plaintext> usage and // replace with fix from that issue. @@ -130,12 +130,29 @@ impl AsyncResponseListener for ParserContext { parser.pending_input.borrow_mut().push(page); parser.parse_sync(); }, - _ => {} + Some(ContentType(Mime(TopLevel::Text, SubLevel::Html, _))) => {}, // Handle text/html + Some(ContentType(Mime(toplevel, sublevel, _))) => { + if toplevel.as_str() == "application" && sublevel.as_str() == "xhtml+xml" { + // Handle xhtml (application/xhtml+xml). + return; + } + + // Show warning page for unknown mime types. + let page = format!("<html><body><p>Unknown content type ({}/{}).</p></body></html>", + toplevel.as_str(), sublevel.as_str()); + self.is_synthesized_document = true; + parser.pending_input.borrow_mut().push(page); + parser.parse_sync(); + }, + None => { + // No content-type header. + // Merge with #4212 when fixed. + } } } fn data_available(&mut self, payload: Vec<u8>) { - if !self.is_image_document { + if !self.is_synthesized_document { // FIXME: use Vec<u8> (html5ever #34) let data = UTF_8.decode(&payload, DecoderTrap::Replace).unwrap(); let parser = match self.parser.as_ref() { diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index e0c95285b34..9e6d98dc3dd 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -12,6 +12,8 @@ use dom::bindings::codegen::Bindings::TestBindingBinding::TestEnum::_empty; use dom::bindings::codegen::UnionTypes::BlobOrString; use dom::bindings::codegen::UnionTypes::EventOrString; use dom::bindings::codegen::UnionTypes::EventOrString::eString; +use dom::bindings::codegen::UnionTypes::EventOrUSVString; +use dom::bindings::codegen::UnionTypes::EventOrUSVString::eUSVString; use dom::bindings::codegen::UnionTypes::HTMLElementOrLong; use dom::bindings::codegen::UnionTypes::HTMLElementOrLong::eLong; use dom::bindings::global::{GlobalField, GlobalRef}; @@ -77,6 +79,8 @@ impl TestBindingMethods for TestBinding { fn SetUnionAttribute(&self, _: HTMLElementOrLong) {} fn Union2Attribute(&self) -> EventOrString { eString("".to_owned()) } fn SetUnion2Attribute(&self, _: EventOrString) {} + fn Union3Attribute(&self) -> EventOrUSVString { eUSVString(USVString("".to_owned())) } + fn SetUnion3Attribute(&self, _: EventOrUSVString) {} fn ArrayAttribute(&self, _: *mut JSContext) -> *mut JSObject { NullValue().to_object_or_null() } fn AnyAttribute(&self, _: *mut JSContext) -> JSVal { NullValue() } fn SetAnyAttribute(&self, _: *mut JSContext, _: HandleValue) {} diff --git a/components/script/dom/textencoder.rs b/components/script/dom/textencoder.rs index cde2115f40a..4e796699fc2 100644 --- a/components/script/dom/textencoder.rs +++ b/components/script/dom/textencoder.rs @@ -22,22 +22,20 @@ use util::str::DOMString; #[dom_struct] pub struct TextEncoder { reflector_: Reflector, - encoding: DOMString, #[ignore_heap_size_of = "Defined in rust-encoding"] encoder: EncodingRef, } impl TextEncoder { - fn new_inherited(encoding: DOMString, encoder: EncodingRef) -> TextEncoder { + fn new_inherited(encoder: EncodingRef) -> TextEncoder { TextEncoder { reflector_: Reflector::new(), - encoding: encoding, encoder: encoder, } } - pub fn new(global: GlobalRef, encoding: DOMString, encoder: EncodingRef) -> Root<TextEncoder> { - reflect_dom_object(box TextEncoder::new_inherited(encoding, encoder), + pub fn new(global: GlobalRef, encoder: EncodingRef) -> Root<TextEncoder> { + reflect_dom_object(box TextEncoder::new_inherited(encoder), global, TextEncoderBinding::Wrap) } @@ -55,7 +53,7 @@ impl TextEncoder { match encoding.name() { "utf-8" | "utf-16be" | "utf-16le" => { - Ok(TextEncoder::new(global, encoding.name().to_owned(), encoding)) + Ok(TextEncoder::new(global, encoding)) } _ => { debug!("Encoding Not UTF"); @@ -68,7 +66,7 @@ impl TextEncoder { impl TextEncoderMethods for TextEncoder { // https://encoding.spec.whatwg.org/#dom-textencoder-encoding fn Encoding(&self) -> DOMString { - self.encoding.clone() + self.encoder.name().to_owned() } #[allow(unsafe_code)] diff --git a/components/script/dom/touchlist.rs b/components/script/dom/touchlist.rs index ed40a5ee2ed..ae5313e855e 100644 --- a/components/script/dom/touchlist.rs +++ b/components/script/dom/touchlist.rs @@ -38,7 +38,7 @@ impl TouchListMethods for TouchList { /// https://w3c.github.io/touch-events/#widl-TouchList-item-getter-Touch-unsigned-long-index fn Item(&self, index: u32) -> Option<Root<Touch>> { - self.touches.get(index as usize).map(JS::root) + self.touches.get(index as usize).map(|js| Root::from_ref(&**js)) } /// https://w3c.github.io/touch-events/#widl-TouchList-item-getter-Touch-unsigned-long-index diff --git a/components/script/dom/treewalker.rs b/components/script/dom/treewalker.rs index 35a7291122d..38f723c995c 100644 --- a/components/script/dom/treewalker.rs +++ b/components/script/dom/treewalker.rs @@ -65,7 +65,7 @@ impl TreeWalker { impl TreeWalkerMethods for TreeWalker { // https://dom.spec.whatwg.org/#dom-treewalker-root fn Root(&self) -> Root<Node> { - self.root_node.root() + Root::from_ref(&*self.root_node) } // https://dom.spec.whatwg.org/#dom-treewalker-whattoshow diff --git a/components/script/dom/url.rs b/components/script/dom/url.rs index 448884a88cd..d4ed5b1bbed 100644 --- a/components/script/dom/url.rs +++ b/components/script/dom/url.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::URLBinding::{self, URLMethods}; use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::global::GlobalRef; @@ -10,7 +11,6 @@ use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::str::USVString; use dom::urlhelper::UrlHelper; use std::borrow::ToOwned; -use std::cell::RefCell; use url::{Host, ParseResult, Url, UrlParser}; use util::str::DOMString; @@ -20,7 +20,7 @@ pub struct URL { reflector_: Reflector, // https://url.spec.whatwg.org/#concept-urlutils-url - url: RefCell<Url>, + url: DOMRefCell<Url>, // https://url.spec.whatwg.org/#concept-urlutils-get-the-base base: Option<Url>, @@ -30,7 +30,7 @@ impl URL { fn new_inherited(url: Url, base: Option<Url>) -> URL { URL { reflector_: Reflector::new(), - url: RefCell::new(url), + url: DOMRefCell::new(url), base: base, } } diff --git a/components/script/dom/urlsearchparams.rs b/components/script/dom/urlsearchparams.rs index 88a576814ac..8fc3cdb6778 100644 --- a/components/script/dom/urlsearchparams.rs +++ b/components/script/dom/urlsearchparams.rs @@ -5,11 +5,12 @@ use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::URLSearchParamsBinding; use dom::bindings::codegen::Bindings::URLSearchParamsBinding::URLSearchParamsMethods; -use dom::bindings::codegen::UnionTypes::StringOrURLSearchParams; -use dom::bindings::codegen::UnionTypes::StringOrURLSearchParams::{eString, eURLSearchParams}; +use dom::bindings::codegen::UnionTypes::USVStringOrURLSearchParams; +use dom::bindings::codegen::UnionTypes::USVStringOrURLSearchParams::{eUSVString, eURLSearchParams}; use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; +use dom::bindings::str::USVString; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use encoding::types::EncodingRef; use url::form_urlencoded::{parse, serialize_with_encoding}; @@ -20,7 +21,7 @@ use util::str::DOMString; pub struct URLSearchParams { reflector_: Reflector, // https://url.spec.whatwg.org/#concept-urlsearchparams-list - list: DOMRefCell<Vec<(DOMString, DOMString)>>, + list: DOMRefCell<Vec<(String, String)>>, } impl URLSearchParams { @@ -37,14 +38,14 @@ impl URLSearchParams { } // https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams - pub fn Constructor(global: GlobalRef, init: Option<StringOrURLSearchParams>) -> + pub fn Constructor(global: GlobalRef, init: Option<USVStringOrURLSearchParams>) -> Fallible<Root<URLSearchParams>> { // Step 1. let query = URLSearchParams::new(global); match init { - Some(eString(init)) => { + Some(eUSVString(init)) => { // Step 2. - *query.r().list.borrow_mut() = parse(init.as_bytes()); + *query.r().list.borrow_mut() = parse(init.0.as_bytes()); }, Some(eURLSearchParams(init)) => { // Step 3. @@ -59,27 +60,27 @@ impl URLSearchParams { impl URLSearchParamsMethods for URLSearchParams { // https://url.spec.whatwg.org/#dom-urlsearchparams-append - fn Append(&self, name: DOMString, value: DOMString) { + fn Append(&self, name: USVString, value: USVString) { // Step 1. - self.list.borrow_mut().push((name, value)); + self.list.borrow_mut().push((name.0, value.0)); // Step 2. self.update_steps(); } // https://url.spec.whatwg.org/#dom-urlsearchparams-delete - fn Delete(&self, name: DOMString) { + fn Delete(&self, name: USVString) { // Step 1. - self.list.borrow_mut().retain(|&(ref k, _)| k != &name); + self.list.borrow_mut().retain(|&(ref k, _)| k != &name.0); // Step 2. self.update_steps(); } // https://url.spec.whatwg.org/#dom-urlsearchparams-get - fn Get(&self, name: DOMString) -> Option<DOMString> { + fn Get(&self, name: USVString) -> Option<USVString> { let list = self.list.borrow(); list.iter().filter_map(|&(ref k, ref v)| { - if k == &name { - Some(v.clone()) + if k == &name.0 { + Some(USVString(v.clone())) } else { None } @@ -87,31 +88,31 @@ impl URLSearchParamsMethods for URLSearchParams { } // https://url.spec.whatwg.org/#dom-urlsearchparams-has - fn Has(&self, name: DOMString) -> bool { + fn Has(&self, name: USVString) -> bool { let list = self.list.borrow(); - list.iter().find(|&&(ref k, _)| k == &name).is_some() + list.iter().any(|&(ref k, _)| k == &name.0) } // https://url.spec.whatwg.org/#dom-urlsearchparams-set - fn Set(&self, name: DOMString, value: DOMString) { + fn Set(&self, name: USVString, value: USVString) { let mut list = self.list.borrow_mut(); let mut index = None; let mut i = 0; list.retain(|&(ref k, _)| { if index.is_none() { - if k == &name { + if k == &name.0 { index = Some(i); } else { i += 1; } true } else { - k != &name + k != &name.0 } }); match index { - Some(index) => list[index].1 = value, - None => list.push((name, value)), + Some(index) => list[index].1 = value.0, + None => list.push((name.0, value.0)), }; self.update_steps(); } @@ -125,7 +126,7 @@ impl URLSearchParamsMethods for URLSearchParams { impl URLSearchParams { // https://url.spec.whatwg.org/#concept-urlencoded-serializer - pub fn serialize(&self, encoding: Option<EncodingRef>) -> DOMString { + pub fn serialize(&self, encoding: Option<EncodingRef>) -> String { let list = self.list.borrow(); serialize_with_encoding(list.iter(), encoding) } diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs index e577c06aa19..3932eb56dc8 100644 --- a/components/script/dom/webglbuffer.rs +++ b/components/script/dom/webglbuffer.rs @@ -71,7 +71,13 @@ impl WebGLBuffer { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteBuffer(self.id))).unwrap(); + let _ = self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteBuffer(self.id))); } } } + +impl Drop for WebGLBuffer { + fn drop(&mut self) { + self.delete(); + } +} diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index 60f550d63c7..86ed0e61b30 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -60,7 +60,13 @@ impl WebGLFramebuffer { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteFramebuffer(self.id))).unwrap(); + let _ = self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteFramebuffer(self.id))); } } } + +impl Drop for WebGLFramebuffer { + fn drop(&mut self) { + self.delete(); + } +} diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index 88052215254..44958f358ba 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -58,7 +58,7 @@ impl WebGLProgram { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteProgram(self.id))).unwrap(); + let _ = self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteProgram(self.id))); } } @@ -125,3 +125,9 @@ impl WebGLProgram { Ok(receiver.recv().unwrap()) } } + +impl Drop for WebGLProgram { + fn drop(&mut self) { + self.delete(); + } +} diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs index 9bca4b5972c..5257c4782a9 100644 --- a/components/script/dom/webglrenderbuffer.rs +++ b/components/script/dom/webglrenderbuffer.rs @@ -59,7 +59,7 @@ impl WebGLRenderbuffer { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteRenderbuffer(self.id))).unwrap(); + let _ = self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteRenderbuffer(self.id))); } } } diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 3e9cc0b60b7..a1db033c283 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -154,7 +154,7 @@ impl WebGLRenderingContext { } fn mark_as_dirty(&self) { - self.canvas.root().upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); + self.canvas.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); } } @@ -167,7 +167,7 @@ impl Drop for WebGLRenderingContext { impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1 fn Canvas(&self) -> Root<HTMLCanvasElement> { - self.canvas.root() + Root::from_ref(&*self.canvas) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1 @@ -849,8 +849,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { None => return, }; - let canvas = self.canvas.root(); - let window = window_from_node(canvas.r()); + let window = window_from_node(&*self.canvas); let img = match canvas_utils::request_image_from_cache(window.r(), img_url) { ImageResponse::Loaded(img) => img, diff --git a/components/script/dom/webglshader.rs b/components/script/dom/webglshader.rs index e272706a95e..6a2e558974c 100644 --- a/components/script/dom/webglshader.rs +++ b/components/script/dom/webglshader.rs @@ -5,6 +5,7 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use angle::hl::{BuiltInResources, Output, ShaderValidator}; use canvas_traits::{CanvasMsg, CanvasWebGLMsg, WebGLError, WebGLResult, WebGLShaderParameter}; +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::codegen::Bindings::WebGLShaderBinding; use dom::bindings::global::GlobalRef; @@ -12,7 +13,7 @@ use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; use dom::webglobject::WebGLObject; use ipc_channel::ipc::{self, IpcSender}; -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use std::sync::{ONCE_INIT, Once}; #[derive(Clone, Copy, PartialEq, Debug, JSTraceable, HeapSizeOf)] @@ -27,8 +28,8 @@ pub struct WebGLShader { webgl_object: WebGLObject, id: u32, gl_type: u32, - source: RefCell<Option<String>>, - info_log: RefCell<Option<String>>, + source: DOMRefCell<Option<String>>, + info_log: DOMRefCell<Option<String>>, is_deleted: Cell<bool>, compilation_status: Cell<ShaderCompilationStatus>, #[ignore_heap_size_of = "Defined in ipc-channel"] @@ -50,8 +51,8 @@ impl WebGLShader { webgl_object: WebGLObject::new_inherited(), id: id, gl_type: shader_type, - source: RefCell::new(None), - info_log: RefCell::new(None), + source: DOMRefCell::new(None), + info_log: DOMRefCell::new(None), is_deleted: Cell::new(false), compilation_status: Cell::new(ShaderCompilationStatus::NotCompiled), renderer: renderer, @@ -121,7 +122,7 @@ impl WebGLShader { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteShader(self.id))).unwrap() + let _ = self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteShader(self.id))); } } @@ -152,3 +153,9 @@ impl WebGLShader { *self.source.borrow_mut() = Some(source); } } + +impl Drop for WebGLShader { + fn drop(&mut self) { + self.delete(); + } +} diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index f6a7acc786b..2288c9be7f7 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -78,7 +78,7 @@ impl WebGLTexture { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteTexture(self.id))).unwrap(); + let _ = self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteTexture(self.id))); } } @@ -145,3 +145,9 @@ impl WebGLTexture { } } } + +impl Drop for WebGLTexture { + fn drop(&mut self) { + self.delete(); + } +} diff --git a/components/script/dom/webidls/HTMLButtonElement.webidl b/components/script/dom/webidls/HTMLButtonElement.webidl index 0edba3293d4..56ee8de8d74 100644 --- a/components/script/dom/webidls/HTMLButtonElement.webidl +++ b/components/script/dom/webidls/HTMLButtonElement.webidl @@ -25,5 +25,5 @@ interface HTMLButtonElement : HTMLElement { //boolean reportValidity(); //void setCustomValidity(DOMString error); - //readonly attribute NodeList labels; + readonly attribute NodeList labels; }; diff --git a/components/script/dom/webidls/HTMLInputElement.webidl b/components/script/dom/webidls/HTMLInputElement.webidl index 0628f386ea6..a5472818afe 100644 --- a/components/script/dom/webidls/HTMLInputElement.webidl +++ b/components/script/dom/webidls/HTMLInputElement.webidl @@ -57,7 +57,7 @@ interface HTMLInputElement : HTMLElement { //boolean reportValidity(); //void setCustomValidity(DOMString error); - //readonly attribute NodeList labels; + readonly attribute NodeList labels; //void select(); // attribute unsigned long selectionStart; diff --git a/components/script/dom/webidls/HTMLMeterElement.webidl b/components/script/dom/webidls/HTMLMeterElement.webidl index 2e174381fcb..29f6ed89205 100644 --- a/components/script/dom/webidls/HTMLMeterElement.webidl +++ b/components/script/dom/webidls/HTMLMeterElement.webidl @@ -11,5 +11,5 @@ interface HTMLMeterElement : HTMLElement { // attribute double low; // attribute double high; // attribute double optimum; - //readonly attribute NodeList labels; + readonly attribute NodeList labels; }; diff --git a/components/script/dom/webidls/HTMLOutputElement.webidl b/components/script/dom/webidls/HTMLOutputElement.webidl index 86ca8ecf86b..aa85afd7b8d 100644 --- a/components/script/dom/webidls/HTMLOutputElement.webidl +++ b/components/script/dom/webidls/HTMLOutputElement.webidl @@ -20,5 +20,5 @@ interface HTMLOutputElement : HTMLElement { //boolean reportValidity(); //void setCustomValidity(DOMString error); - //readonly attribute NodeList labels; + readonly attribute NodeList labels; }; diff --git a/components/script/dom/webidls/HTMLProgressElement.webidl b/components/script/dom/webidls/HTMLProgressElement.webidl index 46ffa6b83f2..3b4b0f4032f 100644 --- a/components/script/dom/webidls/HTMLProgressElement.webidl +++ b/components/script/dom/webidls/HTMLProgressElement.webidl @@ -8,5 +8,5 @@ interface HTMLProgressElement : HTMLElement { // attribute double value; // attribute double max; //readonly attribute double position; - //readonly attribute NodeList labels; + readonly attribute NodeList labels; }; diff --git a/components/script/dom/webidls/HTMLSelectElement.webidl b/components/script/dom/webidls/HTMLSelectElement.webidl index fb6aed7e40c..599cb9f74de 100644 --- a/components/script/dom/webidls/HTMLSelectElement.webidl +++ b/components/script/dom/webidls/HTMLSelectElement.webidl @@ -36,5 +36,5 @@ interface HTMLSelectElement : HTMLElement { //boolean reportValidity(); //void setCustomValidity(DOMString error); - //readonly attribute NodeList labels; + readonly attribute NodeList labels; }; diff --git a/components/script/dom/webidls/HTMLTextAreaElement.webidl b/components/script/dom/webidls/HTMLTextAreaElement.webidl index d7a13d9c959..797a537d0cc 100644 --- a/components/script/dom/webidls/HTMLTextAreaElement.webidl +++ b/components/script/dom/webidls/HTMLTextAreaElement.webidl @@ -35,7 +35,7 @@ interface HTMLTextAreaElement : HTMLElement { //boolean reportValidity(); //void setCustomValidity(DOMString error); - //readonly attribute NodeList labels; + readonly attribute NodeList labels; //void select(); // attribute unsigned long selectionStart; diff --git a/components/script/dom/webidls/TestBinding.webidl b/components/script/dom/webidls/TestBinding.webidl index 181909721aa..f845be7dc15 100644 --- a/components/script/dom/webidls/TestBinding.webidl +++ b/components/script/dom/webidls/TestBinding.webidl @@ -89,6 +89,7 @@ interface TestBinding { attribute Blob interfaceAttribute; attribute (HTMLElement or long) unionAttribute; attribute (Event or DOMString) union2Attribute; + attribute (Event or USVString) union3Attribute; readonly attribute Uint8ClampedArray arrayAttribute; attribute any anyAttribute; attribute object objectAttribute; diff --git a/components/script/dom/webidls/URLSearchParams.webidl b/components/script/dom/webidls/URLSearchParams.webidl index 4ab1cd43019..4804056273f 100644 --- a/components/script/dom/webidls/URLSearchParams.webidl +++ b/components/script/dom/webidls/URLSearchParams.webidl @@ -7,14 +7,14 @@ * https://url.spec.whatwg.org/#interface-urlsearchparams */ -[Constructor(optional (DOMString or URLSearchParams) init/* = ""*/)] +[Constructor(optional (USVString or URLSearchParams) init/* = ""*/)] interface URLSearchParams { - void append(DOMString name, DOMString value); - void delete(DOMString name); - DOMString? get(DOMString name); - // sequence<DOMString> getAll(DOMString name); - boolean has(DOMString name); - void set(DOMString name, DOMString value); + void append(USVString name, USVString value); + void delete(USVString name); + USVString? get(USVString name); + // sequence<USVString> getAll(USVString name); + boolean has(USVString name); + void set(USVString name, USVString value); // iterable<USVString, USVString>; stringifier; }; diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index b6f9a333521..ca71fc93487 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -29,7 +29,7 @@ use net_traits::hosts::replace_hosts; use script_task::ScriptTaskEventCategory::WebSocketEvent; use script_task::{CommonScriptMsg, Runnable}; use std::borrow::ToOwned; -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use std::sync::{Arc, Mutex}; use std::{ptr, slice}; use util::str::DOMString; @@ -134,7 +134,7 @@ pub struct WebSocket { buffered_amount: Cell<u32>, clearing_buffer: Cell<bool>, //Flag to tell if there is a running task to clear buffered_amount #[ignore_heap_size_of = "Defined in std"] - sender: RefCell<Option<Arc<Mutex<Sender<WebSocketStream>>>>>, + sender: DOMRefCell<Option<Arc<Mutex<Sender<WebSocketStream>>>>>, failed: Cell<bool>, //Flag to tell if websocket was closed due to failure full: Cell<bool>, //Flag to tell if websocket queue is full clean_close: Cell<bool>, //Flag to tell if the websocket closed cleanly (not due to full or fail) @@ -176,7 +176,7 @@ impl WebSocket { buffered_amount: Cell::new(0), clearing_buffer: Cell::new(false), failed: Cell::new(false), - sender: RefCell::new(None), + sender: DOMRefCell::new(None), full: Cell::new(false), clean_close: Cell::new(true), code: Cell::new(0), diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index d91be770454..1926a30b06d 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -59,7 +59,7 @@ use script_traits::{ConstellationControlMsg, TimerEventChan, TimerEventId, Timer use selectors::parser::PseudoElement; use std::ascii::AsciiExt; use std::borrow::ToOwned; -use std::cell::{Cell, Ref, RefCell}; +use std::cell::{Cell, Ref}; use std::collections::HashSet; use std::default::Default; use std::ffi::CString; @@ -145,9 +145,9 @@ pub struct Window { /// For sending timeline markers. Will be ignored if /// no devtools server #[ignore_heap_size_of = "TODO(#6909) need to measure HashSet"] - devtools_markers: RefCell<HashSet<TimelineMarkerType>>, + devtools_markers: DOMRefCell<HashSet<TimelineMarkerType>>, #[ignore_heap_size_of = "channels are hard"] - devtools_marker_sender: RefCell<Option<IpcSender<TimelineMarker>>>, + devtools_marker_sender: DOMRefCell<Option<IpcSender<TimelineMarker>>>, /// A flag to indicate whether the developer tools have requested live updates of /// page changes. @@ -209,7 +209,7 @@ pub struct Window { /// A channel for communicating results of async scripts back to the webdriver server #[ignore_heap_size_of = "channels are hard"] - webdriver_script_chan: RefCell<Option<IpcSender<WebDriverJSResult>>>, + webdriver_script_chan: DOMRefCell<Option<IpcSender<WebDriverJSResult>>>, /// The current state of the window object current_state: Cell<WindowState>, @@ -911,7 +911,7 @@ impl Window { } // Send new document and relevant styles to layout. - let reflow = box ScriptReflow { + let reflow = ScriptReflow { reflow_info: Reflow { goal: goal, page_clip_rect: self.page_clip_rect.get(), @@ -1277,10 +1277,10 @@ impl Window { pending_reflow_count: Cell::new(0), current_state: Cell::new(WindowState::Alive), - devtools_marker_sender: RefCell::new(None), - devtools_markers: RefCell::new(HashSet::new()), + devtools_marker_sender: DOMRefCell::new(None), + devtools_markers: DOMRefCell::new(HashSet::new()), devtools_wants_updates: Cell::new(false), - webdriver_script_chan: RefCell::new(None), + webdriver_script_chan: DOMRefCell::new(None), }; WindowBinding::Wrap(runtime.cx(), win) diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index e835f70dcb5..e8a4ddc638a 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -164,10 +164,9 @@ impl XMLHttpRequest { request_headers: DOMRefCell::new(Headers::new()), request_body_len: Cell::new(0), sync: Cell::new(false), - send_flag: Cell::new(false), - upload_complete: Cell::new(false), upload_events: Cell::new(false), + send_flag: Cell::new(false), global: GlobalField::from_rooted(&global), timeout_cancel: DOMRefCell::new(None), @@ -467,7 +466,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { // https://xhr.spec.whatwg.org/#the-upload-attribute fn Upload(&self) -> Root<XMLHttpRequestUpload> { - self.upload.root() + Root::from_ref(&*self.upload) } // https://xhr.spec.whatwg.org/#the-send()-method @@ -882,7 +881,7 @@ impl XMLHttpRequest { _ => "error", }; - let upload_complete: &Cell<bool> = &self.upload_complete; + let upload_complete = &self.upload_complete; if !upload_complete.get() { upload_complete.set(true); self.dispatch_upload_progress_event("progress".to_owned(), None); @@ -1111,7 +1110,7 @@ impl Extractable for SendParam { }, eURLSearchParams(ref usp) => { // Default encoding is UTF-8. - usp.r().serialize(None).as_bytes().to_owned() + usp.r().serialize(None).into_bytes() }, } } diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 5c41a04363c..acb69a02321 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -47,7 +47,7 @@ pub enum Msg { SetQuirksMode, /// Requests a reflow. - Reflow(Box<ScriptReflow>), + Reflow(ScriptReflow), /// Get an RPC interface. GetRPC(Sender<Box<LayoutRPC + Send>>), diff --git a/components/script/lib.rs b/components/script/lib.rs index b442a3b2d31..e4481fb7d49 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -70,7 +70,7 @@ extern crate rand; extern crate rustc_serialize; extern crate rustc_unicode; extern crate script_traits; -extern crate selectors; +#[macro_use(state_pseudo_classes)] extern crate selectors; extern crate serde; extern crate smallvec; extern crate string_cache; diff --git a/components/script/page.rs b/components/script/page.rs index b6b35c6119a..67cb1ca46ed 100644 --- a/components/script/page.rs +++ b/components/script/page.rs @@ -68,11 +68,11 @@ impl Page { } pub fn window(&self) -> Root<Window> { - self.frame.borrow().as_ref().unwrap().window.root() + Root::from_ref(&*self.frame.borrow().as_ref().unwrap().window) } pub fn document(&self) -> Root<Document> { - self.frame.borrow().as_ref().unwrap().document.root() + Root::from_ref(&*self.frame.borrow().as_ref().unwrap().document) } // must handle root case separately diff --git a/components/script/parse/html.rs b/components/script/parse/html.rs index 371ca454cc2..aa5a03c6a08 100644 --- a/components/script/parse/html.rs +++ b/components/script/parse/html.rs @@ -9,8 +9,8 @@ use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::inheritance::{Castable, CharacterDataTypeId, NodeTypeId}; -use dom::bindings::js::{JS, Root}; -use dom::bindings::js::{RootedReference}; + +use dom::bindings::js::{JS, RootedReference}; use dom::characterdata::CharacterData; use dom::comment::Comment; use dom::document::Document; @@ -44,11 +44,10 @@ impl<'a> TreeSink for servohtmlparser::Sink { type Handle = JS<Node>; fn get_document(&mut self) -> JS<Node> { - JS::from_ref(self.document.root().upcast()) + JS::from_ref(self.document.upcast()) } fn get_template_contents(&self, target: JS<Node>) -> JS<Node> { - let target = target.root(); let template = target.downcast::<HTMLTemplateElement>() .expect("tried to get template contents of non-HTMLTemplateElement in HTML parsing"); JS::from_ref(template.Content().upcast()) @@ -59,8 +58,7 @@ impl<'a> TreeSink for servohtmlparser::Sink { } fn elem_name(&self, target: JS<Node>) -> QualName { - let node: Root<Node> = target.root(); - let elem = node.downcast::<Element>() + let elem = target.downcast::<Element>() .expect("tried to get name of non-Element in HTML parsing"); QualName { ns: elem.namespace().clone(), @@ -70,8 +68,7 @@ impl<'a> TreeSink for servohtmlparser::Sink { fn create_element(&mut self, name: QualName, attrs: Vec<Attribute>) -> JS<Node> { - let doc = self.document.root(); - let elem = Element::create(name, None, doc.r(), + let elem = Element::create(name, None, &*self.document, ElementCreator::ParserCreated); for attr in attrs { @@ -82,8 +79,7 @@ impl<'a> TreeSink for servohtmlparser::Sink { } fn create_comment(&mut self, text: StrTendril) -> JS<Node> { - let doc = self.document.root(); - let comment = Comment::new(text.into(), doc.r()); + let comment = Comment::new(text.into(), &*self.document); JS::from_ref(comment.upcast()) } @@ -91,14 +87,13 @@ impl<'a> TreeSink for servohtmlparser::Sink { sibling: JS<Node>, new_node: NodeOrText<JS<Node>>) -> Result<(), NodeOrText<JS<Node>>> { // If there is no parent, return the node to the parser. - let sibling: Root<Node> = sibling.root(); - let parent = match sibling.r().GetParentNode() { + let parent = match sibling.GetParentNode() { Some(p) => p, None => return Err(new_node), }; let child = self.get_or_create(new_node); - assert!(parent.r().InsertBefore(child.r(), Some(sibling.r())).is_ok()); + assert!(parent.r().InsertBefore(child.r(), Some(&*sibling)).is_ok()); Ok(()) } @@ -107,29 +102,26 @@ impl<'a> TreeSink for servohtmlparser::Sink { } fn set_quirks_mode(&mut self, mode: QuirksMode) { - let doc = self.document.root(); - doc.r().set_quirks_mode(mode); + self.document.set_quirks_mode(mode); } fn append(&mut self, parent: JS<Node>, child: NodeOrText<JS<Node>>) { - let parent: Root<Node> = parent.root(); let child = self.get_or_create(child); // FIXME(#3701): Use a simpler algorithm and merge adjacent text nodes - assert!(parent.r().AppendChild(child.r()).is_ok()); + assert!(parent.AppendChild(child.r()).is_ok()); } fn append_doctype_to_document(&mut self, name: StrTendril, public_id: StrTendril, system_id: StrTendril) { - let doc = self.document.root(); + let doc = &*self.document; let doctype = DocumentType::new( - name.into(), Some(public_id.into()), Some(system_id.into()), doc.r()); + name.into(), Some(public_id.into()), Some(system_id.into()), doc); doc.upcast::<Node>().AppendChild(doctype.upcast()).expect("Appending failed"); } fn add_attrs_if_missing(&mut self, target: JS<Node>, attrs: Vec<Attribute>) { - let node: Root<Node> = target.root(); - let elem = node.downcast::<Element>() + let elem = target.downcast::<Element>() .expect("tried to set attrs on non-Element in HTML parsing"); for attr in attrs { elem.set_attribute_from_parser(attr.name, attr.value.into(), None); @@ -137,20 +129,17 @@ impl<'a> TreeSink for servohtmlparser::Sink { } fn remove_from_parent(&mut self, target: JS<Node>) { - let node = target.root(); - if let Some(ref parent) = node.r().GetParentNode() { - parent.r().RemoveChild(node.r()).unwrap(); + if let Some(ref parent) = target.GetParentNode() { + parent.r().RemoveChild(&*target).unwrap(); } } fn mark_script_already_started(&mut self, node: JS<Node>) { - let node: Root<Node> = node.root(); let script = node.downcast::<HTMLScriptElement>(); script.map(|script| script.mark_already_started()); } fn complete_script(&mut self, node: JS<Node>) -> NextParserState { - let node: Root<Node> = node.root(); let script = node.downcast::<HTMLScriptElement>(); if let Some(script) = script { return script.prepare(); @@ -159,11 +148,7 @@ impl<'a> TreeSink for servohtmlparser::Sink { } fn reparent_children(&mut self, node: JS<Node>, new_parent: JS<Node>) { - let new_parent = new_parent.root(); - let new_parent = new_parent.r(); - let old_parent = node.root(); - let old_parent = old_parent.r(); - while let Some(ref child) = old_parent.GetFirstChild() { + while let Some(ref child) = node.GetFirstChild() { new_parent.AppendChild(child.r()).unwrap(); } @@ -180,11 +165,10 @@ impl<'a> Serializable for &'a Node { let name = QualName::new(elem.namespace().clone(), elem.local_name().clone()); if traversal_scope == IncludeNode { - let attrs = elem.attrs().iter().map(|at| { - let attr = at.root(); - let qname = QualName::new(attr.r().namespace().clone(), - attr.r().local_name().clone()); - let value = attr.r().value().clone(); + let attrs = elem.attrs().iter().map(|attr| { + let qname = QualName::new(attr.namespace().clone(), + attr.local_name().clone()); + let value = attr.value().clone(); (qname, value) }).collect::<Vec<_>>(); let attr_refs = attrs.iter().map(|&(ref qname, ref value)| { diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 7efed232426..7a3ddd43837 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -415,7 +415,7 @@ pub struct ScriptTask { mouse_over_targets: DOMRefCell<Vec<JS<Element>>>, /// List of pipelines that have been owned and closed by this script task. - closed_pipelines: RefCell<HashSet<PipelineId>>, + closed_pipelines: DOMRefCell<HashSet<PipelineId>>, scheduler_chan: Sender<TimerEventRequest>, timer_event_chan: Sender<TimerEvent>, @@ -644,7 +644,7 @@ impl ScriptTask { js_runtime: Rc::new(runtime), mouse_over_targets: DOMRefCell::new(vec!()), - closed_pipelines: RefCell::new(HashSet::new()), + closed_pipelines: DOMRefCell::new(HashSet::new()), scheduler_chan: state.scheduler_chan, timer_event_chan: timer_event_chan, @@ -1657,28 +1657,34 @@ impl ScriptTask { } fn notify_devtools(&self, title: DOMString, url: Url, ids: (PipelineId, Option<WorkerId>)) { - match self.devtools_chan { - None => {} - Some(ref chan) => { - let page_info = DevtoolsPageInfo { - title: title, - url: url, - }; - chan.send(ScriptToDevtoolsControlMsg::NewGlobal( - ids, - self.devtools_sender.clone(), - page_info)).unwrap(); - } + if let Some(ref chan) = self.devtools_chan { + let page_info = DevtoolsPageInfo { + title: title, + url: url, + }; + chan.send(ScriptToDevtoolsControlMsg::NewGlobal( + ids, + self.devtools_sender.clone(), + page_info)).unwrap(); } } fn scroll_fragment_point(&self, pipeline_id: PipelineId, element: &Element) { - let rect = element.upcast::<Node>().get_bounding_content_box(); - let point = Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()); - // FIXME(#2003, pcwalton): This is pretty bogus when multiple layers are involved. + // FIXME(#8275, pcwalton): This is pretty bogus when multiple layers are involved. // Really what needs to happen is that this needs to go through layout to ask which // layer the element belongs to, and have it send the scroll message to the // compositor. + let rect = element.upcast::<Node>().get_bounding_content_box(); + + // In order to align with element edges, we snap to unscaled pixel boundaries, since the + // paint task currently does the same for drawing elements. This is important for pages + // that require pixel perfect scroll positioning for proper display (like Acid2). Since we + // don't have the device pixel ratio here, this might not be accurate, but should work as + // long as the ratio is a whole number. Once #8275 is fixed this should actually take into + // account the real device pixel ratio. + let point = Point2D::new(rect.origin.x.to_nearest_px() as f32, + rect.origin.y.to_nearest_px() as f32); + self.compositor.borrow_mut().send(ScriptToCompositorMsg::ScrollFragmentPoint( pipeline_id, LayerId::null(), point, false)).unwrap(); } @@ -1742,9 +1748,8 @@ impl ScriptTask { // Notify Constellation about the topmost anchor mouse over target. for target in &*mouse_over_targets { - let target = target.root(); if target.upcast::<Node>().is_anchor_element() { - let status = target.r().get_attribute(&ns!(""), &atom!("href")) + let status = target.get_attribute(&ns!(""), &atom!("href")) .and_then(|href| { let value = href.value(); let url = document.r().url(); diff --git a/components/script/timers.rs b/components/script/timers.rs index 75d7271154d..a7395de5e02 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -78,7 +78,7 @@ impl Ord for Timer { fn cmp(&self, other: &Timer) -> Ordering { match self.next_call.cmp(&other.next_call).reverse() { Ordering::Equal => self.handle.cmp(&other.handle).reverse(), - res @ _ => res + res => res } } } diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index e8427eb9257..321e000a1be 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -115,7 +115,7 @@ pub fn handle_get_frame_id(page: &Rc<Page>, pub fn handle_find_element_css(page: &Rc<Page>, _pipeline: PipelineId, selector: String, reply: IpcSender<Result<Option<String>, ()>>) { - reply.send(match page.document().r().QuerySelector(selector.clone()) { + reply.send(match page.document().r().QuerySelector(selector) { Ok(node) => { Ok(node.map(|x| x.upcast::<Node>().get_unique_id())) } @@ -127,7 +127,7 @@ pub fn handle_find_elements_css(page: &Rc<Page>, _pipeline: PipelineId, selector: String, reply: IpcSender<Result<Vec<String>, ()>>) { - reply.send(match page.document().r().QuerySelectorAll(selector.clone()) { + reply.send(match page.document().r().QuerySelectorAll(selector) { Ok(ref nodes) => { let mut result = Vec::with_capacity(nodes.r().Length() as usize); for i in 0..nodes.r().Length() { diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index f1642248dd7..3327cec04a8 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -24,6 +24,7 @@ dependencies = [ "net 0.0.1", "net_tests 0.0.1", "net_traits 0.0.1", + "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", "profile 0.0.1", "profile_traits 0.0.1", "script 0.0.1", @@ -139,6 +140,11 @@ dependencies = [ ] [[package]] +name = "brotli" +version = "0.3.17" +source = "git+https://github.com/ende76/brotli-rs#4a8c42cce771ded65fe64d6816f5d7303006b2ea" + +[[package]] name = "byteorder" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -474,18 +480,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "energymon" version = "0.1.0" -source = "git+https://github.com/energymon/energymon-rust.git?rev=67f74732ac#67f74732ac0acc682659f7e81836155a32188fd0" +source = "git+https://github.com/energymon/energymon-rust.git?rev=eba1d8a#eba1d8a7256b710230ea2c1b26525b88bfcb529d" dependencies = [ "energy-monitor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "energymon-default-sys 0.1.0 (git+https://github.com/energymon/energymon-default-sys.git)", - "energymon-sys 0.1.0 (git+https://github.com/energymon/energymon-sys.git)", + "energymon-default-sys 0.1.0 (git+https://github.com/energymon/energymon-sys.git)", "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "energymon-default-sys" version = "0.1.0" -source = "git+https://github.com/energymon/energymon-default-sys.git#82dd2f6762b492ced15d8446b70569778200c287" +source = "git+https://github.com/energymon/energymon-sys.git#82756eee725db3ccb658f14857947a0260743d4d" dependencies = [ "energymon-sys 0.1.0 (git+https://github.com/energymon/energymon-sys.git)", "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -495,7 +500,7 @@ dependencies = [ [[package]] name = "energymon-sys" version = "0.1.0" -source = "git+https://github.com/energymon/energymon-sys.git#6306f70e5d5c824fa168e43521385798fd1b890b" +source = "git+https://github.com/energymon/energymon-sys.git#82756eee725db3ccb658f14857947a0260743d4d" dependencies = [ "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -751,36 +756,6 @@ dependencies = [ ] [[package]] -name = "glutin" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "android_glue 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cgl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cocoa 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dwmapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gl_common 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gl_generator 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "khronos_api 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "osmesa-sys 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "shared_library 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-client 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-kbd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-window 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "x11-dl 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "glutin_app" version = "0.0.1" dependencies = [ @@ -1040,7 +1015,7 @@ dependencies = [ "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "script 0.0.1", "script_traits 0.0.1", - "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", + "selectors 0.2.0 (git+https://github.com/servo/rust-selectors)", "serde 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1201,6 +1176,7 @@ dependencies = [ name = "net" version = "0.0.1" dependencies = [ + "brotli 0.3.17 (git+https://github.com/ende76/brotli-rs)", "cookie 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", "euclid 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1304,14 +1280,14 @@ dependencies = [ [[package]] name = "offscreen_gl_context" version = "0.1.0" -source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#a33af19355dfdd0076a3f2836dc66e0fea44bcab" +source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#aae6e57969c553973c43ce5e4246831ccc2868f0" dependencies = [ "cgl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "gl_generator 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "glutin 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin 0.4.0 (git+https://github.com/servo/glutin?branch=servo)", "khronos_api 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)", "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1436,7 +1412,7 @@ name = "profile_traits" version = "0.0.1" dependencies = [ "energy-monitor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "energymon 0.1.0 (git+https://github.com/energymon/energymon-rust.git?rev=67f74732ac)", + "energymon 0.1.0 (git+https://github.com/energymon/energymon-rust.git?rev=eba1d8a)", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", "plugins 0.0.1", "serde 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1549,7 +1525,7 @@ dependencies = [ "rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "script_traits 0.0.1", - "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", + "selectors 0.2.0 (git+https://github.com/servo/rust-selectors)", "serde 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1594,8 +1570,8 @@ dependencies = [ [[package]] name = "selectors" -version = "0.1.0" -source = "git+https://github.com/servo/rust-selectors#1e1e44c2f4090e8beb95a8d27f184aefcf91a362" +version = "0.2.0" +source = "git+https://github.com/servo/rust-selectors#53f5e09a37684f6a42eb894d7a6fd0b14380a1c6" dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1752,7 +1728,7 @@ dependencies = [ "num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", + "selectors 0.2.0 (git+https://github.com/servo/rust-selectors)", "serde 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1770,7 +1746,7 @@ dependencies = [ "app_units 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", + "selectors 0.2.0 (git+https://github.com/servo/rust-selectors)", "string_cache 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_plugin 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", @@ -1790,7 +1766,7 @@ dependencies = [ "num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", + "selectors 0.2.0 (git+https://github.com/servo/rust-selectors)", "serde 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1935,7 +1911,7 @@ dependencies = [ "plugins 0.0.1", "rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", + "selectors 0.2.0 (git+https://github.com/servo/rust-selectors)", "serde 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index db611072946..d1bb7634689 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -133,6 +133,9 @@ features = ["plugins"] [dependencies.gleam] version = "0.1" +[dependencies.offscreen_gl_context] +git = "https://github.com/ecoal95/rust-offscreen-rendering-context" + [dependencies] env_logger = "0.3" time = "0.1.12" diff --git a/components/servo/main.rs b/components/servo/main.rs index 3e81da46f1f..6d830e7be73 100644 --- a/components/servo/main.rs +++ b/components/servo/main.rs @@ -23,18 +23,31 @@ extern crate android_glue; // The window backed by glutin extern crate glutin_app as app; extern crate env_logger; +#[macro_use] +extern crate log; // The Servo engine extern crate servo; extern crate time; +extern crate gleam; +extern crate offscreen_gl_context; + +use gleam::gl; +use offscreen_gl_context::GLContext; use servo::Browser; use servo::compositing::windowing::WindowEvent; use servo::net_traits::hosts; use servo::util::opts; -#[cfg(target_os = "android")] -use std::borrow::ToOwned; use std::rc::Rc; +#[cfg(not(target_os = "android"))] +fn load_gl_when_headless() { + gl::load_with(|addr| GLContext::get_proc_address(addr) as *const _); +} + +#[cfg(target_os = "android")] +fn load_gl_when_headless() {} + fn main() { env_logger::init().unwrap(); @@ -47,6 +60,9 @@ fn main() { hosts::global_init(); let window = if opts::get().headless { + // Load gl functions even when in headless mode, + // to avoid crashing with webgl + load_gl_when_headless(); None } else { Some(app::create_window(std::ptr::null_mut())) @@ -130,11 +146,39 @@ fn setup_logging() { } #[cfg(target_os = "android")] +/// Attempt to read parameters from a file since they are not passed to us in Android environments. +/// The first line should be the "servo" argument and the last should be the URL to load. +/// Blank lines and those beginning with a '#' are ignored. +/// Each line should be a separate parameter as would be parsed by the shell. +/// For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4 lines. fn args() -> Vec<String> { - vec![ - "servo".to_owned(), - "http://en.wikipedia.org/wiki/Rust".to_owned() - ] + use std::error::Error; + use std::fs::File; + use std::io::{BufRead, BufReader}; + + const PARAMS_FILE: &'static str = "/sdcard/servo/android_params"; + match File::open(PARAMS_FILE) { + Ok(f) => { + let mut vec = Vec::new(); + let file = BufReader::new(&f); + for line in file.lines() { + let l = line.unwrap().trim().to_owned(); + // ignore blank lines and those that start with a '#' + match l.is_empty() || l.as_bytes()[0] == b'#' { + true => (), + false => vec.push(l), + } + } + vec + }, + Err(e) => { + debug!("Failed to open params file '{}': {}", PARAMS_FILE, Error::description(&e)); + vec![ + "servo".to_owned(), + "http://en.wikipedia.org/wiki/Rust".to_owned() + ] + }, + } } #[cfg(not(target_os = "android"))] diff --git a/components/style/animation.rs b/components/style/animation.rs index 30c0b658fec..a073c39ae73 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -28,7 +28,7 @@ use std::iter::repeat; use util::bezier::Bezier; use values::CSSFloat; use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone}; -use values::computed::{Calc, Length, LengthOrPercentage, Time}; +use values::computed::{CalcLengthOrPercentage, Length, LengthOrPercentage, Time}; #[derive(Clone, Debug)] pub struct PropertyAnimation { @@ -461,10 +461,10 @@ impl Interpolate for VerticalAlign { fn interpolate(&self, other: &VerticalAlign, time: f64) -> Option<VerticalAlign> { match (*self, *other) { - (VerticalAlign::Length(ref this), - VerticalAlign::Length(ref other)) => { + (VerticalAlign::LengthOrPercentage(LengthOrPercentage::Length(ref this)), + VerticalAlign::LengthOrPercentage(LengthOrPercentage::Length(ref other))) => { this.interpolate(other, time).and_then(|value| { - Some(VerticalAlign::Length(value)) + Some(VerticalAlign::LengthOrPercentage(LengthOrPercentage::Length(value))) }) } (_, _) => None, @@ -513,11 +513,11 @@ impl Interpolate for Color { } } -impl Interpolate for Calc { +impl Interpolate for CalcLengthOrPercentage { #[inline] - fn interpolate(&self, other: &Calc, time: f64) - -> Option<Calc> { - Some(Calc { + fn interpolate(&self, other: &CalcLengthOrPercentage, time: f64) + -> Option<CalcLengthOrPercentage> { + Some(CalcLengthOrPercentage { length: self.length().interpolate(&other.length(), time), percentage: self.percentage().interpolate(&other.percentage(), time), }) @@ -542,8 +542,8 @@ impl Interpolate for LengthOrPercentage { }) } (this, other) => { - let this: Calc = From::from(this); - let other: Calc = From::from(other); + let this: CalcLengthOrPercentage = From::from(this); + let other: CalcLengthOrPercentage = From::from(other); this.interpolate(&other, time).and_then(|value| { Some(LengthOrPercentage::Calc(value)) }) @@ -573,8 +573,8 @@ impl Interpolate for LengthOrPercentageOrAuto { Some(LengthOrPercentageOrAuto::Auto) } (this, other) => { - let this: Option<Calc> = From::from(this); - let other: Option<Calc> = From::from(other); + let this: Option<CalcLengthOrPercentage> = From::from(this); + let other: Option<CalcLengthOrPercentage> = From::from(other); this.interpolate(&other, time).unwrap_or(None).and_then(|value| { Some(LengthOrPercentageOrAuto::Calc(value)) }) diff --git a/components/style/lib.rs b/components/style/lib.rs index ed898ff2f60..997cd90b79c 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -34,7 +34,7 @@ extern crate euclid; extern crate fnv; extern crate num; extern crate rustc_serialize; -extern crate selectors; +#[macro_use(state_pseudo_classes)] extern crate selectors; extern crate serde; extern crate smallvec; extern crate string_cache; @@ -48,6 +48,7 @@ pub mod legacy; pub mod media_queries; pub mod node; pub mod parser; +pub mod restyle_hints; pub mod selector_matching; pub mod stylesheets; #[macro_use] diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index c8f1834b1ac..2912d4ea871 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -611,7 +611,7 @@ pub mod longhands { if input.try(|input| input.expect_ident_matching("auto")).is_ok() { Ok(computed_value::T::Auto) } else { - Ok(computed_value::T::Number(try!(input.expect_integer()) as i32)) + specified::parse_integer(input).map(computed_value::T::Number) } } </%self:longhand> @@ -658,18 +658,16 @@ pub mod longhands { #[derive(Clone, PartialEq, Copy)] pub enum SpecifiedValue { Normal, - Length(specified::Length), Number(CSSFloat), - Percentage(CSSFloat), + LengthOrPercentage(specified::LengthOrPercentage), } impl ToCss for SpecifiedValue { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { SpecifiedValue::Normal => dest.write_str("normal"), - SpecifiedValue::Length(length) => length.to_css(dest), + SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest), SpecifiedValue::Number(number) => write!(dest, "{}", number), - SpecifiedValue::Percentage(number) => write!(dest, "{}%", number * 100.), } } } @@ -677,22 +675,19 @@ pub mod longhands { pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { use cssparser::Token; use std::ascii::AsciiExt; - match try!(input.next()) { - Token::Number(ref value) if value.value >= 0. => { - Ok(SpecifiedValue::Number(value.value)) - } - Token::Percentage(ref value) if value.unit_value >= 0. => { - Ok(SpecifiedValue::Percentage(value.unit_value)) - } - Token::Dimension(ref value, ref unit) if value.value >= 0. => { - specified::Length::parse_dimension(value.value, unit) - .map(SpecifiedValue::Length) - } - Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => { - Ok(SpecifiedValue::Normal) + input.try(specified::LengthOrPercentage::parse_non_negative) + .map(SpecifiedValue::LengthOrPercentage) + .or_else(|()| { + match try!(input.next()) { + Token::Number(ref value) if value.value >= 0. => { + Ok(SpecifiedValue::Number(value.value)) + } + Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => { + Ok(SpecifiedValue::Normal) + } + _ => Err(()), } - _ => Err(()), - } + }) } pub mod computed_value { use app_units::Au; @@ -733,13 +728,22 @@ pub mod longhands { fn to_computed_value(&self, context: &Context) -> computed_value::T { match *self { SpecifiedValue::Normal => computed_value::T::Normal, - SpecifiedValue::Length(value) => { - computed_value::T::Length(value.to_computed_value(context)) - } SpecifiedValue::Number(value) => computed_value::T::Number(value), - SpecifiedValue::Percentage(value) => { - let fr = specified::Length::FontRelative(specified::FontRelativeLength::Em(value)); - computed_value::T::Length(fr.to_computed_value(context)) + SpecifiedValue::LengthOrPercentage(value) => { + match value { + specified::LengthOrPercentage::Length(value) => + computed_value::T::Length(value.to_computed_value(context)), + specified::LengthOrPercentage::Percentage(specified::Percentage(value)) => { + let fr = specified::Length::FontRelative(specified::FontRelativeLength::Em(value)); + computed_value::T::Length(fr.to_computed_value(context)) + }, + specified::LengthOrPercentage::Calc(calc) => { + let calc = calc.to_computed_value(context); + let fr = specified::FontRelativeLength::Em(calc.percentage()); + let fr = specified::Length::FontRelative(fr); + computed_value::T::Length(calc.length() + fr.to_computed_value(context)) + } + } } } } @@ -804,9 +808,7 @@ pub mod longhands { % for keyword in vertical_align_keywords: ${to_rust_ident(keyword)}, % endfor - Length(Au), - Percentage(CSSFloat), - Calc(computed::Calc), + LengthOrPercentage(computed::LengthOrPercentage), } impl fmt::Debug for T { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -814,9 +816,7 @@ pub mod longhands { % for keyword in vertical_align_keywords: T::${to_rust_ident(keyword)} => write!(f, "${keyword}"), % endfor - T::Length(length) => write!(f, "{:?}", length), - T::Percentage(number) => write!(f, "{}%", number), - T::Calc(calc) => write!(f, "{:?}", calc) + T::LengthOrPercentage(value) => write!(f, "{:?}", value), } } } @@ -826,9 +826,7 @@ pub mod longhands { % for keyword in vertical_align_keywords: T::${to_rust_ident(keyword)} => dest.write_str("${keyword}"), % endfor - T::Length(value) => value.to_css(dest), - T::Percentage(percentage) => write!(dest, "{}%", percentage * 100.), - T::Calc(calc) => calc.to_css(dest), + T::LengthOrPercentage(value) => value.to_css(dest), } } } @@ -847,16 +845,8 @@ pub mod longhands { computed_value::T::${to_rust_ident(keyword)} } % endfor - SpecifiedValue::LengthOrPercentage(value) => { - match value.to_computed_value(context) { - computed::LengthOrPercentage::Length(value) => - computed_value::T::Length(value), - computed::LengthOrPercentage::Percentage(value) => - computed_value::T::Percentage(value), - computed::LengthOrPercentage::Calc(value) => - computed_value::T::Calc(value), - } - } + SpecifiedValue::LengthOrPercentage(value) => + computed_value::T::LengthOrPercentage(value.to_computed_value(context)), } } } @@ -1311,7 +1301,8 @@ pub mod longhands { if content::counter_name_is_illegal(&counter_name) { return Err(()) } - let counter_delta = input.try(|input| input.expect_integer()).unwrap_or(1) as i32; + let counter_delta = + input.try(|input| specified::parse_integer(input)).unwrap_or(1); counters.push((counter_name, counter_delta)) } @@ -1478,8 +1469,7 @@ pub mod longhands { PositionCategory::VerticalKeyword, specified::PositionComponent::Center => PositionCategory::OtherKeyword, - specified::PositionComponent::Length(_) | - specified::PositionComponent::Percentage(_) => + specified::PositionComponent::LengthOrPercentage(_) => PositionCategory::LengthOrPercentage, } } @@ -1929,7 +1919,7 @@ pub mod longhands { } #[derive(Clone, PartialEq)] - pub struct SpecifiedValue(pub specified::Length); // Percentages are the same as em. + pub struct SpecifiedValue(pub specified::LengthOrPercentage); pub mod computed_value { use app_units::Au; pub type T = Au; @@ -1949,17 +1939,14 @@ pub mod longhands { } /// <length> | <percentage> | <absolute-size> | <relative-size> pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { + use values::specified::{Length, LengthOrPercentage}; + input.try(specified::LengthOrPercentage::parse_non_negative) - .and_then(|value| match value { - specified::LengthOrPercentage::Length(value) => Ok(value), - specified::LengthOrPercentage::Percentage(value) => - Ok(specified::Length::FontRelative(specified::FontRelativeLength::Em(value.0))), - // FIXME(dzbarsky) handle calc for font-size - specified::LengthOrPercentage::Calc(_) => Err(()) - }) .or_else(|()| { let ident = try!(input.expect_ident()); - specified::Length::from_str(&ident as &str).ok_or(()) + specified::Length::from_str(&ident as &str) + .ok_or(()) + .map(specified::LengthOrPercentage::Length) }) .map(SpecifiedValue) } @@ -2649,7 +2636,7 @@ pub mod longhands { if input.try(|input| input.expect_ident_matching("auto")).is_ok() { Ok(SpecifiedValue::Auto) } else { - let count = try!(input.expect_integer()); + let count = try!(specified::parse_integer(input)); // Zero is invalid if count <= 0 { return Err(()) @@ -2763,7 +2750,7 @@ pub mod longhands { } } fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - input.expect_number().map(SpecifiedValue) + specified::parse_number(input).map(SpecifiedValue) } </%self:longhand> @@ -3628,10 +3615,10 @@ pub mod longhands { } fn parse_two_floats(input: &mut Parser) -> Result<(CSSFloat,CSSFloat),()> { - let first = try!(input.expect_number()); + let first = try!(specified::parse_number(input)); let second = input.try(|input| { try!(input.expect_comma()); - input.expect_number() + specified::parse_number(input) }).unwrap_or(first); Ok((first, second)) } @@ -3771,7 +3758,7 @@ pub mod longhands { "matrix" => { try!(input.parse_nested_block(|input| { let values = try!(input.parse_comma_separated(|input| { - input.expect_number() + specified::parse_number(input) })); if values.len() != 6 { return Err(()) @@ -3789,7 +3776,7 @@ pub mod longhands { "matrix3d" => { try!(input.parse_nested_block(|input| { let values = try!(input.parse_comma_separated(|input| { - input.expect_number() + specified::parse_number(input) })); if values.len() != 16 { return Err(()) @@ -3872,32 +3859,32 @@ pub mod longhands { }, "scalex" => { try!(input.parse_nested_block(|input| { - let sx = try!(input.expect_number()); + let sx = try!(specified::parse_number(input)); result.push(SpecifiedOperation::Scale(sx, 1.0, 1.0)); Ok(()) })) }, "scaley" => { try!(input.parse_nested_block(|input| { - let sy = try!(input.expect_number()); + let sy = try!(specified::parse_number(input)); result.push(SpecifiedOperation::Scale(1.0, sy, 1.0)); Ok(()) })) }, "scalez" => { try!(input.parse_nested_block(|input| { - let sz = try!(input.expect_number()); + let sz = try!(specified::parse_number(input)); result.push(SpecifiedOperation::Scale(1.0, 1.0, sz)); Ok(()) })) }, "scale3d" => { try!(input.parse_nested_block(|input| { - let sx = try!(input.expect_number()); + let sx = try!(specified::parse_number(input)); try!(input.expect_comma()); - let sy = try!(input.expect_number()); + let sy = try!(specified::parse_number(input)); try!(input.expect_comma()); - let sz = try!(input.expect_number()); + let sz = try!(specified::parse_number(input)); result.push(SpecifiedOperation::Scale(sx, sy, sz)); Ok(()) })) @@ -3932,11 +3919,11 @@ pub mod longhands { }, "rotate3d" => { try!(input.parse_nested_block(|input| { - let ax = try!(input.expect_number()); + let ax = try!(specified::parse_number(input)); try!(input.expect_comma()); - let ay = try!(input.expect_number()); + let ay = try!(specified::parse_number(input)); try!(input.expect_comma()); - let az = try!(input.expect_number()); + let az = try!(specified::parse_number(input)); try!(input.expect_comma()); let theta = try!(specified::Angle::parse(input)); // TODO(gw): Check the axis can be normalized!! @@ -4539,13 +4526,13 @@ pub mod longhands { "cubic-bezier" => { let (mut p1x, mut p1y, mut p2x, mut p2y) = (0.0, 0.0, 0.0, 0.0); try!(input.parse_nested_block(|input| { - p1x = try!(input.expect_number()); + p1x = try!(specified::parse_number(input)); try!(input.expect_comma()); - p1y = try!(input.expect_number()); + p1y = try!(specified::parse_number(input)); try!(input.expect_comma()); - p2x = try!(input.expect_number()); + p2x = try!(specified::parse_number(input)); try!(input.expect_comma()); - p2y = try!(input.expect_number()); + p2y = try!(specified::parse_number(input)); Ok(()) })); let (p1, p2) = (Point2D::new(p1x, p1y), Point2D::new(p2x, p2y)); @@ -4554,7 +4541,7 @@ pub mod longhands { "steps" => { let (mut step_count, mut start_end) = (0, computed_value::StartEnd::Start); try!(input.parse_nested_block(|input| { - step_count = try!(input.expect_integer()); + step_count = try!(specified::parse_integer(input)); try!(input.expect_comma()); start_end = try!(match_ignore_ascii_case! { try!(input.expect_ident()), @@ -6520,6 +6507,7 @@ pub fn cascade(viewport_size: Size2D<Au>, // Initialize `context` // Declarations blocks are already stored in increasing precedence order. for sub_list in applicable_declarations { + use values::specified::{LengthOrPercentage, Percentage}; // Declarations are stored in reverse source order, we want them in forward order here. for declaration in sub_list.declarations.iter().rev() { match *declaration { @@ -6528,14 +6516,23 @@ pub fn cascade(viewport_size: Size2D<Au>, value, &custom_properties, |value| match *value { DeclaredValue::Value(ref specified_value) => { match specified_value.0 { - Length::FontRelative(value) => { + LengthOrPercentage::Length(Length::FontRelative(value)) => { value.to_computed_value(context.inherited_font_size, context.root_font_size) } - Length::ServoCharacterWidth(value) => { + LengthOrPercentage::Length(Length::ServoCharacterWidth(value)) => { value.to_computed_value(context.inherited_font_size) } - _ => specified_value.0.to_computed_value(&context) + LengthOrPercentage::Length(l) => { + l.to_computed_value(&context) + } + LengthOrPercentage::Percentage(Percentage(value)) => { + context.inherited_font_size.scale_by(value) + } + LengthOrPercentage::Calc(calc) => { + let calc = calc.to_computed_value(&context); + calc.length() + context.inherited_font_size.scale_by(calc.percentage()) + } } } DeclaredValue::Initial => longhands::font_size::get_initial_value(), diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs new file mode 100644 index 00000000000..acb521b0f10 --- /dev/null +++ b/components/style/restyle_hints.rs @@ -0,0 +1,247 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use selectors::Element; +use selectors::matching::matches_compound_selector; +use selectors::parser::{AttrSelector, Combinator, CompoundSelector, SimpleSelector}; +use selectors::states::*; +use std::clone::Clone; +use std::sync::Arc; +use string_cache::{Atom, Namespace}; + +/// When the ElementState of an element (like IN_HOVER_STATE) changes, certain +/// pseudo-classes (like :hover) may require us to restyle that element, its +/// siblings, and/or its descendants. Doing this conservatively is expensive, +/// and so we RestyleHints to short-circuit work we know is unnecessary. +/// +/// NB: We should extent restyle hints to check for attribute-dependent style +/// in addition to state-dependent style (Gecko does this). + + +bitflags! { + flags RestyleHint: u8 { + #[doc = "Rerun selector matching on the element."] + const RESTYLE_SELF = 0x01, + #[doc = "Rerun selector matching on all of the element's descendants."] + // NB: In Gecko, we have RESTYLE_SUBTREE which is inclusive of self, but heycam isn't aware + // of a good reason for that. + const RESTYLE_DESCENDANTS = 0x02, + #[doc = "Rerun selector matching on all later siblings of the element and all of their descendants."] + const RESTYLE_LATER_SIBLINGS = 0x04, + } +} + +/// In order to compute restyle hints, we perform a selector match against a list of partial +/// selectors whose rightmost simple selector may be sensitive to the thing being changed. We +/// do this matching twice, once for the element as it exists now and once for the element as it +/// existed at the time of the last restyle. If the results of the selector match differ, that means +/// that the given partial selector is sensitive to the change, and we compute a restyle hint +/// based on its combinator. +/// +/// In order to run selector matching against the old element state, we generate a wrapper for +/// the element which claims to have the old state. This is the ElementWrapper logic below. +/// +/// Gecko does this differently for element states, and passes a mask called mStateMask, which +/// indicates the states that need to be ignored during selector matching. This saves an ElementWrapper +/// allocation and an additional selector match call at the expense of additional complexity inside +/// the selector matching logic. This only works for boolean states though, so we still need to +/// take the ElementWrapper approach for attribute-dependent style. So we do it the same both ways for +/// now to reduce complexity, but it's worth measuring the performance impact (if any) of the +/// mStateMask approach. +struct ElementWrapper<E> where E: Element { + element: E, + state_override: ElementState, +} + +impl<'a, E> ElementWrapper<E> where E: Element { + pub fn new(el: E) -> ElementWrapper<E> { + ElementWrapper { element: el, state_override: ElementState::empty() } + } + + pub fn new_with_override(el: E, state: ElementState) -> ElementWrapper<E> { + ElementWrapper { element: el, state_override: state } + } +} + +macro_rules! overridden_state_accessors { + ($( + $(#[$Flag_attr: meta])* + state $css: expr => $variant: ident / $method: ident / + $flag: ident = $value: expr, + )+) => { $( fn $method(&self) -> bool { self.state_override.contains($flag) } )+ + } +} + +impl<E> Element for ElementWrapper<E> where E: Element { + + // Implement the state accessors on Element to use our overridden state. + state_pseudo_classes!(overridden_state_accessors); + + fn parent_element(&self) -> Option<Self> { + self.element.parent_element().map(|el| ElementWrapper::new(el)) + } + fn first_child_element(&self) -> Option<Self> { + self.element.first_child_element().map(|el| ElementWrapper::new(el)) + } + fn last_child_element(&self) -> Option<Self> { + self.element.last_child_element().map(|el| ElementWrapper::new(el)) + } + fn prev_sibling_element(&self) -> Option<Self> { + self.element.prev_sibling_element().map(|el| ElementWrapper::new(el)) + } + fn next_sibling_element(&self) -> Option<Self> { + self.element.next_sibling_element().map(|el| ElementWrapper::new(el)) + } + fn is_html_element_in_html_document(&self) -> bool { + self.element.is_html_element_in_html_document() + } + fn get_local_name<'b>(&'b self) -> &'b Atom { + self.element.get_local_name() + } + fn get_namespace<'b>(&'b self) -> &'b Namespace { + self.element.get_namespace() + } + fn get_id(&self) -> Option<Atom> { + self.element.get_id() + } + fn has_class(&self, name: &Atom) -> bool { + self.element.has_class(name) + } + fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool + where F: Fn(&str) -> bool { + self.element.match_attr(attr, test) + } + fn is_empty(&self) -> bool { + self.element.is_empty() + } + fn is_root(&self) -> bool { + self.element.is_root() + } + fn is_link(&self) -> bool { + self.element.is_link() + } + fn is_visited_link(&self) -> bool { + self.element.is_visited_link() + } + fn is_unvisited_link(&self) -> bool { + self.element.is_unvisited_link() + } + fn each_class<F>(&self, callback: F) where F: FnMut(&Atom) { + self.element.each_class(callback) + } +} + +macro_rules! gen_selector_to_state { + ($( + $(#[$Flag_attr: meta])* + state $css: expr => $variant: ident / $method: ident / + $flag: ident = $value: expr, + )+) => { + fn selector_to_state(sel: &SimpleSelector) -> ElementState { + match *sel { + $( SimpleSelector::$variant => $flag, )+ + _ => ElementState::empty(), + } + } + } +} + +fn combinator_to_restyle_hint(combinator: Option<Combinator>) -> RestyleHint { + match combinator { + None => RESTYLE_SELF, + Some(c) => match c { + Combinator::Child => RESTYLE_DESCENDANTS, + Combinator::Descendant => RESTYLE_DESCENDANTS, + Combinator::NextSibling => RESTYLE_LATER_SIBLINGS, + Combinator::LaterSibling => RESTYLE_LATER_SIBLINGS, + } + } +} + +state_pseudo_classes!(gen_selector_to_state); + +// Mapping between (partial) CompoundSelectors (and the combinator to their right) +// and the states they depend on. +// +// In general, for all selectors in all applicable stylesheets of the form: +// +// |s _ s:X _ s _ s:Y _ s| +// +// Where: +// * Each |s| is an arbitrary simple selector. +// * Each |s| is an arbitrary combinator (or nothing). +// * X and Y are state-dependent pseudo-classes like :hover. +// +// We generate a StateDependency for both |s _ s:X _| and |s _ s:X _ s _ s:Y _|, even +// though those selectors may not appear on their own in any stylesheet. This allows +// us to quickly scan through the operation points of pseudo-classes and determine the +// maximum effect their associated state changes may have on the style of elements in +// the document. +#[derive(Debug)] +struct StateDependency { + selector: Arc<CompoundSelector>, + combinator: Option<Combinator>, + state: ElementState, +} + +#[derive(Debug)] +pub struct StateDependencySet { + deps: Vec<StateDependency>, +} + +impl StateDependencySet { + pub fn new() -> StateDependencySet { + StateDependencySet { deps: Vec::new() } + } + + pub fn compute_hint<E>(&self, el: &E, current_state: ElementState, state_changes: ElementState) + -> RestyleHint where E: Element, E: Clone { + let mut hint = RestyleHint::empty(); + let mut old_state = current_state; + old_state.toggle(state_changes); + for dep in &self.deps { + if state_changes.intersects(dep.state) { + let old_el: ElementWrapper<E> = ElementWrapper::new_with_override(el.clone(), old_state); + let matched_then = matches_compound_selector(&*dep.selector, &old_el, None, &mut false); + let matches_now = matches_compound_selector(&*dep.selector, el, None, &mut false); + if matched_then != matches_now { + hint.insert(combinator_to_restyle_hint(dep.combinator)); + if hint.is_all() { + break + } + } + } + } + hint + } + + pub fn note_selector(&mut self, selector: Arc<CompoundSelector>) { + let mut cur = selector; + let mut combinator: Option<Combinator> = None; + loop { + if let Some(rightmost) = cur.simple_selectors.last() { + let state_dep = selector_to_state(rightmost); + if !state_dep.is_empty() { + self.deps.push(StateDependency { + selector: cur.clone(), + combinator: combinator, + state: state_dep, + }); + } + } + + cur = match cur.next { + Some((ref sel, comb)) => { + combinator = Some(comb); + sel.clone() + } + None => break, + } + } + } + + pub fn clear(&mut self) { + self.deps.clear(); + } +} diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index b758c535da8..53f1a0d3589 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -6,11 +6,13 @@ use legacy::PresentationalHintSynthesis; use media_queries::Device; use node::TElementAttributes; use properties::{PropertyDeclaration, PropertyDeclarationBlock}; +use restyle_hints::{RestyleHint, StateDependencySet}; use selectors::Element; use selectors::bloom::BloomFilter; use selectors::matching::DeclarationBlock as GenericDeclarationBlock; use selectors::matching::{Rule, SelectorMap}; use selectors::parser::PseudoElement; +use selectors::states::*; use smallvec::VecLike; use std::process; use style_traits::viewport::ViewportConstraints; @@ -41,6 +43,9 @@ pub struct Stylist { before_map: PerPseudoElementSelectorMap, after_map: PerPseudoElementSelectorMap, rules_source_order: usize, + + // Selector state dependencies used to compute restyle hints. + state_deps: StateDependencySet, } impl Stylist { @@ -55,6 +60,7 @@ impl Stylist { before_map: PerPseudoElementSelectorMap::new(), after_map: PerPseudoElementSelectorMap::new(), rules_source_order: 0, + state_deps: StateDependencySet::new(), }; // FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8. // FIXME: presentational-hints.css should be at author origin with zero specificity. @@ -102,6 +108,7 @@ impl Stylist { self.before_map = PerPseudoElementSelectorMap::new(); self.after_map = PerPseudoElementSelectorMap::new(); self.rules_source_order = 0; + self.state_deps.clear(); for stylesheet in &self.stylesheets { let (mut element_map, mut before_map, mut after_map) = match stylesheet.origin { @@ -151,6 +158,9 @@ impl Stylist { append!(style_rule, normal); append!(style_rule, important); rules_source_order += 1; + for selector in &style_rule.selectors { + self.state_deps.note_selector(selector.compound_selectors.clone()); + } } self.rules_source_order = rules_source_order; } @@ -162,6 +172,14 @@ impl Stylist { false } + pub fn restyle_hint_for_state_change<E>(&self, element: &E, + current_state: ElementState, + state_change: ElementState) + -> RestyleHint + where E: Element + Clone { + self.state_deps.compute_hint(element, current_state, state_change) + } + pub fn set_device(&mut self, device: Device) { let is_dirty = self.is_dirty || self.stylesheets.iter() .flat_map(|stylesheet| stylesheet.rules().media()) diff --git a/components/style/values.rs b/components/style/values.rs index d8850dc31cf..a32b668fa9c 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -232,6 +232,8 @@ pub mod specified { /// This cannot be specified by the user directly and is only generated by /// `Stylist::synthesize_rules_for_legacy_attributes()`. ServoCharacterWidth(CharacterWidth), + + Calc(CalcLengthOrPercentage), } impl ToCss for Length { @@ -240,6 +242,7 @@ pub mod specified { Length::Absolute(length) => write!(dest, "{}px", length.to_f32_px()), Length::FontRelative(length) => length.to_css(dest), Length::ViewportPercentage(length) => length.to_css(dest), + Length::Calc(calc) => calc.to_css(dest), Length::ServoCharacterWidth(_) => panic!("internal CSS values should never be serialized"), } @@ -255,6 +258,7 @@ pub mod specified { Length::Absolute(Au(v)) => Length::Absolute(Au(((v as f32) * scalar) as i32)), Length::FontRelative(v) => Length::FontRelative(v * scalar), Length::ViewportPercentage(v) => Length::ViewportPercentage(v * scalar), + Length::Calc(_) => panic!("Can't multiply Calc!"), Length::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"), } } @@ -292,6 +296,7 @@ pub mod specified { const AU_PER_IN: CSSFloat = AU_PER_PX * 96.; const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54; const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4; + const AU_PER_Q: CSSFloat = AU_PER_MM / 4.; const AU_PER_PT: CSSFloat = AU_PER_IN / 72.; const AU_PER_PC: CSSFloat = AU_PER_PT * 12.; impl Length { @@ -320,6 +325,8 @@ pub mod specified { Length::parse_dimension(value.value, unit), Token::Number(ref value) if value.value == 0. => Ok(Length::Absolute(Au(0))), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => + input.parse_nested_block(CalcLengthOrPercentage::parse_length), _ => Err(()) } } @@ -335,6 +342,7 @@ pub mod specified { "in" => Ok(Length::Absolute(Au((value * AU_PER_IN) as i32))), "cm" => Ok(Length::Absolute(Au((value * AU_PER_CM) as i32))), "mm" => Ok(Length::Absolute(Au((value * AU_PER_MM) as i32))), + "q" => Ok(Length::Absolute(Au((value * AU_PER_Q) as i32))), "pt" => Ok(Length::Absolute(Au((value * AU_PER_PT) as i32))), "pc" => Ok(Length::Absolute(Au((value * AU_PER_PC) as i32))), // font-relative @@ -369,6 +377,8 @@ pub mod specified { #[derive(Clone, Debug)] enum CalcValueNode { Length(Length), + Angle(Angle), + Time(Time), Percentage(CSSFloat), Number(CSSFloat), Sum(Box<CalcSumNode>), @@ -392,6 +402,8 @@ pub mod specified { #[derive(Clone, Debug)] enum SimplifiedValueNode { Length(Length), + Angle(Angle), + Time(Time), Percentage(CSSFloat), Number(CSSFloat), Sum(Box<SimplifiedSumNode>), @@ -404,6 +416,8 @@ pub mod specified { match *self { SimplifiedValueNode::Length(l) => SimplifiedValueNode::Length(l * scalar), SimplifiedValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p * scalar), + SimplifiedValueNode::Angle(Angle(a)) => SimplifiedValueNode::Angle(Angle(a * scalar)), + SimplifiedValueNode::Time(Time(t)) => SimplifiedValueNode::Time(Time(t * scalar)), SimplifiedValueNode::Number(n) => SimplifiedValueNode::Number(n * scalar), SimplifiedValueNode::Sum(box ref s) => { let sum = s * scalar; @@ -413,8 +427,68 @@ pub mod specified { } } + pub fn parse_integer(input: &mut Parser) -> Result<i32, ()> { + match try!(input.next()) { + Token::Number(ref value) => value.int_value.ok_or(()), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Integer))); + + let mut result = None; + + for ref node in ast.products { + match try!(CalcLengthOrPercentage::simplify_product(node)) { + SimplifiedValueNode::Number(val) => + result = Some(result.unwrap_or(0) + val as i32), + _ => unreachable!() + } + } + + match result { + Some(result) => Ok(result), + _ => Err(()) + } + } + _ => Err(()) + } + } + + pub fn parse_number(input: &mut Parser) -> Result<f32, ()> { + match try!(input.next()) { + Token::Number(ref value) => Ok(value.value), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Number))); + + let mut result = None; + + for ref node in ast.products { + match try!(CalcLengthOrPercentage::simplify_product(node)) { + SimplifiedValueNode::Number(val) => + result = Some(result.unwrap_or(0.) + val), + _ => unreachable!() + } + } + + match result { + Some(result) => Ok(result), + _ => Err(()) + } + } + _ => Err(()) + } + } + + #[derive(Clone, Copy, PartialEq)] + enum CalcUnit { + Number, + Integer, + Length, + LengthOrPercentage, + Angle, + Time, + } + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] - pub struct Calc { + pub struct CalcLengthOrPercentage { pub absolute: Option<Au>, pub vw: Option<ViewportPercentageLength>, pub vh: Option<ViewportPercentageLength>, @@ -426,18 +500,18 @@ pub mod specified { pub rem: Option<FontRelativeLength>, pub percentage: Option<Percentage>, } - impl Calc { - fn parse_sum(input: &mut Parser) -> Result<CalcSumNode, ()> { + impl CalcLengthOrPercentage { + fn parse_sum(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcSumNode, ()> { let mut products = Vec::new(); - products.push(try!(Calc::parse_product(input))); + products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit))); loop { match input.next() { Ok(Token::Delim('+')) => { - products.push(try!(Calc::parse_product(input))); + products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit))); } Ok(Token::Delim('-')) => { - let mut right = try!(Calc::parse_product(input)); + let mut right = try!(CalcLengthOrPercentage::parse_product(input, expected_unit)); right.values.push(CalcValueNode::Number(-1.)); products.push(right); } @@ -449,17 +523,17 @@ pub mod specified { Ok(CalcSumNode { products: products }) } - fn parse_product(input: &mut Parser) -> Result<CalcProductNode, ()> { + fn parse_product(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcProductNode, ()> { let mut values = Vec::new(); - values.push(try!(Calc::parse_value(input))); + values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit))); loop { let position = input.position(); match input.next() { Ok(Token::Delim('*')) => { - values.push(try!(Calc::parse_value(input))); + values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit))); } - Ok(Token::Delim('/')) => { + Ok(Token::Delim('/')) if expected_unit != CalcUnit::Integer => { if let Ok(Token::Number(ref value)) = input.next() { if value.value == 0. { return Err(()); @@ -479,16 +553,24 @@ pub mod specified { Ok(CalcProductNode { values: values }) } - fn parse_value(input: &mut Parser) -> Result<CalcValueNode, ()> { - match input.next() { - Ok(Token::Number(ref value)) => Ok(CalcValueNode::Number(value.value)), - Ok(Token::Dimension(ref value, ref unit)) => - Length::parse_dimension(value.value, unit).map(CalcValueNode::Length), - Ok(Token::Percentage(ref value)) => + fn parse_value(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcValueNode, ()> { + match (try!(input.next()), expected_unit) { + (Token::Number(ref value), _) => Ok(CalcValueNode::Number(value.value)), + (Token::Dimension(ref value, ref unit), CalcUnit::Length) | + (Token::Dimension(ref value, ref unit), CalcUnit::LengthOrPercentage) => { + Length::parse_dimension(value.value, unit).map(CalcValueNode::Length) + } + (Token::Dimension(ref value, ref unit), CalcUnit::Angle) => { + Angle::parse_dimension(value.value, unit).map(CalcValueNode::Angle) + } + (Token::Dimension(ref value, ref unit), CalcUnit::Time) => { + Time::parse_dimension(value.value, unit).map(CalcValueNode::Time) + } + (Token::Percentage(ref value), CalcUnit::LengthOrPercentage) => Ok(CalcValueNode::Percentage(value.unit_value)), - Ok(Token::ParenthesisBlock) => { - let result = try!(input.parse_nested_block(Calc::parse_sum)); - Ok(CalcValueNode::Sum(box result)) + (Token::ParenthesisBlock, _) => { + input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, expected_unit)) + .map(|result| CalcValueNode::Sum(box result)) }, _ => Err(()) } @@ -497,7 +579,7 @@ pub mod specified { fn simplify_value_to_number(node: &CalcValueNode) -> Option<CSSFloat> { match *node { CalcValueNode::Number(number) => Some(number), - CalcValueNode::Sum(box ref sum) => Calc::simplify_sum_to_number(sum), + CalcValueNode::Sum(box ref sum) => CalcLengthOrPercentage::simplify_sum_to_number(sum), _ => None } } @@ -505,7 +587,7 @@ pub mod specified { fn simplify_sum_to_number(node: &CalcSumNode) -> Option<CSSFloat> { let mut sum = 0.; for ref product in &node.products { - match Calc::simplify_product_to_number(product) { + match CalcLengthOrPercentage::simplify_product_to_number(product) { Some(number) => sum += number, _ => return None } @@ -516,7 +598,7 @@ pub mod specified { fn simplify_product_to_number(node: &CalcProductNode) -> Option<CSSFloat> { let mut product = 1.; for ref value in &node.values { - match Calc::simplify_value_to_number(value) { + match CalcLengthOrPercentage::simplify_value_to_number(value) { Some(number) => product *= number, _ => return None } @@ -527,7 +609,7 @@ pub mod specified { fn simplify_products_in_sum(node: &CalcSumNode) -> Result<SimplifiedValueNode, ()> { let mut simplified = Vec::new(); for product in &node.products { - match try!(Calc::simplify_product(product)) { + match try!(CalcLengthOrPercentage::simplify_product(product)) { SimplifiedValueNode::Sum(box sum) => simplified.push_all(&sum.values), val => simplified.push(val), } @@ -544,13 +626,15 @@ pub mod specified { let mut multiplier = 1.; let mut node_with_unit = None; for node in &node.values { - match Calc::simplify_value_to_number(&node) { + match CalcLengthOrPercentage::simplify_value_to_number(&node) { Some(number) => multiplier *= number, _ if node_with_unit.is_none() => { node_with_unit = Some(match *node { CalcValueNode::Sum(box ref sum) => - try!(Calc::simplify_products_in_sum(sum)), + try!(CalcLengthOrPercentage::simplify_products_in_sum(sum)), CalcValueNode::Length(l) => SimplifiedValueNode::Length(l), + CalcValueNode::Angle(a) => SimplifiedValueNode::Angle(a), + CalcValueNode::Time(t) => SimplifiedValueNode::Time(t), CalcValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p), _ => unreachable!("Numbers should have been handled by simplify_value_to_nubmer") }) @@ -565,12 +649,20 @@ pub mod specified { } } - pub fn parse(input: &mut Parser) -> Result<Calc, ()> { - let ast = try!(Calc::parse_sum(input)); + fn parse_length(input: &mut Parser) -> Result<Length, ()> { + CalcLengthOrPercentage::parse(input, CalcUnit::Length).map(Length::Calc) + } + + fn parse_length_or_percentage(input: &mut Parser) -> Result<CalcLengthOrPercentage, ()> { + CalcLengthOrPercentage::parse(input, CalcUnit::LengthOrPercentage) + } + + fn parse(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> { + let ast = try!(CalcLengthOrPercentage::parse_sum(input, expected_unit)); let mut simplified = Vec::new(); for ref node in ast.products { - match try!(Calc::simplify_product(node)) { + match try!(CalcLengthOrPercentage::simplify_product(node)) { SimplifiedValueNode::Sum(sum) => simplified.push_all(&sum.values), value => simplified.push(value), } @@ -617,11 +709,11 @@ pub mod specified { rem = Some(rem.unwrap_or(0.) + val), }, SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val), - _ => unreachable!() + _ => return Err(()), } } - Ok(Calc { + Ok(CalcLengthOrPercentage { absolute: absolute.map(Au), vw: vw.map(ViewportPercentageLength::Vw), vh: vh.map(ViewportPercentageLength::Vh), @@ -634,9 +726,66 @@ pub mod specified { percentage: percentage.map(Percentage), }) } + + pub fn parse_time(input: &mut Parser) -> Result<Time, ()> { + let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Time)); + + let mut simplified = Vec::new(); + for ref node in ast.products { + match try!(CalcLengthOrPercentage::simplify_product(node)) { + SimplifiedValueNode::Sum(sum) => simplified.push_all(&sum.values), + value => simplified.push(value), + } + } + + let mut time = None; + + for value in simplified { + match value { + SimplifiedValueNode::Time(Time(val)) => + time = Some(time.unwrap_or(0.) + val), + _ => return Err(()), + } + } + + match time { + Some(time) => Ok(Time(time)), + _ => Err(()) + } + } + + pub fn parse_angle(input: &mut Parser) -> Result<Angle, ()> { + let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Angle)); + + let mut simplified = Vec::new(); + for ref node in ast.products { + match try!(CalcLengthOrPercentage::simplify_product(node)) { + SimplifiedValueNode::Sum(sum) => simplified.push_all(&sum.values), + value => simplified.push(value), + } + } + + let mut angle = None; + let mut number = None; + + for value in simplified { + match value { + SimplifiedValueNode::Angle(Angle(val)) => + angle = Some(angle.unwrap_or(0.) + val), + SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val), + _ => unreachable!() + } + } + + match (angle, number) { + (Some(angle), None) => Ok(Angle(angle)), + (None, Some(value)) if value == 0. => Ok(Angle(0.)), + _ => Err(()) + } + } } - impl ToCss for Calc { + impl ToCss for CalcLengthOrPercentage { #[allow(unused_assignments)] fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { @@ -701,7 +850,7 @@ pub mod specified { pub enum LengthOrPercentage { Length(Length), Percentage(Percentage), - Calc(Calc), + Calc(CalcLengthOrPercentage), } impl ToCss for LengthOrPercentage { @@ -729,7 +878,7 @@ pub mod specified { Token::Number(ref value) if value.value == 0. => Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))), Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - let calc = try!(input.parse_nested_block(Calc::parse)); + let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); Ok(LengthOrPercentage::Calc(calc)) }, _ => Err(()) @@ -750,7 +899,7 @@ pub mod specified { Length(Length), Percentage(Percentage), Auto, - Calc(Calc), + Calc(CalcLengthOrPercentage), } impl ToCss for LengthOrPercentageOrAuto { @@ -778,7 +927,7 @@ pub mod specified { Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => Ok(LengthOrPercentageOrAuto::Auto), Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - let calc = try!(input.parse_nested_block(Calc::parse)); + let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); Ok(LengthOrPercentageOrAuto::Calc(calc)) }, _ => Err(()) @@ -798,6 +947,7 @@ pub mod specified { pub enum LengthOrPercentageOrNone { Length(Length), Percentage(Percentage), + Calc(CalcLengthOrPercentage), None, } @@ -806,6 +956,7 @@ pub mod specified { match *self { LengthOrPercentageOrNone::Length(length) => length.to_css(dest), LengthOrPercentageOrNone::Percentage(percentage) => percentage.to_css(dest), + LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest), LengthOrPercentageOrNone::None => dest.write_str("none"), } } @@ -821,6 +972,10 @@ pub mod specified { Ok(LengthOrPercentageOrNone::Percentage(Percentage(value.unit_value))), Token::Number(ref value) if value.value == 0. => Ok(LengthOrPercentageOrNone::Length(Length::Absolute(Au(0)))), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); + Ok(LengthOrPercentageOrNone::Calc(calc)) + }, Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => Ok(LengthOrPercentageOrNone::None), _ => Err(()) @@ -859,6 +1014,8 @@ pub mod specified { Length::parse_dimension(value.value, unit).map(LengthOrNone::Length), Token::Number(ref value) if value.value == 0. => Ok(LengthOrNone::Length(Length::Absolute(Au(0)))), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => + input.parse_nested_block(CalcLengthOrPercentage::parse_length).map(LengthOrNone::Length), Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => Ok(LengthOrNone::None), _ => Err(()) @@ -911,8 +1068,7 @@ pub mod specified { // http://dev.w3.org/csswg/css2/colors.html#propdef-background-position #[derive(Clone, PartialEq, Copy)] pub enum PositionComponent { - Length(Length), - Percentage(Percentage), + LengthOrPercentage(LengthOrPercentage), Center, Left, Right, @@ -921,35 +1077,29 @@ pub mod specified { } impl PositionComponent { pub fn parse(input: &mut Parser) -> Result<PositionComponent, ()> { - match try!(input.next()) { - Token::Dimension(ref value, ref unit) => { - Length::parse_dimension(value.value, unit) - .map(PositionComponent::Length) - } - Token::Percentage(ref value) => { - Ok(PositionComponent::Percentage(Percentage(value.unit_value))) - } - Token::Number(ref value) if value.value == 0. => { - Ok(PositionComponent::Length(Length::Absolute(Au(0)))) - } - Token::Ident(value) => { - match_ignore_ascii_case! { value, - "center" => Ok(PositionComponent::Center), - "left" => Ok(PositionComponent::Left), - "right" => Ok(PositionComponent::Right), - "top" => Ok(PositionComponent::Top), - "bottom" => Ok(PositionComponent::Bottom) - _ => Err(()) - } + + input.try(LengthOrPercentage::parse) + .map(PositionComponent::LengthOrPercentage) + .or_else(|()| { + match try!(input.next()) { + Token::Ident(value) => { + match_ignore_ascii_case! { value, + "center" => Ok(PositionComponent::Center), + "left" => Ok(PositionComponent::Left), + "right" => Ok(PositionComponent::Right), + "top" => Ok(PositionComponent::Top), + "bottom" => Ok(PositionComponent::Bottom) + _ => Err(()) + } + }, + _ => Err(()) } - _ => Err(()) - } + }) } #[inline] pub fn to_length_or_percentage(self) -> LengthOrPercentage { match self { - PositionComponent::Length(x) => LengthOrPercentage::Length(x), - PositionComponent::Percentage(x) => LengthOrPercentage::Percentage(x), + PositionComponent::LengthOrPercentage(value) => value, PositionComponent::Center => LengthOrPercentage::Percentage(Percentage(0.5)), PositionComponent::Left | PositionComponent::Top => LengthOrPercentage::Percentage(Percentage(0.0)), @@ -984,19 +1134,24 @@ pub mod specified { /// Parses an angle according to CSS-VALUES § 6.1. pub fn parse(input: &mut Parser) -> Result<Angle, ()> { match try!(input.next()) { - Token::Dimension(value, unit) => { - match_ignore_ascii_case! { unit, - "deg" => Ok(Angle(value.value * RAD_PER_DEG)), - "grad" => Ok(Angle(value.value * RAD_PER_GRAD)), - "turn" => Ok(Angle(value.value * RAD_PER_TURN)), - "rad" => Ok(Angle(value.value)) - _ => Err(()) - } - } + Token::Dimension(ref value, ref unit) => Angle::parse_dimension(value.value, unit), Token::Number(ref value) if value.value == 0. => Ok(Angle(0.)), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + input.parse_nested_block(CalcLengthOrPercentage::parse_angle) + }, _ => Err(()) } } + + pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> { + match_ignore_ascii_case! { unit, + "deg" => Ok(Angle(value * RAD_PER_DEG)), + "grad" => Ok(Angle(value * RAD_PER_GRAD)), + "turn" => Ok(Angle(value * RAD_PER_TURN)), + "rad" => Ok(Angle(value)) + _ => Err(()) + } + } } /// Specified values for an image according to CSS-IMAGES. @@ -1235,7 +1390,10 @@ pub mod specified { Ok(Token::Dimension(ref value, ref unit)) => { Time::parse_dimension(value.value, &unit) } - _ => Err(()), + Ok(Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") => { + input.parse_nested_block(CalcLengthOrPercentage::parse_time) + } + _ => Err(()) } } } @@ -1251,7 +1409,7 @@ pub mod specified { impl ToCss for Time { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - write!(dest, "{}ms", self.0) + write!(dest, "{}s", self.0) } } } @@ -1328,6 +1486,7 @@ pub mod computed { fn to_computed_value(&self, context: &Context) -> Au { match *self { specified::Length::Absolute(length) => length, + specified::Length::Calc(calc) => calc.to_computed_value(context).length(), specified::Length::FontRelative(length) => length.to_computed_value(context.font_size, context.root_font_size), specified::Length::ViewportPercentage(length) => @@ -1339,12 +1498,12 @@ pub mod computed { } #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] - pub struct Calc { + pub struct CalcLengthOrPercentage { pub length: Option<Au>, pub percentage: Option<CSSFloat>, } - impl Calc { + impl CalcLengthOrPercentage { pub fn length(&self) -> Au { self.length.unwrap_or(Au(0)) } @@ -1354,17 +1513,17 @@ pub mod computed { } } - impl From<LengthOrPercentage> for Calc { - fn from(len: LengthOrPercentage) -> Calc { + impl From<LengthOrPercentage> for CalcLengthOrPercentage { + fn from(len: LengthOrPercentage) -> CalcLengthOrPercentage { match len { LengthOrPercentage::Percentage(this) => { - Calc { + CalcLengthOrPercentage { length: None, percentage: Some(this), } } LengthOrPercentage::Length(this) => { - Calc { + CalcLengthOrPercentage { length: Some(this), percentage: None, } @@ -1376,17 +1535,17 @@ pub mod computed { } } - impl From<LengthOrPercentageOrAuto> for Option<Calc> { - fn from(len: LengthOrPercentageOrAuto) -> Option<Calc> { + impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> { + fn from(len: LengthOrPercentageOrAuto) -> Option<CalcLengthOrPercentage> { match len { LengthOrPercentageOrAuto::Percentage(this) => { - Some(Calc { + Some(CalcLengthOrPercentage { length: None, percentage: Some(this), }) } LengthOrPercentageOrAuto::Length(this) => { - Some(Calc { + Some(CalcLengthOrPercentage { length: Some(this), percentage: None, }) @@ -1401,7 +1560,7 @@ pub mod computed { } } - impl ::cssparser::ToCss for Calc { + impl ::cssparser::ToCss for CalcLengthOrPercentage { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match (self.length, self.percentage) { (None, Some(p)) => write!(dest, "{}%", p * 100.), @@ -1412,10 +1571,10 @@ pub mod computed { } } - impl ToComputedValue for specified::Calc { - type ComputedValue = Calc; + impl ToComputedValue for specified::CalcLengthOrPercentage { + type ComputedValue = CalcLengthOrPercentage; - fn to_computed_value(&self, context: &Context) -> Calc { + fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage { let mut length = None; if let Some(absolute) = self.absolute { @@ -1435,7 +1594,7 @@ pub mod computed { } } - Calc { length: length, percentage: self.percentage.map(|p| p.0) } + CalcLengthOrPercentage { length: length, percentage: self.percentage.map(|p| p.0) } } } @@ -1474,7 +1633,7 @@ pub mod computed { pub enum LengthOrPercentage { Length(Au), Percentage(CSSFloat), - Calc(Calc), + Calc(CalcLengthOrPercentage), } impl LengthOrPercentage { @@ -1527,7 +1686,7 @@ pub mod computed { Length(Au), Percentage(CSSFloat), Auto, - Calc(Calc), + Calc(CalcLengthOrPercentage), } impl fmt::Debug for LengthOrPercentageOrAuto { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1578,6 +1737,7 @@ pub mod computed { pub enum LengthOrPercentageOrNone { Length(Au), Percentage(CSSFloat), + Calc(CalcLengthOrPercentage), None, } impl fmt::Debug for LengthOrPercentageOrNone { @@ -1585,6 +1745,7 @@ pub mod computed { match *self { LengthOrPercentageOrNone::Length(length) => write!(f, "{:?}", length), LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.), + LengthOrPercentageOrNone::Calc(calc) => write!(f, "{:?}", calc), LengthOrPercentageOrNone::None => write!(f, "none"), } } @@ -1602,6 +1763,9 @@ pub mod computed { specified::LengthOrPercentageOrNone::Percentage(value) => { LengthOrPercentageOrNone::Percentage(value.0) } + specified::LengthOrPercentageOrNone::Calc(calc) => { + LengthOrPercentageOrNone::Calc(calc.to_computed_value(context)) + } specified::LengthOrPercentageOrNone::None => { LengthOrPercentageOrNone::None } @@ -1615,6 +1779,7 @@ pub mod computed { LengthOrPercentageOrNone::Length(length) => length.to_css(dest), LengthOrPercentageOrNone::Percentage(percentage) => write!(dest, "{}%", percentage * 100.), + LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest), LengthOrPercentageOrNone::None => dest.write_str("none"), } } @@ -1640,6 +1805,9 @@ pub mod computed { #[inline] fn to_computed_value(&self, context: &Context) -> LengthOrNone { match *self { + specified::LengthOrNone::Length(specified::Length::Calc(calc)) => { + LengthOrNone::Length(calc.to_computed_value(context).length()) + } specified::LengthOrNone::Length(value) => { LengthOrNone::Length(value.to_computed_value(context)) } diff --git a/components/util/lib.rs b/components/util/lib.rs index 5cfda0e8c7c..850998408f1 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -11,7 +11,7 @@ #![feature(heap_api)] #![feature(oom)] #![feature(optin_builtin_traits)] -#![feature(path_ext)] +#![cfg_attr(not(target_os = "android"), feature(path_ext))] #![feature(plugin)] #![feature(slice_splits)] #![feature(step_by)] diff --git a/components/util/mem.rs b/components/util/mem.rs index 1577ff39dc2..bcd8de3250d 100644 --- a/components/util/mem.rs +++ b/components/util/mem.rs @@ -27,6 +27,7 @@ use logical_geometry::WritingMode; use rand::OsRng; use range::Range; use selectors::parser::{Combinator, CompoundSelector, PseudoElement, Selector, SimpleSelector}; +use selectors::states::ElementState; use std::cell::{Cell, RefCell}; use std::collections::{HashMap, LinkedList, hash_state}; use std::hash::Hash; @@ -417,4 +418,4 @@ known_heap_size!(0, Au, WritingMode, CSSParserColor, Color, RGBA, Cursor, Matrix known_heap_size!(0, JSVal, PagePx, ViewportPx, DevicePixel, QuirksMode, OsRng, RawStatus); known_heap_size!(0, TokenSerializationType, LengthOrPercentageOrAuto); -known_heap_size!(0, PseudoElement, Combinator, str); +known_heap_size!(0, ElementState, Combinator, PseudoElement, str); diff --git a/components/util/opts.rs b/components/util/opts.rs index 785f5909240..9f68ffb432b 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -121,6 +121,9 @@ pub struct Opts { /// Periodically print out on which events script tasks spend their processing time. pub profile_script_events: bool, + /// Enable all heartbeats for profiling. + pub profile_heartbeats: bool, + /// `None` to disable devtools or `Some` with a port number to start a server to listen to /// remote Firefox devtools connections. pub devtools_port: Option<u16>, @@ -223,6 +226,9 @@ pub struct DebugOptions { /// Profile which events script tasks spend their time on. pub profile_script_events: bool, + /// Enable all heartbeats for profiling. + pub profile_heartbeats: bool, + /// Paint borders along layer and tile boundaries. pub show_compositor_borders: bool, @@ -286,6 +292,7 @@ impl DebugOptions { "relayout-event" => debug_options.relayout_event = true, "profile-tasks" => debug_options.profile_tasks = true, "profile-script-events" => debug_options.profile_script_events = true, + "profile-heartbeats" => debug_options.profile_heartbeats = true, "show-compositor-borders" => debug_options.show_compositor_borders = true, "show-fragment-borders" => debug_options.show_fragment_borders = true, "show-parallel-paint" => debug_options.show_parallel_paint = true, @@ -325,6 +332,8 @@ pub fn print_debug_usage(app: &str) -> ! { print_option("dump-layer-tree", "Print the layer tree whenever it changes."); print_option("relayout-event", "Print notifications when there is a relayout."); print_option("profile-tasks", "Instrument each task, writing the output to a file."); + print_option("profile-script-events", "Enable profiling of script-related events."); + print_option("profile-heartbeats", "Enable heartbeats for all task categories."); print_option("show-compositor-borders", "Paint borders along layer and tile boundaries."); print_option("show-fragment-borders", "Paint borders along fragment boundaries."); print_option("show-parallel-paint", "Overlay tiles with colors showing which thread painted them."); @@ -336,10 +345,10 @@ pub fn print_debug_usage(app: &str) -> ! { print_option("disable-share-style-cache", "Disable the style sharing cache."); print_option("parallel-display-list-building", "Build display lists in parallel."); + print_option("convert-mouse-to-touch", "Send touch events instead of mouse events"); print_option("replace-surrogates", "Replace unpaires surrogates in DOM strings with U+FFFD. \ See https://github.com/servo/servo/issues/6564"); print_option("gc-profile", "Log GC passes and their durations."); - print_option("convert-mouse-to-touch", "Send touch events instead of mouse events"); println!(""); @@ -433,6 +442,7 @@ pub fn default_opts() -> Opts { validate_display_list_geometry: false, profile_tasks: false, profile_script_events: false, + profile_heartbeats: false, sniff_mime_types: false, disable_share_style_cache: false, parallel_display_list_building: false, @@ -620,6 +630,7 @@ pub fn from_cmdline_args(args: &[String]) { bubble_inline_sizes_separately: bubble_inline_sizes_separately, profile_tasks: debug_options.profile_tasks, profile_script_events: debug_options.profile_script_events, + profile_heartbeats: debug_options.profile_heartbeats, trace_layout: debug_options.trace_layout, devtools_port: devtools_port, webdriver_port: webdriver_port, |