diff options
-rw-r--r-- | components/layout/css/matching.rs | 9 | ||||
-rw-r--r-- | components/layout/css/node_style.rs | 58 | ||||
-rw-r--r-- | components/layout/css/node_util.rs | 75 | ||||
-rw-r--r-- | components/layout/lib.rs | 2 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 24 | ||||
-rw-r--r-- | components/script/dom/element.rs | 61 | ||||
-rw-r--r-- | components/script/dom/htmltablecellelement.rs | 25 | ||||
-rw-r--r-- | components/script/dom/htmltableelement.rs | 77 | ||||
-rw-r--r-- | components/script/dom/virtualmethods.rs | 8 | ||||
-rw-r--r-- | components/style/legacy.rs | 58 | ||||
-rw-r--r-- | components/style/lib.rs | 8 | ||||
-rw-r--r-- | components/style/node.rs | 4 | ||||
-rw-r--r-- | components/style/selector_matching.rs | 13 | ||||
-rw-r--r-- | components/style/selectors.rs | 9 | ||||
-rw-r--r-- | components/util/str.rs | 4 | ||||
-rw-r--r-- | resources/presentational-hints.css | 20 | ||||
-rw-r--r-- | tests/ref/basic.list | 1 | ||||
-rw-r--r-- | tests/ref/legacy_table_border_attribute_a.html | 9 | ||||
-rw-r--r-- | tests/ref/legacy_table_border_attribute_ref.html | 10 |
19 files changed, 349 insertions, 126 deletions
diff --git a/components/layout/css/matching.rs b/components/layout/css/matching.rs index f1615aa005d..86968a6d9c2 100644 --- a/components/layout/css/matching.rs +++ b/components/layout/css/matching.rs @@ -268,6 +268,9 @@ impl StyleSharingCandidate { return false } + // FIXME(pcwalton): It's probably faster to iterate over all the element's attributes and + // use the {common, rare}-style-affecting-attributes tables as lookup tables. + for attribute_info in style::common_style_affecting_attributes().iter() { match attribute_info.mode { AttrIsPresentMode(flag) => { @@ -295,6 +298,12 @@ impl StyleSharingCandidate { } } + for attribute_name in style::rare_style_affecting_attributes().iter() { + if element.get_attr(&ns!(""), attribute_name).is_some() { + return false + } + } + if element.get_link().is_some() != self.link { return false } diff --git a/components/layout/css/node_style.rs b/components/layout/css/node_style.rs index ecfb3383453..c3eaa04ddd2 100644 --- a/components/layout/css/node_style.rs +++ b/components/layout/css/node_style.rs @@ -2,27 +2,75 @@ * 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/. */ -// Style retrieval from DOM elements. +//! Style retrieval from DOM elements. -use css::node_util::NodeUtil; -use wrapper::ThreadSafeLayoutNode; +use wrapper::{After, Before, Normal, ThreadSafeLayoutNode}; +use std::mem; use style::ComputedValues; use sync::Arc; /// Node mixin providing `style` method that returns a `NodeStyle` pub trait StyledNode { + /// Returns the style results for the given node. If CSS selector matching has not yet been + /// performed, fails. fn style<'a>(&'a self) -> &'a Arc<ComputedValues>; + /// Does this node have a computed style yet? + fn has_style(&self) -> bool; + /// Removes the style from this node. fn unstyle(self); } impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> { #[inline] fn style<'a>(&'a self) -> &'a Arc<ComputedValues> { - self.get_css_select_results() + unsafe { + let layout_data_ref = self.borrow_layout_data(); + match self.get_pseudo_element_type() { + Before(_) => { + mem::transmute(layout_data_ref.as_ref() + .unwrap() + .data + .before_style + .as_ref() + .unwrap()) + } + After(_) => { + mem::transmute(layout_data_ref.as_ref() + .unwrap() + .data + .after_style + .as_ref() + .unwrap()) + } + Normal => { + mem::transmute(layout_data_ref.as_ref() + .unwrap() + .shared_data + .style + .as_ref() + .unwrap()) + } + } + } + } + + fn has_style(&self) -> bool { + let layout_data_ref = self.borrow_layout_data(); + layout_data_ref.as_ref().unwrap().shared_data.style.is_some() } fn unstyle(self) { - self.remove_css_select_results() + let mut layout_data_ref = self.mutate_layout_data(); + let layout_data = layout_data_ref.as_mut().expect("no layout data"); + + let style = + match self.get_pseudo_element_type() { + Before(_) => &mut layout_data.data.before_style, + After (_) => &mut layout_data.data.after_style, + Normal => &mut layout_data.shared_data.style, + }; + + *style = None; } } diff --git a/components/layout/css/node_util.rs b/components/layout/css/node_util.rs deleted file mode 100644 index eb447b0cf6b..00000000000 --- a/components/layout/css/node_util.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* 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 util::LayoutDataAccess; -use wrapper::ThreadSafeLayoutNode; -use wrapper::{After, Before, Normal}; - -use std::mem; -use style::ComputedValues; -use sync::Arc; - -pub trait NodeUtil { - fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>; - fn have_css_select_results(&self) -> bool; - fn remove_css_select_results(self); -} - -impl<'ln> NodeUtil for ThreadSafeLayoutNode<'ln> { - /// Returns the style results for the given node. If CSS selector - /// matching has not yet been performed, fails. - #[inline] - fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> { - unsafe { - let layout_data_ref = self.borrow_layout_data(); - match self.get_pseudo_element_type() { - Before(_) => { - mem::transmute(layout_data_ref.as_ref() - .unwrap() - .data - .before_style - .as_ref() - .unwrap()) - } - After(_) => { - mem::transmute(layout_data_ref.as_ref() - .unwrap() - .data - .after_style - .as_ref() - .unwrap()) - } - Normal => { - mem::transmute(layout_data_ref.as_ref() - .unwrap() - .shared_data - .style - .as_ref() - .unwrap()) - } - } - } - } - - /// Does this node have a computed style yet? - fn have_css_select_results(&self) -> bool { - let layout_data_ref = self.borrow_layout_data(); - layout_data_ref.as_ref().unwrap().shared_data.style.is_some() - } - - fn remove_css_select_results(self) { - let mut layout_data_ref = self.mutate_layout_data(); - let layout_data = layout_data_ref.as_mut().expect("no layout data"); - - let style = - match self.get_pseudo_element_type() { - Before(_) => &mut layout_data.data.before_style, - After (_) => &mut layout_data.data.after_style, - Normal => &mut layout_data.shared_data.style, - }; - - *style = None; - } -} - diff --git a/components/layout/lib.rs b/components/layout/lib.rs index 1fa21311373..af91126cc4a 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -70,8 +70,6 @@ pub mod incremental; pub mod wrapper; pub mod css { - mod node_util; - pub mod matching; pub mod node_style; } diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 9a70539c78b..ba16eb885a9 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -56,11 +56,12 @@ use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_util::str::{LengthOrPercentageOrAuto, is_whitespace}; use std::kinds::marker::ContravariantLifetime; use std::mem; +use string_cache::{Atom, Namespace}; use style::computed_values::{content, display, white_space}; -use style::{AnyNamespace, AttrSelector, IntegerAttribute, LengthAttribute}; -use style::{PropertyDeclarationBlock, SpecificNamespace, TElement, TElementAttributes, TNode}; +use style::{AnyNamespace, AttrSelector, BorderUnsignedIntegerAttribute, IntegerAttribute}; +use style::{LengthAttribute, PropertyDeclarationBlock, SpecificNamespace, TElement}; +use style::{TElementAttributes, TNode, UnsignedIntegerAttribute}; use url::Url; -use string_cache::{Atom, Namespace}; use std::cell::{Ref, RefMut}; @@ -580,6 +581,17 @@ impl<'le> TElement<'le> for LayoutElement<'le> { } } } + + #[inline] + fn has_nonzero_border(self) -> bool { + unsafe { + match self.element + .get_unsigned_integer_attribute_for_layout(BorderUnsignedIntegerAttribute) { + None | Some(0) => false, + _ => true, + } + } + } } impl<'le> TElementAttributes for LayoutElement<'le> { @@ -594,6 +606,12 @@ impl<'le> TElementAttributes for LayoutElement<'le> { self.element.get_integer_attribute_for_layout(integer_attribute) } } + + fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) -> Option<u32> { + unsafe { + self.element.get_unsigned_integer_attribute_for_layout(attribute) + } + } } fn get_content(content_list: &content::T) -> String { diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 1e55f9f73c2..db2b8d3d096 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -15,8 +15,10 @@ use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods; -use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLInputElementDerived, HTMLTableCellElementDerived}; -use dom::bindings::codegen::InheritTypes::{HTMLInputElementCast, NodeCast, EventTargetCast, ElementCast}; +use dom::bindings::codegen::InheritTypes::{ElementCast, ElementDerived, EventTargetCast}; +use dom::bindings::codegen::InheritTypes::{HTMLInputElementCast, HTMLInputElementDerived}; +use dom::bindings::codegen::InheritTypes::{HTMLTableElementCast, HTMLTableElementDerived}; +use dom::bindings::codegen::InheritTypes::{HTMLTableCellElementDerived, NodeCast}; use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable}; use dom::bindings::js::{OptionalRootable, Root}; use dom::bindings::utils::{Reflectable, Reflector}; @@ -32,14 +34,16 @@ use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers}; use dom::htmlcollection::HTMLCollection; use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers}; use dom::htmlserializer::serialize; +use dom::htmltableelement::{HTMLTableElement, HTMLTableElementHelpers}; use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementHelpers}; -use dom::node::{CLICK_IN_PROGRESS, ElementNodeTypeId, Node, NodeHelpers, NodeIterator}; -use dom::node::{document_from_node, window_from_node, LayoutNodeHelpers, NodeStyleDamaged}; -use dom::node::{OtherNodeDamage}; +use dom::node::{CLICK_IN_PROGRESS, ElementNodeTypeId, LayoutNodeHelpers, Node, NodeHelpers}; +use dom::node::{NodeIterator, NodeStyleDamaged, OtherNodeDamage, document_from_node}; +use dom::node::{window_from_node}; use dom::nodelist::NodeList; use dom::virtualmethods::{VirtualMethods, vtable_for}; use devtools_traits::AttrInfo; -use style::{IntegerAttribute, LengthAttribute, SizeIntegerAttribute, WidthLengthAttribute}; +use style::{BorderUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute}; +use style::{SizeIntegerAttribute, UnsignedIntegerAttribute, WidthLengthAttribute}; use style::{matches, parse_selector_list_from_str}; use style; use servo_util::namespace; @@ -201,6 +205,8 @@ pub trait RawLayoutElementHelpers { unsafe fn get_integer_attribute_for_layout(&self, integer_attribute: IntegerAttribute) -> Option<i32>; unsafe fn get_checked_state_for_layout(&self) -> bool; + unsafe fn get_unsigned_integer_attribute_for_layout(&self, attribute: UnsignedIntegerAttribute) + -> Option<u32>; fn local_name<'a>(&'a self) -> &'a Atom; fn namespace<'a>(&'a self) -> &'a Namespace; fn style_attribute<'a>(&'a self) -> &'a DOMRefCell<Option<style::PropertyDeclarationBlock>>; @@ -285,11 +291,15 @@ impl RawLayoutElementHelpers for Element { -> LengthOrPercentageOrAuto { match length_attribute { WidthLengthAttribute => { - if !self.is_htmltablecellelement() { - panic!("I'm not a table cell!") + if self.is_htmltableelement() { + let this: &HTMLTableElement = mem::transmute(self); + this.get_width() + } else if self.is_htmltablecellelement() { + let this: &HTMLTableCellElement = mem::transmute(self); + this.get_width() + } else { + panic!("I'm not a table or table cell!") } - let this: &HTMLTableCellElement = mem::transmute(self); - this.get_width() } } } @@ -319,6 +329,26 @@ impl RawLayoutElementHelpers for Element { this.get_checked_state_for_layout() } + unsafe fn get_unsigned_integer_attribute_for_layout(&self, + attribute: UnsignedIntegerAttribute) + -> Option<u32> { + match attribute { + BorderUnsignedIntegerAttribute => { + if self.is_htmltableelement() { + let this: &HTMLTableElement = mem::transmute(self); + this.get_border() + } else if self.is_htmltablecellelement() { + let this: &HTMLTableCellElement = mem::transmute(self); + this.get_border() + } else { + // Don't panic since `:-servo-nonzero-border` can cause this to be called on + // arbitrary elements. + None + } + } + } + } + // Getters used in components/layout/wrapper.rs fn local_name<'a>(&'a self) -> &'a Atom { @@ -1222,6 +1252,17 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> { } } } + fn has_nonzero_border(self) -> bool { + match HTMLTableElementCast::to_ref(self) { + None => false, + Some(this) => { + match this.get_border() { + None | Some(0) => false, + Some(_) => true, + } + } + } + } } pub trait ActivationElementHelpers<'a> { diff --git a/components/script/dom/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs index cee07540301..622389397e9 100644 --- a/components/script/dom/htmltablecellelement.rs +++ b/components/script/dom/htmltablecellelement.rs @@ -2,8 +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::attr::Attr; -use dom::attr::AttrHelpers; +use dom::attr::{Attr, AttrHelpers}; use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableCellElementDerived}; use dom::bindings::js::JSRef; use dom::bindings::utils::{Reflectable, Reflector}; @@ -22,6 +21,7 @@ use std::cell::Cell; #[dom_struct] pub struct HTMLTableCellElement { htmlelement: HTMLElement, + border: Cell<Option<u32>>, width: Cell<LengthOrPercentageOrAuto>, } @@ -36,10 +36,15 @@ impl HTMLTableCellElementDerived for EventTarget { } impl HTMLTableCellElement { - pub fn new_inherited(type_id: ElementTypeId, tag_name: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTableCellElement { + pub fn new_inherited(type_id: ElementTypeId, + tag_name: DOMString, + prefix: Option<DOMString>, + document: JSRef<Document>) + -> HTMLTableCellElement { HTMLTableCellElement { htmlelement: HTMLElement::new_inherited(type_id, tag_name, prefix, document), - width: Cell::new(AutoLpa) + border: Cell::new(None), + width: Cell::new(AutoLpa), } } @@ -50,10 +55,15 @@ impl HTMLTableCellElement { } pub trait HTMLTableCellElementHelpers { + fn get_border(&self) -> Option<u32>; fn get_width(&self) -> LengthOrPercentageOrAuto; } impl HTMLTableCellElementHelpers for HTMLTableCellElement { + fn get_border(&self) -> Option<u32> { + self.border.get() + } + fn get_width(&self) -> LengthOrPercentageOrAuto { self.width.get() } @@ -72,6 +82,12 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableCellElement> { } match attr.local_name() { + &atom!("border") => { + // According to HTML5 § 14.3.9, invalid values map to 1px. + self.border.set(Some(str::parse_unsigned_integer(attr.value() + .as_slice() + .chars()).unwrap_or(1))) + } &atom!("width") => self.width.set(str::parse_length(attr.value().as_slice())), _ => () } @@ -84,6 +100,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableCellElement> { } match attr.local_name() { + &atom!("border") => self.border.set(None), &atom!("width") => self.width.set(AutoLpa), _ => () } diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs index 7dddf98bdc4..9a7acd02559 100644 --- a/components/script/dom/htmltableelement.rs +++ b/components/script/dom/htmltableelement.rs @@ -2,10 +2,12 @@ * 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::HTMLTableElementBinding; +use dom::attr::{Attr, AttrHelpers}; use dom::bindings::codegen::Bindings::HTMLTableElementBinding::HTMLTableElementMethods; -use dom::bindings::codegen::InheritTypes::{HTMLTableElementDerived, NodeCast, HTMLTableCaptionElementCast}; +use dom::bindings::codegen::Bindings::HTMLTableElementBinding; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableCaptionElementCast}; +use dom::bindings::codegen::InheritTypes::{HTMLTableElementDerived, NodeCast}; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::Document; @@ -14,11 +16,16 @@ use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::htmltablecaptionelement::HTMLTableCaptionElement; use dom::node::{Node, NodeHelpers, ElementNodeTypeId}; -use servo_util::str::DOMString; +use dom::virtualmethods::VirtualMethods; + +use servo_util::str::{mod, AutoLpa, DOMString, LengthOrPercentageOrAuto}; +use std::cell::Cell; #[dom_struct] pub struct HTMLTableElement { htmlelement: HTMLElement, + border: Cell<Option<u32>>, + width: Cell<LengthOrPercentageOrAuto>, } impl HTMLTableElementDerived for EventTarget { @@ -28,14 +35,21 @@ impl HTMLTableElementDerived for EventTarget { } impl HTMLTableElement { - fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTableElement { + fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) + -> HTMLTableElement { HTMLTableElement { - htmlelement: HTMLElement::new_inherited(HTMLTableElementTypeId, localName, prefix, document) + htmlelement: HTMLElement::new_inherited(HTMLTableElementTypeId, + localName, + prefix, + document), + border: Cell::new(None), + width: Cell::new(AutoLpa), } } #[allow(unrooted_must_root)] - pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLTableElement> { + pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) + -> Temporary<HTMLTableElement> { let element = HTMLTableElement::new_inherited(localName, prefix, document); Node::reflect_node(box element, document, HTMLTableElementBinding::Wrap) } @@ -77,3 +91,54 @@ impl<'a> HTMLTableElementMethods for JSRef<'a, HTMLTableElement> { }); } } + +pub trait HTMLTableElementHelpers { + fn get_border(&self) -> Option<u32>; + fn get_width(&self) -> LengthOrPercentageOrAuto; +} + +impl HTMLTableElementHelpers for HTMLTableElement { + fn get_border(&self) -> Option<u32> { + self.border.get() + } + fn get_width(&self) -> LengthOrPercentageOrAuto { + self.width.get() + } +} + +impl<'a> VirtualMethods for JSRef<'a, HTMLTableElement> { + fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> { + let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self); + Some(htmlelement as &VirtualMethods) + } + + fn after_set_attr(&self, attr: JSRef<Attr>) { + match self.super_type() { + Some(ref s) => s.after_set_attr(attr), + _ => () + } + + match attr.local_name() { + &atom!("border") => { + // According to HTML5 § 14.3.9, invalid values map to 1px. + self.border.set(Some(str::parse_unsigned_integer(attr.value() + .as_slice() + .chars()).unwrap_or(1))) + } + _ => () + } + } + + fn before_remove_attr(&self, attr: JSRef<Attr>) { + match self.super_type() { + Some(ref s) => s.before_remove_attr(attr), + _ => () + } + + match attr.local_name() { + &atom!("border") => self.border.set(None), + _ => () + } + } +} + diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index a90055bc50d..2f75127c513 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -22,6 +22,7 @@ use dom::bindings::codegen::InheritTypes::HTMLOptionElementCast; use dom::bindings::codegen::InheritTypes::HTMLScriptElementCast; use dom::bindings::codegen::InheritTypes::HTMLSelectElementCast; use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast; +use dom::bindings::codegen::InheritTypes::HTMLTableElementCast; use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast; use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast; use dom::bindings::codegen::InheritTypes::HTMLTitleElementCast; @@ -46,6 +47,7 @@ use dom::element::HTMLScriptElementTypeId; use dom::element::HTMLSelectElementTypeId; use dom::element::HTMLStyleElementTypeId; use dom::element::HTMLTableDataCellElementTypeId; +use dom::element::HTMLTableElementTypeId; use dom::element::HTMLTableHeaderCellElementTypeId; use dom::element::HTMLTextAreaElementTypeId; use dom::element::HTMLTitleElementTypeId; @@ -67,6 +69,7 @@ use dom::htmloptionelement::HTMLOptionElement; use dom::htmlscriptelement::HTMLScriptElement; use dom::htmlselectelement::HTMLSelectElement; use dom::htmlstyleelement::HTMLStyleElement; +use dom::htmltableelement::HTMLTableElement; use dom::htmltablecellelement::HTMLTableCellElement; use dom::htmltextareaelement::HTMLTextAreaElement; use dom::htmltitleelement::HTMLTitleElement; @@ -226,6 +229,11 @@ pub fn vtable_for<'a>(node: &'a JSRef<'a, Node>) -> &'a VirtualMethods + 'a { let element: &'a JSRef<'a, HTMLStyleElement> = HTMLStyleElementCast::to_borrowed_ref(node).unwrap(); element as &'a VirtualMethods + 'a } + ElementNodeTypeId(HTMLTableElementTypeId) => { + let element: &'a JSRef<'a, HTMLTableElement> = + HTMLTableElementCast::to_borrowed_ref(node).unwrap(); + element as &'a VirtualMethods + 'a + } ElementNodeTypeId(HTMLTableDataCellElementTypeId) | ElementNodeTypeId(HTMLTableHeaderCellElementTypeId) => { let element: &'a JSRef<'a, HTMLTableCellElement> = HTMLTableCellElementCast::to_borrowed_ref(node).unwrap(); diff --git a/components/style/legacy.rs b/components/style/legacy.rs index 4a4e8a428f0..8eb9a7d1e56 100644 --- a/components/style/legacy.rs +++ b/components/style/legacy.rs @@ -6,7 +6,9 @@ //! `<input size>`, and so forth. use node::{TElement, TElementAttributes, TNode}; -use properties::{SpecifiedValue, WidthDeclaration, specified}; +use properties::{BorderBottomWidthDeclaration, BorderLeftWidthDeclaration}; +use properties::{BorderRightWidthDeclaration, BorderTopWidthDeclaration, SpecifiedValue}; +use properties::{WidthDeclaration, specified}; use selector_matching::{DeclarationBlock, Stylist}; use servo_util::geometry::Au; @@ -25,6 +27,12 @@ pub enum IntegerAttribute { SizeIntegerAttribute, } +/// Legacy presentational attributes that take a nonnegative integer as defined in HTML5 § 2.4.4.2. +pub enum UnsignedIntegerAttribute { + /// `<td border>` + BorderUnsignedIntegerAttribute, +} + /// Extension methods for `Stylist` that cause rules to be synthesized for legacy attributes. pub trait PresentationalHintSynthesis { /// Synthesizes rules from various HTML attributes (mostly legacy junk from HTML4) that confer @@ -39,6 +47,16 @@ pub trait PresentationalHintSynthesis { TElementAttributes, N: TNode<'a,E>, V: VecLike<DeclarationBlock>; + /// Synthesizes rules for the legacy `border` attribute. + fn synthesize_presentational_hint_for_legacy_border_attribute<'a,E,V>( + &self, + element: E, + matching_rules_list: &mut V, + shareable: &mut bool) + where + E: TElement<'a> + + TElementAttributes, + V: VecLike<DeclarationBlock>; } impl PresentationalHintSynthesis for Stylist { @@ -68,7 +86,17 @@ impl PresentationalHintSynthesis for Stylist { WidthDeclaration(SpecifiedValue(width_value)))); *shareable = false } - }; + } + self.synthesize_presentational_hint_for_legacy_border_attribute( + element, + matching_rules_list, + shareable); + } + name if *name == atom!("table") => { + self.synthesize_presentational_hint_for_legacy_border_attribute( + element, + matching_rules_list, + shareable); } name if *name == atom!("input") => { match element.get_integer_attribute(SizeIntegerAttribute) { @@ -94,5 +122,31 @@ impl PresentationalHintSynthesis for Stylist { _ => {} } } + + fn synthesize_presentational_hint_for_legacy_border_attribute<'a,E,V>( + &self, + element: E, + matching_rules_list: &mut V, + shareable: &mut bool) + where + E: TElement<'a> + + TElementAttributes, + V: VecLike<DeclarationBlock> { + match element.get_unsigned_integer_attribute(BorderUnsignedIntegerAttribute) { + None => {} + Some(length) => { + let width_value = specified::Au_(Au::from_px(length as int)); + matching_rules_list.vec_push(DeclarationBlock::from_declaration( + BorderTopWidthDeclaration(SpecifiedValue(width_value)))); + matching_rules_list.vec_push(DeclarationBlock::from_declaration( + BorderLeftWidthDeclaration(SpecifiedValue(width_value)))); + matching_rules_list.vec_push(DeclarationBlock::from_declaration( + BorderBottomWidthDeclaration(SpecifiedValue(width_value)))); + matching_rules_list.vec_push(DeclarationBlock::from_declaration( + BorderRightWidthDeclaration(SpecifiedValue(width_value)))); + *shareable = false + } + } + } } diff --git a/components/style/lib.rs b/components/style/lib.rs index e6e0e77f7a5..23a674151b4 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -41,7 +41,8 @@ pub use selector_matching::{DeclarationBlock, CommonStyleAffectingAttributes}; pub use selector_matching::{CommonStyleAffectingAttributeInfo, CommonStyleAffectingAttributeMode}; pub use selector_matching::{AttrIsPresentMode, AttrIsEqualMode}; pub use selector_matching::{matches, matches_simple_selector, common_style_affecting_attributes}; -pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE,SELECTOR_WHITESPACE}; +pub use selector_matching::{rare_style_affecting_attributes}; +pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE, SELECTOR_WHITESPACE}; pub use properties::{cascade, cascade_anonymous, computed}; pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs}; pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes @@ -51,9 +52,10 @@ pub use properties::{Left, Right, Bottom, Top}; pub use node::{TElement, TElementAttributes, TNode}; pub use selectors::{PseudoElement, Before, After, SelectorList, parse_selector_list_from_str}; pub use selectors::{AttrSelector, NamespaceConstraint, SpecificNamespace, AnyNamespace}; -pub use selectors::{SimpleSelector,LocalNameSelector}; +pub use selectors::{SimpleSelector, LocalNameSelector}; pub use cssparser::{Color, RGBA}; -pub use legacy::{IntegerAttribute, LengthAttribute, SizeIntegerAttribute, WidthLengthAttribute}; +pub use legacy::{BorderUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute}; +pub use legacy::{SizeIntegerAttribute, UnsignedIntegerAttribute, WidthLengthAttribute}; pub use font_face::{Source, LocalSource, UrlSource_}; mod stylesheets; diff --git a/components/style/node.rs b/components/style/node.rs index 5a765f2798d..3d9ad18e623 100644 --- a/components/style/node.rs +++ b/components/style/node.rs @@ -5,7 +5,7 @@ //! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and //! style. -use legacy::{IntegerAttribute, LengthAttribute}; +use legacy::{IntegerAttribute, LengthAttribute, UnsignedIntegerAttribute}; use selectors::AttrSelector; use servo_util::str::LengthOrPercentageOrAuto; use string_cache::{Atom, Namespace}; @@ -47,6 +47,7 @@ pub trait TElement<'a> : Copy { fn get_enabled_state(self) -> bool; fn get_checked_state(self) -> bool; fn has_class(self, name: &Atom) -> bool; + fn has_nonzero_border(self) -> bool; // Ordinarily I wouldn't use callbacks like this, but the alternative is // really messy, since there is a `JSRef` and a `RefCell` involved. Maybe @@ -58,4 +59,5 @@ pub trait TElement<'a> : Copy { pub trait TElementAttributes : Copy { fn get_length_attribute(self, attribute: LengthAttribute) -> LengthOrPercentageOrAuto; fn get_integer_attribute(self, attribute: IntegerAttribute) -> Option<i32>; + fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) -> Option<u32>; } diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 228ff41af05..b1fbd5042e8 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -799,6 +799,13 @@ pub fn common_style_affecting_attributes() -> [CommonStyleAffectingAttributeInfo ] } +/// Attributes that, if present, disable style sharing. All legacy HTML attributes must be in +/// either this list or `common_style_affecting_attributes`. See the comment in +/// `synthesize_presentational_hints_for_legacy_attributes`. +pub fn rare_style_affecting_attributes() -> [Atom, ..1] { + [ atom!("border") ] +} + /// Determines whether the given element matches the given single selector. /// /// NB: If you add support for any new kinds of selectors to this routine, be sure to set @@ -993,6 +1000,12 @@ pub fn matches_simple_selector<'a,E,N>(selector: &SimpleSelector, matches_generic_nth_child(element, 0, 1, true, true) } + ServoNonzeroBorder => { + *shareable = false; + let elem = element.as_element(); + elem.has_nonzero_border() + } + Negation(ref negated) => { *shareable = false; !negated.iter().all(|s| matches_simple_selector(s, element, shareable)) diff --git a/components/style/selectors.rs b/components/style/selectors.rs index da0e2b7b638..9cb3f240dd4 100644 --- a/components/style/selectors.rs +++ b/components/style/selectors.rs @@ -79,7 +79,8 @@ pub enum SimpleSelector { NthLastOfType(i32, i32), FirstOfType, LastOfType, - OnlyOfType + OnlyOfType, + ServoNonzeroBorder, // ... } @@ -231,7 +232,7 @@ fn compute_specificity(mut selector: &CompoundSelector, // | &Empty | &Lang(*) | &NthChild(..) | &NthLastChild(..) | &NthOfType(..) | &NthLastOfType(..) - | &FirstOfType | &LastOfType | &OnlyOfType + | &FirstOfType | &LastOfType | &OnlyOfType | &ServoNonzeroBorder => specificity.class_like_selectors += 1, &NamespaceSelector(..) => (), &Negation(ref negated) @@ -506,6 +507,10 @@ fn parse_simple_pseudo_class(name: &str) -> Result<SimpleSelector, ()> { "first-of-type" => Ok(FirstOfType), "last-of-type" => Ok(LastOfType), "only-of-type" => Ok(OnlyOfType), + "-servo-nonzero-border" => { + // TODO(pcwalton): Have some mechanism whereby we forbid Web content from using this. + Ok(ServoNonzeroBorder) + } // "empty" => Ok(Empty), _ => Err(()) } diff --git a/components/util/str.rs b/components/util/str.rs index 28aedee4f30..0428d0db5b2 100644 --- a/components/util/str.rs +++ b/components/util/str.rs @@ -61,7 +61,8 @@ pub static HTML_SPACE_CHARACTERS: StaticCharVec = &[ '\u000d', ]; -pub fn split_html_space_chars<'a>(s: &'a str) -> Filter<'a, &'a str, CharSplits<'a, StaticCharVec>> { +pub fn split_html_space_chars<'a>(s: &'a str) + -> Filter<'a, &'a str, CharSplits<'a, StaticCharVec>> { s.split(HTML_SPACE_CHARACTERS).filter(|&split| !split.is_empty()) } @@ -76,7 +77,6 @@ fn do_parse_integer<T: Iterator<char>>(input: T) -> Option<i64> { } } - let mut input = input.skip_while(|c| { HTML_SPACE_CHARACTERS.iter().any(|s| s == c) }).peekable(); diff --git a/resources/presentational-hints.css b/resources/presentational-hints.css index dcccbf9a64b..b3b4d2a5dd1 100644 --- a/resources/presentational-hints.css +++ b/resources/presentational-hints.css @@ -57,12 +57,8 @@ table:matches([rules=none i], [rules=groups i], [rules=rows i], [rules=cols i], border-collapse: collapse; } -table[border] { +table:-servo-nonzero-border { border-style: outset; - /* - FIXME: only if border is not equivalent to zero - https://html.spec.whatwg.org/multipage/rendering.html#magic-border-selector - */ } table[frame=void i] { border-style: hidden; } table[frame=above i] { border-style: outset hidden hidden hidden; } @@ -74,12 +70,14 @@ table[frame=vsides i] { border-style: hidden outset; } table[frame=box i], table[frame=border i] { border-style: outset; } -table[border] > tr > :matches(td, th), -table[border] > :matches(thead, tbody, tfoot) > tr > :matches(td, th) { - /* - FIXME: only if border is not equivalent to zero - https://html.spec.whatwg.org/multipage/rendering.html#magic-border-selector - */ +table:-servo-nonzero-border > tr > td, +table:-servo-nonzero-border > tr > th, +table:-servo-nonzero-border > thead > tr > td, +table:-servo-nonzero-border > thead > tr > th, +table:-servo-nonzero-border > tbody > tr > td, +table:-servo-nonzero-border > tbody > tr > th, +table:-servo-nonzero-border > tfoot > tr > td, +table:-servo-nonzero-border > tfoot > tr > th { border-width: 1px; border-style: inset; } diff --git a/tests/ref/basic.list b/tests/ref/basic.list index d4b0571a7da..980350b5d9a 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -209,3 +209,4 @@ fragment=top != ../html/acid2.html acid2_ref.html == box_shadow_inset_parsing_a.html box_shadow_inset_parsing_ref.html != list_style_type_a.html list_style_type_ref.html == list_style_position_a.html list_style_position_ref.html +== legacy_table_border_attribute_a.html legacy_table_border_attribute_ref.html diff --git a/tests/ref/legacy_table_border_attribute_a.html b/tests/ref/legacy_table_border_attribute_a.html new file mode 100644 index 00000000000..44c32e2cdc6 --- /dev/null +++ b/tests/ref/legacy_table_border_attribute_a.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<body> +<table border=10 style="border-style: solid; border-color: black"><tr><td style="border: none">:-)</td></tr></table> +<table border=mimi style="border-style: solid; border-color: black"><tr><td style="border: none">:-)</td></tr></table> +<table border=0 style="border-style: solid; border-color: black"><tr><td style="border: none">:-)</td></tr></table> +</body> +</html> + diff --git a/tests/ref/legacy_table_border_attribute_ref.html b/tests/ref/legacy_table_border_attribute_ref.html new file mode 100644 index 00000000000..0b513372ac7 --- /dev/null +++ b/tests/ref/legacy_table_border_attribute_ref.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> +<body> +<table style="border: solid black 10px"><tr><td>:-)</td></tr></table> +<table style="border: solid black 1px"><tr><td>:-)</td></tr></table> +<table style="border: none"><tr><td>:-)</td></tr></table> +</body> +</html> + + |