aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorrohan.prinja <rohan.prinja@samsung.com>2015-11-03 19:01:23 +0900
committerrohan.prinja <rohan.prinja@samsung.com>2015-11-03 19:01:23 +0900
commit6e774ea6eb6d719b98f924ab5bd0629d92fb27d0 (patch)
treefa48b89bb313a2e9514124b556bbcff5ed526a0f /components
parent7032a5d1dee9bb2ba0bee45f1fda984dadfa0609 (diff)
parent4f51710ed387baa1ad0a6e4cdb0fc5eee44093d5 (diff)
downloadservo-6e774ea6eb6d719b98f924ab5bd0629d92fb27d0.tar.gz
servo-6e774ea6eb6d719b98f924ab5bd0629d92fb27d0.zip
merge from master
Diffstat (limited to 'components')
-rw-r--r--components/compositing/constellation.rs22
-rw-r--r--components/layout/block.rs19
-rw-r--r--components/layout/inline.rs7
-rw-r--r--components/layout/layout_task.rs47
-rw-r--r--components/layout/lib.rs2
-rw-r--r--components/layout/model.rs2
-rw-r--r--components/layout/wrapper.rs142
-rw-r--r--components/net/Cargo.toml3
-rw-r--r--components/net/about_loader.rs10
-rw-r--r--components/net/data_loader.rs32
-rw-r--r--components/net/file_loader.rs25
-rw-r--r--components/net/http_loader.rs17
-rw-r--r--components/net/lib.rs1
-rw-r--r--components/net/resource_task.rs10
-rw-r--r--components/profile/heartbeats.rs58
-rw-r--r--components/profile_traits/Cargo.toml2
-rw-r--r--components/profile_traits/energy.rs9
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py4
-rw-r--r--components/script/dom/bindings/global.rs4
-rw-r--r--components/script/dom/bindings/js.rs8
-rw-r--r--components/script/dom/bindings/num.rs3
-rw-r--r--components/script/dom/bindings/trace.rs30
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs25
-rw-r--r--components/script/dom/cssstyledeclaration.rs2
-rw-r--r--components/script/dom/document.rs90
-rw-r--r--components/script/dom/domrectlist.rs2
-rw-r--r--components/script/dom/domstringmap.rs3
-rw-r--r--components/script/dom/element.rs159
-rw-r--r--components/script/dom/event.rs18
-rw-r--r--components/script/dom/eventdispatcher.rs2
-rw-r--r--components/script/dom/eventtarget.rs24
-rw-r--r--components/script/dom/filelist.rs2
-rw-r--r--components/script/dom/filereader.rs7
-rw-r--r--components/script/dom/formdata.rs2
-rw-r--r--components/script/dom/htmlbodyelement.rs2
-rw-r--r--components/script/dom/htmlbuttonelement.rs19
-rw-r--r--components/script/dom/htmlcanvaselement.rs4
-rw-r--r--components/script/dom/htmlcollection.rs2
-rw-r--r--components/script/dom/htmlelement.rs99
-rw-r--r--components/script/dom/htmlfieldsetelement.rs3
-rw-r--r--components/script/dom/htmlfontelement.rs19
-rw-r--r--components/script/dom/htmliframeelement.rs4
-rw-r--r--components/script/dom/htmlimageelement.rs15
-rw-r--r--components/script/dom/htmlinputelement.rs59
-rw-r--r--components/script/dom/htmllabelelement.rs39
-rw-r--r--components/script/dom/htmlmeterelement.rs11
-rw-r--r--components/script/dom/htmloptgroupelement.rs3
-rw-r--r--components/script/dom/htmloptionelement.rs7
-rw-r--r--components/script/dom/htmloutputelement.rs7
-rw-r--r--components/script/dom/htmlprogresselement.rs11
-rw-r--r--components/script/dom/htmlscriptelement.rs12
-rw-r--r--components/script/dom/htmlselectelement.rs13
-rw-r--r--components/script/dom/htmltablecellelement.rs14
-rw-r--r--components/script/dom/htmltableelement.rs14
-rw-r--r--components/script/dom/htmltablerowelement.rs4
-rw-r--r--components/script/dom/htmltablesectionelement.rs4
-rw-r--r--components/script/dom/htmltextareaelement.rs27
-rw-r--r--components/script/dom/keyboardevent.rs11
-rw-r--r--components/script/dom/namednodemap.rs8
-rw-r--r--components/script/dom/node.rs24
-rw-r--r--components/script/dom/nodeiterator.rs2
-rw-r--r--components/script/dom/nodelist.rs6
-rw-r--r--components/script/dom/performance.rs2
-rw-r--r--components/script/dom/range.rs2
-rw-r--r--components/script/dom/servohtmlparser.rs33
-rw-r--r--components/script/dom/testbinding.rs4
-rw-r--r--components/script/dom/textencoder.rs12
-rw-r--r--components/script/dom/touchlist.rs2
-rw-r--r--components/script/dom/treewalker.rs2
-rw-r--r--components/script/dom/url.rs6
-rw-r--r--components/script/dom/urlsearchparams.rs43
-rw-r--r--components/script/dom/webglbuffer.rs8
-rw-r--r--components/script/dom/webglframebuffer.rs8
-rw-r--r--components/script/dom/webglprogram.rs8
-rw-r--r--components/script/dom/webglrenderbuffer.rs2
-rw-r--r--components/script/dom/webglrenderingcontext.rs7
-rw-r--r--components/script/dom/webglshader.rs19
-rw-r--r--components/script/dom/webgltexture.rs8
-rw-r--r--components/script/dom/webidls/HTMLButtonElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLInputElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLMeterElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLOutputElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLProgressElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLSelectElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLTextAreaElement.webidl2
-rw-r--r--components/script/dom/webidls/TestBinding.webidl1
-rw-r--r--components/script/dom/webidls/URLSearchParams.webidl14
-rw-r--r--components/script/dom/websocket.rs6
-rw-r--r--components/script/dom/window.rs16
-rw-r--r--components/script/dom/xmlhttprequest.rs9
-rw-r--r--components/script/layout_interface.rs2
-rw-r--r--components/script/lib.rs2
-rw-r--r--components/script/page.rs4
-rw-r--r--components/script/parse/html.rs56
-rw-r--r--components/script/script_task.rs43
-rw-r--r--components/script/timers.rs2
-rw-r--r--components/script/webdriver_handlers.rs4
-rw-r--r--components/servo/Cargo.lock68
-rw-r--r--components/servo/Cargo.toml3
-rw-r--r--components/servo/main.rs56
-rw-r--r--components/style/animation.rs24
-rw-r--r--components/style/lib.rs3
-rw-r--r--components/style/properties.mako.rs157
-rw-r--r--components/style/restyle_hints.rs247
-rw-r--r--components/style/selector_matching.rs18
-rw-r--r--components/style/values.rs346
-rw-r--r--components/util/lib.rs2
-rw-r--r--components/util/mem.rs3
-rw-r--r--components/util/opts.rs13
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,