diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2014-12-11 09:58:00 -0800 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2014-12-15 18:09:44 -0800 |
commit | a1ea44b294e73f4397887fe806fc5bc95499efda (patch) | |
tree | a32b122e99c87a1f98e6b05c087fee00411cef36 | |
parent | 17835ba0cb446e1d542c7e5347210c03158a9fec (diff) | |
download | servo-a1ea44b294e73f4397887fe806fc5bc95499efda.tar.gz servo-a1ea44b294e73f4397887fe806fc5bc95499efda.zip |
style: Address review comments relating to `bgcolor` and column spans
33 files changed, 712 insertions, 422 deletions
diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index edd6ed0ad1b..ca77107965b 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -31,6 +31,9 @@ path = "../net" [dependencies.util] path = "../util" +[dependencies.cssparser] +git = "https://github.com/servo/rust-cssparser" + [dependencies.encoding] git = "https://github.com/lifthrasiir/rust-encoding" diff --git a/components/layout/lib.rs b/components/layout/lib.rs index af91126cc4a..26054f0dae0 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -14,6 +14,7 @@ #[phase(plugin, link)] extern crate log; +extern crate cssparser; extern crate geom; extern crate gfx; extern crate layout_traits; diff --git a/components/layout/table.rs b/components/layout/table.rs index 1bab26d06a9..0e2af0b2f68 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -106,9 +106,10 @@ impl TableFlow { /// Update the corresponding value of `self_inline_sizes` if a value of `kid_inline_sizes` has /// a larger value than one of `self_inline_sizes`. Returns the minimum and preferred inline /// sizes. - fn update_automatic_column_inline_sizes(parent_inline_sizes: &mut Vec<ColumnInlineSize>, - child_cell_inline_sizes: &[CellIntrinsicInlineSize]) - -> IntrinsicISizes { + fn update_automatic_column_inline_sizes( + parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>, + child_cell_inline_sizes: &[CellIntrinsicInlineSize]) + -> IntrinsicISizes { let mut total_inline_sizes = IntrinsicISizes::new(); let mut column_index = 0; for child_cell_inline_size in child_cell_inline_sizes.iter() { @@ -122,7 +123,7 @@ impl TableFlow { // 4. For now we make this column contribute no width. } else { let column_size = &child_cell_inline_size.column_size; - *parent_sizes = ColumnInlineSize { + *parent_sizes = ColumnIntrinsicInlineSize { minimum_length: max(parent_sizes.minimum_length, column_size.minimum_length), percentage: parent_sizes.greatest_percentage(column_size), @@ -136,7 +137,7 @@ impl TableFlow { if child_cell_inline_size.column_span > 1 { // TODO(pcwalton): Perform the recursive algorithm specified in INTRINSIC § // 4. For now we make this column contribute no width. - parent_inline_sizes.push(ColumnInlineSize::new()) + parent_inline_sizes.push(ColumnIntrinsicInlineSize::new()) } else { parent_inline_sizes.push(child_cell_inline_size.column_size) } @@ -169,7 +170,7 @@ impl TableFlow { /// Updates the minimum and preferred inline-size calculation for a single row. This is /// factored out into a separate function because we process children of rowgroups too. fn update_column_inline_sizes_for_row(child: &mut Flow, - column_inline_sizes: &mut Vec<ColumnInlineSize>, + column_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>, computation: &mut IntrinsicISizesContribution, did_first_row: &mut bool, table_layout: TableLayout) { @@ -254,18 +255,20 @@ impl Flow for TableFlow { } } else if kid.is_table_rowgroup() { for grandkid in flow::mut_base(kid).child_iter() { - TableFlow::update_column_inline_sizes_for_row(grandkid, - &mut self.column_inline_sizes, - &mut computation, - &mut did_first_row, - self.table_layout) + TableFlow::update_column_inline_sizes_for_row( + grandkid, + &mut self.column_intrinsic_inline_sizes, + &mut computation, + &mut did_first_row, + self.table_layout) } } else if kid.is_table_row() { - TableFlow::update_column_inline_sizes_for_row(kid, - &mut self.column_inline_sizes, - &mut computation, - &mut did_first_row, - self.table_layout) + TableFlow::update_column_inline_sizes_for_row( + kid, + &mut self.column_intrinsic_inline_sizes, + &mut computation, + &mut did_first_row, + self.table_layout) } } @@ -309,8 +312,7 @@ impl Flow for TableFlow { // In fixed table layout, we distribute extra space among the unspecified columns // if there are any, or among all the columns if all are specified. self.column_computed_inline_sizes.clear(); - if total_column_inline_size < content_inline_size && - num_unspecified_inline_sizes == 0 { + if num_unspecified_inline_sizes == 0 { let ratio = content_inline_size.to_subpx() / total_column_inline_size.to_subpx(); for column_inline_size in self.column_intrinsic_inline_sizes.iter() { @@ -445,6 +447,16 @@ pub struct ColumnIntrinsicInlineSize { } impl ColumnIntrinsicInlineSize { + /// Returns a newly-initialized `ColumnIntrinsicInlineSize` with all fields blank. + pub fn new() -> ColumnIntrinsicInlineSize { + ColumnIntrinsicInlineSize { + preferred: Au(0), + minimum_length: Au(0), + percentage: 0.0, + constrained: false, + } + } + /// Returns the true minimum size of this column, given the containing block's inline size. /// Beware that this is generally only correct for fixed table layout. (Compare CSS 2.1 § /// 17.5.2.1 with the algorithm in INTRINSIC § 4.) diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 280e86408cb..0a4e7d05e24 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -17,7 +17,7 @@ use wrapper::ThreadSafeLayoutNode; use servo_util::geometry::Au; use std::fmt; -use style::ComputedValues; +use style::{ColSpanUnsignedIntegerAttribute, ComputedValues}; use sync::Arc; /// A table formatting context. @@ -25,13 +25,17 @@ use sync::Arc; pub struct TableCellFlow { /// Data common to all block flows. pub block_flow: BlockFlow, + /// The column span of this cell. + pub column_span: u32, } impl TableCellFlow { pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment) -> TableCellFlow { TableCellFlow { - block_flow: BlockFlow::from_node_and_fragment(node, fragment) + block_flow: BlockFlow::from_node_and_fragment(node, fragment), + column_span: node.get_unsigned_integer_attribute(ColSpanUnsignedIntegerAttribute) + .unwrap_or(1), } } diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index 3489cb9c6ff..e50f5b2f33e 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -41,7 +41,7 @@ pub struct TableRowFlow { #[deriving(Encodable)] pub struct CellIntrinsicInlineSize { /// Inline sizes that this cell contributes to the column. - pub column_size: ColumnInlineSize, + pub column_size: ColumnIntrinsicInlineSize, /// The column span of this cell. pub column_span: u32, } @@ -165,7 +165,7 @@ impl Flow for TableRowFlow { } fn column_intrinsic_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnIntrinsicInlineSize> { - &mut self.column_intrinsic_inline_sizes + panic!("can't call column_intrinsic_inline_sizes() on table row") } fn column_computed_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnComputedInlineSize> { @@ -193,9 +193,11 @@ impl Flow for TableRowFlow { let child_specified_inline_size; let child_column_span; { - let child_style = kid.as_table_cell().fragment().style(); - child_specified_inline_size = child_style.content_inline_size(); - child_column_span = child_style.get_table()._servo_column_span + let child_table_cell = kid.as_table_cell(); + child_specified_inline_size = child_table_cell.fragment() + .style() + .content_inline_size(); + child_column_span = child_table_cell.column_span } // Collect minimum and preferred inline-sizes of the cell for automatic table layout @@ -248,31 +250,36 @@ impl Flow for TableRowFlow { // Spread out the completed inline sizes among columns with spans > 1. let mut computed_inline_size_for_cells = Vec::new(); - let mut column_inline_size_iterator = self.column_inline_sizes.iter(); + let mut column_computed_inline_size_iterator = self.column_computed_inline_sizes.iter(); for cell_intrinsic_inline_size in self.cell_intrinsic_inline_sizes.iter() { - //(intrinsic_inline_size_for_column, computed_inline_size_for_column) in // Start with the computed inline size for the first column in the span. - let mut column_inline_size = match column_inline_size_iterator.next() { - Some(column_inline_size) => *column_inline_size, - None => { - // This could happen if there are too few cells in this row. Don't crash. - break - } - }; + let mut column_computed_inline_size = + match column_computed_inline_size_iterator.next() { + Some(column_computed_inline_size) => *column_computed_inline_size, + None => { + // We're in fixed layout mode and there are more cells in this row than + // columns we know about. According to CSS 2.1 § 17.5.2.1, the behavior is + // now undefined. So just use zero. + // + // FIXME(pcwalton): $10 says this isn't Web compatible. + ColumnComputedInlineSize { + size: Au(0), + } + } + }; // Add in computed inline sizes for any extra columns in the span. for _ in range(1, cell_intrinsic_inline_size.column_span) { - let extra_column_inline_size = match column_inline_size_iterator.next() { - Some(column_inline_size) => column_inline_size, - None => break, - }; - column_inline_size.minimum_length = column_inline_size.minimum_length + - extra_column_inline_size.minimum_length; - column_inline_size.preferred = column_inline_size.preferred + - extra_column_inline_size.preferred; + let extra_column_computed_inline_size = + match column_computed_inline_size_iterator.next() { + Some(column_computed_inline_size) => column_computed_inline_size, + None => break, + }; + column_computed_inline_size.size = column_computed_inline_size.size + + extra_column_computed_inline_size.size; } - computed_inline_size_for_cells.push(column_inline_size) + computed_inline_size_for_cells.push(column_computed_inline_size) } // Push those inline sizes down to the cells. diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs index dd5ca85465d..4f62cd10a75 100644 --- a/components/layout/table_rowgroup.rs +++ b/components/layout/table_rowgroup.rs @@ -6,13 +6,13 @@ #![deny(unsafe_blocks)] -use block::{BlockFlow, ISizeAndMarginsComputer}; +use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayNotCollapse}; use construct::FlowConstructor; use context::LayoutContext; -use flow::{mod, Flow, FlowClass, TableRowGroupFlowClass}; +use flow::{Flow, FlowClass, TableRowGroupFlowClass}; use fragment::{Fragment, FragmentBoundsIterator}; use layout_debug; -use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, TableFlow}; +use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable}; use wrapper::ThreadSafeLayoutNode; use servo_util::geometry::Au; diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index 271a6545d1d..0d785ce1ca3 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -31,7 +31,7 @@ use style::{ComputedValues, CSSFloat}; use style::computed_values::table_layout; use sync::Arc; -#[deriving(Encodable)] +#[deriving(Encodable, Show)] pub enum TableLayout { FixedLayout, AutoLayout diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 41c05e1646c..97aa8dd189a 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -36,6 +36,7 @@ use incremental::RestyleDamage; use util::{LayoutDataAccess, LayoutDataFlags, LayoutDataWrapper, OpaqueNodeMethods}; use util::{PrivateLayoutData}; +use cssparser::RGBA; use gfx::display_list::OpaqueNode; use script::dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementCast}; use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementCast, HTMLInputElementCast}; @@ -53,7 +54,7 @@ use script::dom::node::{HAS_CHANGED, IS_DIRTY, HAS_DIRTY_SIBLINGS, HAS_DIRTY_DES use script::dom::text::Text; use script::layout_interface::LayoutChan; use servo_msg::constellation_msg::{PipelineId, SubpageId}; -use servo_util::str::{LengthOrPercentageOrAuto, SimpleColor, is_whitespace}; +use servo_util::str::{LengthOrPercentageOrAuto, is_whitespace}; use std::kinds::marker::ContravariantLifetime; use std::mem; use string_cache::{Atom, Namespace}; @@ -613,7 +614,7 @@ impl<'le> TElementAttributes for LayoutElement<'le> { } } - fn get_simple_color_attribute(self, attribute: SimpleColorAttribute) -> Option<SimpleColor> { + fn get_simple_color_attribute(self, attribute: SimpleColorAttribute) -> Option<RGBA> { unsafe { self.element.get_simple_color_attribute_for_layout(attribute) } @@ -937,6 +938,18 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { } } + pub fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) + -> Option<u32> { + unsafe { + match ElementCast::to_js(self.get_jsmanaged()) { + Some(element) => { + (*element.unsafe_get()).get_unsigned_integer_attribute_for_layout(attribute) + } + None => panic!("not an element!") + } + } + } + /// Get the description of how to account for recent style changes. /// This is a simple bitfield and fine to copy by value. pub fn restyle_damage(self) -> RestyleDamage { diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index d5acb22ad7b..b877d022c2e 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -32,6 +32,7 @@ use dom::bindings::utils::{Reflectable, Reflector, WindowProxyHandler}; use dom::node::{Node, TrustedNodeAddress}; use collections::hash::{Hash, Hasher}; +use cssparser::RGBA; use geom::rect::Rect; use html5ever::tree_builder::QuirksMode; use hyper::header::Headers; @@ -48,7 +49,7 @@ use script_traits::UntrustedNodeAddress; use servo_msg::compositor_msg::ScriptListener; use servo_msg::constellation_msg::ConstellationChan; use servo_util::smallvec::{SmallVec1, SmallVec}; -use servo_util::str::{LengthOrPercentageOrAuto, SimpleColor}; +use servo_util::str::{LengthOrPercentageOrAuto}; use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::comm::{Receiver, Sender}; @@ -214,7 +215,7 @@ no_jsmanaged_fields!(LayoutChan) no_jsmanaged_fields!(WindowProxyHandler) no_jsmanaged_fields!(UntrustedNodeAddress) no_jsmanaged_fields!(LengthOrPercentageOrAuto) -no_jsmanaged_fields!(SimpleColor) +no_jsmanaged_fields!(RGBA) impl<'a> JSTraceable for &'a str { #[inline] diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 6795511a3d0..69846d40543 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -19,7 +19,8 @@ use dom::bindings::codegen::InheritTypes::{ElementCast, ElementDerived, EventTar use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLInputElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLTableElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLTableElementDerived, HTMLTableCellElementDerived}; -use dom::bindings::codegen::InheritTypes::{NodeCast}; +use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived}; +use dom::bindings::codegen::InheritTypes::{HTMLTableSectionElementDerived, NodeCast}; use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable}; use dom::bindings::js::{OptionalRootable, Root}; use dom::bindings::utils::{Reflectable, Reflector}; @@ -38,19 +39,22 @@ use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers}; use dom::htmlserializer::serialize; use dom::htmltableelement::{HTMLTableElement, HTMLTableElementHelpers}; use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementHelpers}; +use dom::htmltablerowelement::{HTMLTableRowElement, HTMLTableRowElementHelpers}; +use dom::htmltablesectionelement::{HTMLTableSectionElement, HTMLTableSectionElementHelpers}; 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::{mod, BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute}; -use style::{ColSpanUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute}; +use style::{mod, AuthorOrigin, BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute}; +use style::{ColSpanUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute, ParserContext}; use style::{SimpleColorAttribute, SizeIntegerAttribute, UnsignedIntegerAttribute}; -use style::{WidthLengthAttribute, matches, parse_selector_list_from_str}; +use style::{WidthLengthAttribute, matches}; use servo_util::namespace; -use servo_util::str::{DOMString, LengthOrPercentageOrAuto, SimpleColor}; +use servo_util::str::{DOMString, LengthOrPercentageOrAuto}; +use cssparser::RGBA; use std::ascii::AsciiExt; use std::cell::{Ref, RefMut}; use std::default::Default; @@ -210,7 +214,7 @@ pub trait RawLayoutElementHelpers { unsafe fn get_unsigned_integer_attribute_for_layout(&self, attribute: UnsignedIntegerAttribute) -> Option<u32>; unsafe fn get_simple_color_attribute_for_layout(&self, attribute: SimpleColorAttribute) - -> Option<SimpleColor>; + -> Option<RGBA>; 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>>; @@ -341,9 +345,6 @@ impl RawLayoutElementHelpers for Element { 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. @@ -355,7 +356,9 @@ impl RawLayoutElementHelpers for Element { let this: &HTMLTableCellElement = mem::transmute(self); this.get_colspan() } else { - panic!("I'm not a table cell!") + // Don't panic since `display` can cause this to be called on arbitrary + // elements. + None } } } @@ -364,7 +367,7 @@ impl RawLayoutElementHelpers for Element { #[inline] #[allow(unrooted_must_root)] unsafe fn get_simple_color_attribute_for_layout(&self, attribute: SimpleColorAttribute) - -> Option<SimpleColor> { + -> Option<RGBA> { match attribute { BgColorSimpleColorAttribute => { if self.is_htmlbodyelement() { @@ -376,8 +379,14 @@ impl RawLayoutElementHelpers for Element { } else if self.is_htmltablecellelement() { let this: &HTMLTableCellElement = mem::transmute(self); this.get_background_color() + } else if self.is_htmltablerowelement() { + let this: &HTMLTableRowElement = mem::transmute(self); + this.get_background_color() + } else if self.is_htmltablesectionelement() { + let this: &HTMLTableSectionElement = mem::transmute(self); + this.get_background_color() } else { - panic!("I'm not a body, table, or table cell!") + None } } } @@ -1011,7 +1020,10 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // http://dom.spec.whatwg.org/#dom-element-matches fn Matches(self, selectors: DOMString) -> Fallible<bool> { - match parse_selector_list_from_str(selectors.as_slice()) { + let parser_context = ParserContext { + origin: AuthorOrigin, + }; + match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) { Err(()) => Err(Syntax), Ok(ref selectors) => { let root: JSRef<Node> = NodeCast::from_ref(self); diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index ebfe1e8025a..917b02913a7 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -17,13 +17,14 @@ use dom::htmlelement::HTMLElement; use dom::node::{Node, ElementNodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; -use servo_util::str::{mod, DOMString, SimpleColor}; +use cssparser::RGBA; +use servo_util::str::{mod, DOMString}; use std::cell::Cell; #[dom_struct] pub struct HTMLBodyElement { htmlelement: HTMLElement, - background_color: Cell<Option<SimpleColor>>, + background_color: Cell<Option<RGBA>>, } impl HTMLBodyElementDerived for EventTarget { @@ -65,11 +66,11 @@ impl<'a> HTMLBodyElementMethods for JSRef<'a, HTMLBodyElement> { } pub trait HTMLBodyElementHelpers { - fn get_background_color(&self) -> Option<SimpleColor>; + fn get_background_color(&self) -> Option<RGBA>; } impl HTMLBodyElementHelpers for HTMLBodyElement { - fn get_background_color(&self) -> Option<SimpleColor> { + fn get_background_color(&self) -> Option<RGBA> { self.background_color.get() } } diff --git a/components/script/dom/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs index 81a6ba3f9f0..9ca84b0e70f 100644 --- a/components/script/dom/htmltablecellelement.rs +++ b/components/script/dom/htmltablecellelement.rs @@ -14,14 +14,14 @@ use dom::htmlelement::HTMLElement; use dom::node::ElementNodeTypeId; use dom::virtualmethods::VirtualMethods; -use servo_util::str::{mod, AutoLpa, DOMString, LengthOrPercentageOrAuto, SimpleColor}; +use cssparser::RGBA; +use servo_util::str::{mod, AutoLpa, DOMString, LengthOrPercentageOrAuto}; use std::cell::Cell; #[dom_struct] pub struct HTMLTableCellElement { htmlelement: HTMLElement, - background_color: Cell<Option<SimpleColor>>, - border: Cell<Option<u32>>, + background_color: Cell<Option<RGBA>>, colspan: Cell<Option<u32>>, width: Cell<LengthOrPercentageOrAuto>, } @@ -45,7 +45,6 @@ impl HTMLTableCellElement { HTMLTableCellElement { htmlelement: HTMLElement::new_inherited(type_id, tag_name, prefix, document), background_color: Cell::new(None), - border: Cell::new(None), colspan: Cell::new(None), width: Cell::new(AutoLpa), } @@ -58,21 +57,16 @@ impl HTMLTableCellElement { } pub trait HTMLTableCellElementHelpers { - fn get_background_color(&self) -> Option<SimpleColor>; - fn get_border(&self) -> Option<u32>; + fn get_background_color(&self) -> Option<RGBA>; fn get_colspan(&self) -> Option<u32>; fn get_width(&self) -> LengthOrPercentageOrAuto; } impl HTMLTableCellElementHelpers for HTMLTableCellElement { - fn get_background_color(&self) -> Option<SimpleColor> { + fn get_background_color(&self) -> Option<RGBA> { self.background_color.get() } - fn get_border(&self) -> Option<u32> { - self.border.get() - } - fn get_colspan(&self) -> Option<u32> { self.colspan.get() } @@ -98,12 +92,6 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableCellElement> { &atom!("bgcolor") => { self.background_color.set(str::parse_legacy_color(attr.value().as_slice()).ok()) } - &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!("colspan") => { self.colspan.set(str::parse_unsigned_integer(attr.value().as_slice().chars())); } @@ -120,7 +108,6 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableCellElement> { match attr.local_name() { &atom!("bgcolor") => self.background_color.set(None), - &atom!("border") => self.border.set(None), &atom!("colspan") => self.colspan.set(None), &atom!("width") => self.width.set(AutoLpa), _ => () diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs index d88017fe151..d2c9e723b78 100644 --- a/components/script/dom/htmltableelement.rs +++ b/components/script/dom/htmltableelement.rs @@ -18,13 +18,14 @@ use dom::htmltablecaptionelement::HTMLTableCaptionElement; use dom::node::{Node, NodeHelpers, ElementNodeTypeId}; use dom::virtualmethods::VirtualMethods; -use servo_util::str::{mod, AutoLpa, DOMString, LengthOrPercentageOrAuto, SimpleColor}; +use cssparser::RGBA; +use servo_util::str::{mod, AutoLpa, DOMString, LengthOrPercentageOrAuto}; use std::cell::Cell; #[dom_struct] pub struct HTMLTableElement { htmlelement: HTMLElement, - background_color: Cell<Option<SimpleColor>>, + background_color: Cell<Option<RGBA>>, border: Cell<Option<u32>>, width: Cell<LengthOrPercentageOrAuto>, } @@ -95,13 +96,13 @@ impl<'a> HTMLTableElementMethods for JSRef<'a, HTMLTableElement> { } pub trait HTMLTableElementHelpers { - fn get_background_color(&self) -> Option<SimpleColor>; + fn get_background_color(&self) -> Option<RGBA>; fn get_border(&self) -> Option<u32>; fn get_width(&self) -> LengthOrPercentageOrAuto; } impl HTMLTableElementHelpers for HTMLTableElement { - fn get_background_color(&self) -> Option<SimpleColor> { + fn get_background_color(&self) -> Option<RGBA> { self.background_color.get() } diff --git a/components/script/dom/htmltablerowelement.rs b/components/script/dom/htmltablerowelement.rs index 3edf4a0e64f..500c7d74472 100644 --- a/components/script/dom/htmltablerowelement.rs +++ b/components/script/dom/htmltablerowelement.rs @@ -2,8 +2,9 @@ * 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, AttrHelpers}; use dom::bindings::codegen::Bindings::HTMLTableRowElementBinding; -use dom::bindings::codegen::InheritTypes::HTMLTableRowElementDerived; +use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableRowElementDerived}; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::Document; @@ -11,11 +12,16 @@ use dom::element::HTMLTableRowElementTypeId; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::node::{Node, ElementNodeTypeId}; -use servo_util::str::DOMString; +use dom::virtualmethods::VirtualMethods; + +use cssparser::RGBA; +use servo_util::str::{mod, DOMString}; +use std::cell::Cell; #[dom_struct] pub struct HTMLTableRowElement { htmlelement: HTMLElement, + background_color: Cell<Option<RGBA>>, } impl HTMLTableRowElementDerived for EventTarget { @@ -25,9 +31,14 @@ impl HTMLTableRowElementDerived for EventTarget { } impl HTMLTableRowElement { - fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTableRowElement { + fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) + -> HTMLTableRowElement { HTMLTableRowElement { - htmlelement: HTMLElement::new_inherited(HTMLTableRowElementTypeId, localName, prefix, document) + htmlelement: HTMLElement::new_inherited(HTMLTableRowElementTypeId, + localName, + prefix, + document), + background_color: Cell::new(None), } } @@ -45,3 +56,47 @@ impl Reflectable for HTMLTableRowElement { self.htmlelement.reflector() } } + +pub trait HTMLTableRowElementHelpers { + fn get_background_color(&self) -> Option<RGBA>; +} + +impl HTMLTableRowElementHelpers for HTMLTableRowElement { + fn get_background_color(&self) -> Option<RGBA> { + self.background_color.get() + } +} + +impl<'a> VirtualMethods for JSRef<'a, HTMLTableRowElement> { + 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!("bgcolor") => { + self.background_color.set(str::parse_legacy_color(attr.value().as_slice()).ok()) + } + _ => {} + } + } + + 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!("bgcolor") => self.background_color.set(None), + _ => {} + } + } +} + diff --git a/components/script/dom/htmltablesectionelement.rs b/components/script/dom/htmltablesectionelement.rs index d10e4b82b44..b191e21bde0 100644 --- a/components/script/dom/htmltablesectionelement.rs +++ b/components/script/dom/htmltablesectionelement.rs @@ -2,8 +2,9 @@ * 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, AttrHelpers}; use dom::bindings::codegen::Bindings::HTMLTableSectionElementBinding; -use dom::bindings::codegen::InheritTypes::HTMLTableSectionElementDerived; +use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableSectionElementDerived}; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::Document; @@ -11,11 +12,16 @@ use dom::element::HTMLTableSectionElementTypeId; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::node::{Node, ElementNodeTypeId}; -use servo_util::str::DOMString; +use dom::virtualmethods::VirtualMethods; + +use cssparser::RGBA; +use servo_util::str::{mod, DOMString}; +use std::cell::Cell; #[dom_struct] pub struct HTMLTableSectionElement { htmlelement: HTMLElement, + background_color: Cell<Option<RGBA>>, } impl HTMLTableSectionElementDerived for EventTarget { @@ -25,14 +31,20 @@ impl HTMLTableSectionElementDerived for EventTarget { } impl HTMLTableSectionElement { - fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTableSectionElement { + fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) + -> HTMLTableSectionElement { HTMLTableSectionElement { - htmlelement: HTMLElement::new_inherited(HTMLTableSectionElementTypeId, localName, prefix, document) + htmlelement: HTMLElement::new_inherited(HTMLTableSectionElementTypeId, + localName, + prefix, + document), + background_color: Cell::new(None), } } #[allow(unrooted_must_root)] - pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLTableSectionElement> { + pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) + -> Temporary<HTMLTableSectionElement> { let element = HTMLTableSectionElement::new_inherited(localName, prefix, document); Node::reflect_node(box element, document, HTMLTableSectionElementBinding::Wrap) } @@ -43,3 +55,47 @@ impl Reflectable for HTMLTableSectionElement { self.htmlelement.reflector() } } + +pub trait HTMLTableSectionElementHelpers { + fn get_background_color(&self) -> Option<RGBA>; +} + +impl HTMLTableSectionElementHelpers for HTMLTableSectionElement { + fn get_background_color(&self) -> Option<RGBA> { + self.background_color.get() + } +} + +impl<'a> VirtualMethods for JSRef<'a, HTMLTableSectionElement> { + 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!("bgcolor") => { + self.background_color.set(str::parse_legacy_color(attr.value().as_slice()).ok()) + } + _ => {} + } + } + + 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!("bgcolor") => self.background_color.set(None), + _ => {} + } + } +} + diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index ecfccf8aefc..0871a266df3 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -50,7 +50,7 @@ use devtools_traits::NodeInfo; use script_traits::UntrustedNodeAddress; use servo_util::geometry::Au; use servo_util::str::{DOMString, null_str_as_empty}; -use style::{parse_selector_list_from_str, matches, SelectorList}; +use style::{matches, AuthorOrigin, ParserContext, SelectorList}; use js::jsapi::{JSContext, JSObject, JSTracer, JSRuntime}; use js::jsfriendapi; @@ -60,8 +60,7 @@ use std::cell::{Cell, RefCell, Ref, RefMut}; use std::default::Default; use std::iter::{FilterMap, Peekable}; use std::mem; -use style; -use style::ComputedValues; +use style::{mod, ComputedValues}; use sync::Arc; use uuid; use string_cache::QualName; @@ -741,7 +740,10 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { // http://dom.spec.whatwg.org/#dom-parentnode-queryselector fn query_selector(self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> { // Step 1. - match parse_selector_list_from_str(selectors.as_slice()) { + let parser_context = ParserContext { + origin: AuthorOrigin, + }; + match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) { // Step 2. Err(()) => return Err(Syntax), // Step 3. @@ -758,11 +760,15 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { /// Get an iterator over all nodes which match a set of selectors /// Be careful not to do anything which may manipulate the DOM tree whilst iterating, otherwise /// the iterator may be invalidated - unsafe fn query_selector_iter(self, selectors: DOMString) -> Fallible<QuerySelectorIterator<'a>> { + unsafe fn query_selector_iter(self, selectors: DOMString) + -> Fallible<QuerySelectorIterator<'a>> { // Step 1. let nodes; let root = self.ancestors().last().unwrap_or(self.clone()); - match parse_selector_list_from_str(selectors.as_slice()) { + let parser_context = ParserContext { + origin: AuthorOrigin, + }; + match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) { // Step 2. Err(()) => return Err(Syntax), // Step 3. diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index 2f75127c513..94a74124eca 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -24,6 +24,8 @@ 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::HTMLTableRowElementCast; +use dom::bindings::codegen::InheritTypes::HTMLTableSectionElementCast; use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast; use dom::bindings::codegen::InheritTypes::HTMLTitleElementCast; use dom::bindings::js::JSRef; @@ -49,6 +51,8 @@ use dom::element::HTMLStyleElementTypeId; use dom::element::HTMLTableDataCellElementTypeId; use dom::element::HTMLTableElementTypeId; use dom::element::HTMLTableHeaderCellElementTypeId; +use dom::element::HTMLTableRowElementTypeId; +use dom::element::HTMLTableSectionElementTypeId; use dom::element::HTMLTextAreaElementTypeId; use dom::element::HTMLTitleElementTypeId; use dom::event::Event; @@ -71,6 +75,8 @@ use dom::htmlselectelement::HTMLSelectElement; use dom::htmlstyleelement::HTMLStyleElement; use dom::htmltableelement::HTMLTableElement; use dom::htmltablecellelement::HTMLTableCellElement; +use dom::htmltablerowelement::HTMLTableRowElement; +use dom::htmltablesectionelement::HTMLTableSectionElement; use dom::htmltextareaelement::HTMLTextAreaElement; use dom::htmltitleelement::HTMLTitleElement; use dom::node::{Node, NodeHelpers, ElementNodeTypeId, CloneChildrenFlag}; @@ -236,7 +242,18 @@ pub fn vtable_for<'a>(node: &'a JSRef<'a, Node>) -> &'a VirtualMethods + 'a { } ElementNodeTypeId(HTMLTableDataCellElementTypeId) | ElementNodeTypeId(HTMLTableHeaderCellElementTypeId) => { - let element: &'a JSRef<'a, HTMLTableCellElement> = HTMLTableCellElementCast::to_borrowed_ref(node).unwrap(); + let element: &'a JSRef<'a, HTMLTableCellElement> = + HTMLTableCellElementCast::to_borrowed_ref(node).unwrap(); + element as &'a VirtualMethods + 'a + } + ElementNodeTypeId(HTMLTableRowElementTypeId) => { + let element: &'a JSRef<'a, HTMLTableRowElement> = + HTMLTableRowElementCast::to_borrowed_ref(node).unwrap(); + element as &'a VirtualMethods + 'a + } + ElementNodeTypeId(HTMLTableSectionElementTypeId) => { + let element: &'a JSRef<'a, HTMLTableSectionElement> = + HTMLTableSectionElementCast::to_borrowed_ref(node).unwrap(); element as &'a VirtualMethods + 'a } ElementNodeTypeId(HTMLTextAreaElementTypeId) => { diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 6c4b2708b9e..edede8178fc 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -410,6 +410,7 @@ dependencies = [ name = "layout" version = "0.0.1" dependencies = [ + "cssparser 0.1.0 (git+https://github.com/servo/rust-cssparser)", "encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)", "geom 0.1.0 (git+https://github.com/servo/rust-geom)", "gfx 0.0.1", diff --git a/components/style/legacy.rs b/components/style/legacy.rs index 81c83a02fc4..6b22d70ca76 100644 --- a/components/style/legacy.rs +++ b/components/style/legacy.rs @@ -8,11 +8,10 @@ use node::{TElement, TElementAttributes, TNode}; use properties::{BackgroundColorDeclaration, BorderBottomWidthDeclaration}; use properties::{BorderLeftWidthDeclaration, BorderRightWidthDeclaration}; -use properties::{BorderTopWidthDeclaration, ServoColumnSpanDeclaration, SpecifiedValue}; -use properties::{WidthDeclaration, specified}; +use properties::{BorderTopWidthDeclaration, SpecifiedValue, WidthDeclaration, specified}; use selector_matching::{DeclarationBlock, Stylist}; -use cssparser::{RGBA, RGBAColor}; +use cssparser::RGBAColor; use servo_util::geometry::Au; use servo_util::smallvec::VecLike; use servo_util::str::{AutoLpa, LengthLpa, PercentageLpa}; @@ -114,14 +113,6 @@ impl PresentationalHintSynthesis for Stylist { *shareable = false } } - match element.get_unsigned_integer_attribute(ColSpanUnsignedIntegerAttribute) { - None => {} - Some(value) => { - matching_rules_list.vec_push(DeclarationBlock::from_declaration( - ServoColumnSpanDeclaration(SpecifiedValue(value)))); - *shareable = false - } - } self.synthesize_presentational_hint_for_legacy_background_color_attribute( element, matching_rules_list, @@ -141,7 +132,8 @@ impl PresentationalHintSynthesis for Stylist { matching_rules_list, shareable); } - name if *name == atom!("body") => { + name if *name == atom!("body") || *name == atom!("tr") || *name == atom!("thead") || + *name == atom!("tbody") || *name == atom!("tfoot") => { self.synthesize_presentational_hint_for_legacy_background_color_attribute( element, matching_rules_list, @@ -187,12 +179,7 @@ impl PresentationalHintSynthesis for Stylist { None => {} Some(color) => { matching_rules_list.vec_push(DeclarationBlock::from_declaration( - BackgroundColorDeclaration(SpecifiedValue(RGBAColor(RGBA { - red: color.red as f32 / 255.0, - green: color.green as f32 / 255.0, - blue: color.blue as f32 / 255.0, - alpha: 1.0, - }))))); + BackgroundColorDeclaration(SpecifiedValue(RGBAColor(color))))); *shareable = false } } diff --git a/components/style/lib.rs b/components/style/lib.rs index 2c88995d521..d28ba62b112 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -50,9 +50,9 @@ pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult}; pub use properties::{Angle, AngleOrCorner, AngleAoc, CornerAoc}; 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::{PseudoElement, Before, After, ParserContext, SelectorList}; pub use selectors::{AttrSelector, NamespaceConstraint, SpecificNamespace, AnyNamespace}; -pub use selectors::{SimpleSelector, LocalNameSelector}; +pub use selectors::{SimpleSelector, LocalNameSelector, parse_selector_list_from_str}; pub use cssparser::{Color, RGBA}; pub use legacy::{BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute}; pub use legacy::{ColSpanUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute}; diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs index 33d5203064e..f014be0114d 100644 --- a/components/style/media_queries.rs +++ b/components/style/media_queries.rs @@ -8,12 +8,14 @@ use cssparser::ast::*; use errors::{ErrorLoggerIterator, log_css_error}; use geom::size::TypedSize2D; -use stylesheets::{CSSRule, CSSMediaRule, parse_style_rule, parse_nested_at_rule}; +use selectors::ParserContext; +use stylesheets::{CSSRule, CSSMediaRule}; use namespaces::NamespaceMap; use parsing_utils::{BufferedIter, ParserIter}; use properties::common_types::*; use properties::longhands; use servo_util::geometry::ViewportPx; +use stylesheets; use url::Url; pub struct MediaRule { @@ -95,8 +97,11 @@ impl Device { } } -pub fn parse_media_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, - namespaces: &NamespaceMap, base_url: &Url) { +pub fn parse_media_rule(context: &ParserContext, + rule: AtRule, + parent_rules: &mut Vec<CSSRule>, + namespaces: &NamespaceMap, + base_url: &Url) { let media_queries = parse_media_query_list(rule.prelude.as_slice()); let block = match rule.block { Some(block) => block, @@ -108,9 +113,17 @@ pub fn parse_media_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, let mut rules = vec!(); for rule in ErrorLoggerIterator(parse_rule_list(block.into_iter())) { match rule { - QualifiedRule_(rule) => parse_style_rule(rule, &mut rules, namespaces, base_url), - AtRule_(rule) => parse_nested_at_rule( - rule.name.as_slice().to_ascii_lower().as_slice(), rule, &mut rules, namespaces, base_url), + QualifiedRule_(rule) => { + stylesheets::parse_style_rule(context, rule, &mut rules, namespaces, base_url) + } + AtRule_(rule) => { + stylesheets::parse_nested_at_rule(context, + rule.name.as_slice().to_ascii_lower().as_slice(), + rule, + &mut rules, + namespaces, + base_url) + } } } parent_rules.push(CSSMediaRule(MediaRule { diff --git a/components/style/node.rs b/components/style/node.rs index 4866f27e6c5..a1c9a8071c4 100644 --- a/components/style/node.rs +++ b/components/style/node.rs @@ -5,9 +5,10 @@ //! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and //! style. +use cssparser::RGBA; use legacy::{IntegerAttribute, LengthAttribute, SimpleColorAttribute, UnsignedIntegerAttribute}; use selectors::AttrSelector; -use servo_util::str::{LengthOrPercentageOrAuto, SimpleColor}; +use servo_util::str::LengthOrPercentageOrAuto; use string_cache::{Atom, Namespace}; pub trait TNode<'a, E: TElement<'a>> : Clone + Copy { @@ -60,5 +61,5 @@ 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>; - fn get_simple_color_attribute(self, attribute: SimpleColorAttribute) -> Option<SimpleColor>; + fn get_simple_color_attribute(self, attribute: SimpleColorAttribute) -> Option<RGBA>; } diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako index f199fa62fb1..2107ac86c7b 100644 --- a/components/style/properties/mod.rs.mako +++ b/components/style/properties/mod.rs.mako @@ -1316,34 +1316,6 @@ pub mod longhands { ${single_keyword("table-layout", "auto fixed")} - <%self:single_component_value name="-servo-column-span"> - // The handling of this property is not well-specified by INTRINSIC, but its presence is - // assumed. HTML5 14.3.9 specifies that the `colspan` attribute is to be a nonnegative - // integer. - pub use super::computed_as_specified as to_computed_value; - pub mod computed_value { - pub type T = u32; - } - pub type SpecifiedValue = computed_value::T; - - #[inline] - pub fn get_initial_value() -> computed_value::T { - 1 - } - - pub fn from_component_value(input: &ComponentValue, _: &Url) -> Result<SpecifiedValue,()> { - match input { - &Number(ref value) => { - match value.int_value { - None => Err(()), - Some(n) => Ok(n as SpecifiedValue), - } - } - _ => Err(()), - } - } - </%self:single_component_value> - // CSS 2.1, Section 18 - User interface diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 1e1acaf918a..5482745721f 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -20,9 +20,22 @@ use legacy::PresentationalHintSynthesis; use media_queries::Device; use node::{TElement, TElementAttributes, TNode}; use properties::{PropertyDeclaration, PropertyDeclarationBlock}; -use selectors::*; +use selectors::{After, AnyLink, AttrDashMatch, AttrEqual}; +use selectors::{AttrExists, AttrIncludes, AttrPrefixMatch}; +use selectors::{AttrSubstringMatch, AttrSuffixMatch, Before, CaseInsensitive, CaseSensitive}; +use selectors::{Checked, Child, ClassSelector}; +use selectors::{CompoundSelector, Descendant, Disabled, Enabled, FirstChild, FirstOfType}; +use selectors::{Hover, IDSelector, LastChild, LastOfType}; +use selectors::{LaterSibling, LocalName, LocalNameSelector}; +use selectors::{NamespaceSelector, Link, Negation}; +use selectors::{NextSibling, NthChild}; +use selectors::{NthLastChild, NthLastOfType}; +use selectors::{NthOfType, OnlyChild, OnlyOfType, PseudoElement, Root}; +use selectors::{SelectorList, ServoNonzeroBorder, SimpleSelector, Visited}; +use selectors::{get_selector_list_selectors}; use stylesheets::{Stylesheet, iter_stylesheet_media_rules, iter_stylesheet_style_rules}; +#[deriving(Clone, PartialEq)] pub enum StylesheetOrigin { UserAgentOrigin, AuthorOrigin, @@ -1166,12 +1179,16 @@ mod tests { /// Each sublist of the result contains the Rules for one StyleRule. fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> { use namespaces::NamespaceMap; - use selectors::parse_selector_list; + use selectors::{ParserContext, parse_selector_list}; + use selector_matching::AuthorOrigin; use cssparser::tokenize; let namespaces = NamespaceMap::new(); css_selectors.iter().enumerate().map(|(i, selectors)| { - parse_selector_list(tokenize(*selectors).map(|(c, _)| c), &namespaces) + let context = ParserContext { + origin: AuthorOrigin, + }; + parse_selector_list(&context, tokenize(*selectors).map(|(c, _)| c), &namespaces) .unwrap().into_iter().map(|s| { Rule { selector: s.compound_selectors.clone(), diff --git a/components/style/selectors.rs b/components/style/selectors.rs index 9cb3f240dd4..1d72a530383 100644 --- a/components/style/selectors.rs +++ b/components/style/selectors.rs @@ -9,10 +9,16 @@ use sync::Arc; use cssparser::ast::*; use cssparser::{tokenize, parse_nth}; +use selector_matching::{StylesheetOrigin, UserAgentOrigin}; use string_cache::{Atom, Namespace}; use namespaces::NamespaceMap; +/// Ambient data used by the parser. +pub struct ParserContext { + /// The origin of this stylesheet. + pub origin: StylesheetOrigin, +} #[deriving(PartialEq, Clone)] pub struct Selector { @@ -112,12 +118,6 @@ pub enum NamespaceConstraint { } -pub fn parse_selector_list_from_str(input: &str) -> Result<SelectorList, ()> { - let namespaces = NamespaceMap::new(); - let iter = tokenize(input).map(|(token, _)| token); - parse_selector_list(iter, &namespaces).map(|s| SelectorList { selectors: s }) -} - /// Re-exported to script, but opaque. pub struct SelectorList { selectors: Vec<Selector> @@ -128,70 +128,9 @@ pub fn get_selector_list_selectors<'a>(selector_list: &'a SelectorList) -> &'a [ selector_list.selectors.as_slice() } -/// Parse a comma-separated list of Selectors. -/// aka Selector Group in http://www.w3.org/TR/css3-selectors/#grouping -/// -/// Return the Selectors or None if there is an invalid selector. -pub fn parse_selector_list<I: Iterator<ComponentValue>>( - iter: I, namespaces: &NamespaceMap) - -> Result<Vec<Selector>, ()> { - let iter = &mut iter.peekable(); - let mut results = vec![try!(parse_selector(iter, namespaces))]; - - loop { - skip_whitespace(iter); - match iter.peek() { - None => break, // EOF - Some(&Comma) => { - iter.next(); - } - _ => return Err(()), - } - results.push(try!(parse_selector(iter, namespaces))); - } - Ok(results) -} - type Iter<I> = iter::Peekable<ComponentValue, I>; -/// Build up a Selector. -/// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ; -/// -/// `Err` means invalid selector. -fn parse_selector<I: Iterator<ComponentValue>>( - iter: &mut Iter<I>, namespaces: &NamespaceMap) - -> Result<Selector, ()> { - let (first, mut pseudo_element) = try!(parse_simple_selectors(iter, namespaces)); - let mut compound = CompoundSelector{ simple_selectors: first, next: None }; - - while pseudo_element.is_none() { - let any_whitespace = skip_whitespace(iter); - let combinator = match iter.peek() { - None => break, // EOF - Some(&Comma) => break, - Some(&Delim('>')) => { iter.next(); Child }, - Some(&Delim('+')) => { iter.next(); NextSibling }, - Some(&Delim('~')) => { iter.next(); LaterSibling }, - Some(_) => { - if any_whitespace { Descendant } - else { return Err(()) } - } - }; - let (simple_selectors, pseudo) = try!(parse_simple_selectors(iter, namespaces)); - compound = CompoundSelector { - simple_selectors: simple_selectors, - next: Some((box compound, combinator)) - }; - pseudo_element = pseudo; - } - Ok(Selector { - specificity: compute_specificity(&compound, &pseudo_element), - compound_selectors: Arc::new(compound), - pseudo_element: pseudo_element, - }) -} - fn compute_specificity(mut selector: &CompoundSelector, pseudo_element: &Option<PseudoElement>) -> u32 { @@ -248,32 +187,6 @@ fn compute_specificity(mut selector: &CompoundSelector, } -/// simple_selector_sequence -/// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]* -/// | [ HASH | class | attrib | pseudo | negation ]+ -/// -/// `Err(())` means invalid selector -fn parse_simple_selectors<I: Iterator<ComponentValue>>( - iter: &mut Iter<I>, namespaces: &NamespaceMap) - -> Result<(Vec<SimpleSelector>, Option<PseudoElement>), ()> { - let mut empty = true; - let mut simple_selectors = match try!(parse_type_selector(iter, namespaces)) { - None => vec![], - Some(s) => { empty = false; s } - }; - - let mut pseudo_element = None; - loop { - match try!(parse_one_simple_selector(iter, namespaces, /* inside_negation = */ false)) { - None => break, - Some(SimpleSelectorResult(s)) => { simple_selectors.push(s); empty = false }, - Some(PseudoElementResult(p)) => { pseudo_element = Some(p); empty = false; break }, - } - } - if empty { Err(()) } // An empty selector is invalid - else { Ok((simple_selectors, pseudo_element)) } -} - /// * `Err(())`: Invalid selector, abort /// * `Ok(None)`: Not a type selector, could be something else. `iter` was not consumed. @@ -310,67 +223,6 @@ enum SimpleSelectorParseResult { PseudoElementResult(PseudoElement), } -/// Parse a simple selector other than a type selector. -/// -/// * `Err(())`: Invalid selector, abort -/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed. -/// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element -fn parse_one_simple_selector<I: Iterator<ComponentValue>>( - iter: &mut Iter<I>, namespaces: &NamespaceMap, inside_negation: bool) - -> Result<Option<SimpleSelectorParseResult>, ()> { - match iter.peek() { - Some(&IDHash(_)) => match iter.next() { - Some(IDHash(id)) => Ok(Some(SimpleSelectorResult( - IDSelector(Atom::from_slice(id.as_slice()))))), - _ => panic!("Implementation error, this should not happen."), - }, - Some(&Delim('.')) => { - iter.next(); - match iter.next() { - Some(Ident(class)) => Ok(Some(SimpleSelectorResult( - ClassSelector(Atom::from_slice(class.as_slice()))))), - _ => Err(()), - } - } - Some(&SquareBracketBlock(_)) => match iter.next() { - Some(SquareBracketBlock(content)) - => Ok(Some(SimpleSelectorResult(try!(parse_attribute_selector(content, namespaces))))), - _ => panic!("Implementation error, this should not happen."), - }, - Some(&Colon) => { - iter.next(); - match iter.next() { - Some(Ident(name)) => match parse_simple_pseudo_class(name.as_slice()) { - Err(()) => { - match name.as_slice().to_ascii_lower().as_slice() { - // Supported CSS 2.1 pseudo-elements only. - // ** Do not add to this list! ** - "before" => Ok(Some(PseudoElementResult(Before))), - "after" => Ok(Some(PseudoElementResult(After))), -// "first-line" => PseudoElementResult(FirstLine), -// "first-letter" => PseudoElementResult(FirstLetter), - _ => Err(()) - } - }, - Ok(result) => Ok(Some(SimpleSelectorResult(result))), - }, - Some(Function(name, arguments)) - => Ok(Some(SimpleSelectorResult(try!(parse_functional_pseudo_class( - name, arguments, namespaces, inside_negation))))), - Some(Colon) => { - match iter.next() { - Some(Ident(name)) - => Ok(Some(PseudoElementResult(try!(parse_pseudo_element(name))))), - _ => Err(()), - } - } - _ => Err(()), - } - } - _ => Ok(None), - } -} - /// * `Err(())`: Invalid selector, abort /// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed. @@ -490,8 +342,224 @@ fn parse_attribute_flags<I: Iterator<ComponentValue>>(iter: &mut Iter<I>) } } +pub fn parse_selector_list_from_str(context: &ParserContext, input: &str) + -> Result<SelectorList,()> { + let namespaces = NamespaceMap::new(); + let iter = tokenize(input).map(|(token, _)| token); + parse_selector_list(context, iter, &namespaces).map(|s| SelectorList { selectors: s }) +} + +/// Parse a comma-separated list of Selectors. +/// aka Selector Group in http://www.w3.org/TR/css3-selectors/#grouping +/// +/// Return the Selectors or None if there is an invalid selector. +pub fn parse_selector_list<I>(context: &ParserContext, iter: I, namespaces: &NamespaceMap) + -> Result<Vec<Selector>,()> + where I: Iterator<ComponentValue> { + let iter = &mut iter.peekable(); + let mut results = vec![try!(parse_selector(context, iter, namespaces))]; + + loop { + skip_whitespace(iter); + match iter.peek() { + None => break, // EOF + Some(&Comma) => { + iter.next(); + } + _ => return Err(()), + } + results.push(try!(parse_selector(context, iter, namespaces))); + } + Ok(results) +} +/// Build up a Selector. +/// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ; +/// +/// `Err` means invalid selector. +fn parse_selector<I>(context: &ParserContext, iter: &mut Iter<I>, namespaces: &NamespaceMap) + -> Result<Selector,()> + where I: Iterator<ComponentValue> { + let (first, mut pseudo_element) = try!(parse_simple_selectors(context, iter, namespaces)); + let mut compound = CompoundSelector{ simple_selectors: first, next: None }; + + while pseudo_element.is_none() { + let any_whitespace = skip_whitespace(iter); + let combinator = match iter.peek() { + None => break, // EOF + Some(&Comma) => break, + Some(&Delim('>')) => { iter.next(); Child }, + Some(&Delim('+')) => { iter.next(); NextSibling }, + Some(&Delim('~')) => { iter.next(); LaterSibling }, + Some(_) => { + if any_whitespace { Descendant } + else { return Err(()) } + } + }; + let (simple_selectors, pseudo) = try!(parse_simple_selectors(context, iter, namespaces)); + compound = CompoundSelector { + simple_selectors: simple_selectors, + next: Some((box compound, combinator)) + }; + pseudo_element = pseudo; + } + Ok(Selector { + specificity: compute_specificity(&compound, &pseudo_element), + compound_selectors: Arc::new(compound), + pseudo_element: pseudo_element, + }) +} + +/// Level 3: Parse **one** simple_selector +fn parse_negation(context: &ParserContext, + arguments: Vec<ComponentValue>, + namespaces: &NamespaceMap) + -> Result<SimpleSelector,()> { + let iter = &mut arguments.into_iter().peekable(); + match try!(parse_type_selector(iter, namespaces)) { + Some(type_selector) => Ok(Negation(type_selector)), + None => { + match try!(parse_one_simple_selector(context, + iter, + namespaces, + /* inside_negation = */ true)) { + Some(SimpleSelectorResult(simple_selector)) => { + Ok(Negation(vec![simple_selector])) + } + _ => Err(()) + } + }, + } +} + +/// simple_selector_sequence +/// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]* +/// | [ HASH | class | attrib | pseudo | negation ]+ +/// +/// `Err(())` means invalid selector +fn parse_simple_selectors<I>(context: &ParserContext, + iter: &mut Iter<I>, + namespaces: &NamespaceMap) + -> Result<(Vec<SimpleSelector>, Option<PseudoElement>),()> + where I: Iterator<ComponentValue> { + let mut empty = true; + let mut simple_selectors = match try!(parse_type_selector(iter, namespaces)) { + None => vec![], + Some(s) => { empty = false; s } + }; + + let mut pseudo_element = None; + loop { + match try!(parse_one_simple_selector(context, + iter, + namespaces, + /* inside_negation = */ false)) { + None => break, + Some(SimpleSelectorResult(s)) => { simple_selectors.push(s); empty = false }, + Some(PseudoElementResult(p)) => { pseudo_element = Some(p); empty = false; break }, + } + } + if empty { + // An empty selector is invalid. + Err(()) + } else { + Ok((simple_selectors, pseudo_element)) + } +} + +fn parse_functional_pseudo_class(context: &ParserContext, + name: String, + arguments: Vec<ComponentValue>, + namespaces: &NamespaceMap, + inside_negation: bool) + -> Result<SimpleSelector,()> { + match name.as_slice().to_ascii_lower().as_slice() { +// "lang" => parse_lang(arguments), + "nth-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthChild(a, b)), + "nth-last-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastChild(a, b)), + "nth-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthOfType(a, b)), + "nth-last-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastOfType(a, b)), + "not" => { + if inside_negation { + Err(()) + } else { + parse_negation(context, arguments, namespaces) + } + } + _ => Err(()) + } +} + +/// Parse a simple selector other than a type selector. +/// +/// * `Err(())`: Invalid selector, abort +/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed. +/// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element +fn parse_one_simple_selector<I>(context: &ParserContext, + iter: &mut Iter<I>, + namespaces: &NamespaceMap, + inside_negation: bool) + -> Result<Option<SimpleSelectorParseResult>,()> + where I: Iterator<ComponentValue> { + match iter.peek() { + Some(&IDHash(_)) => match iter.next() { + Some(IDHash(id)) => Ok(Some(SimpleSelectorResult( + IDSelector(Atom::from_slice(id.as_slice()))))), + _ => panic!("Implementation error, this should not happen."), + }, + Some(&Delim('.')) => { + iter.next(); + match iter.next() { + Some(Ident(class)) => Ok(Some(SimpleSelectorResult( + ClassSelector(Atom::from_slice(class.as_slice()))))), + _ => Err(()), + } + } + Some(&SquareBracketBlock(_)) => match iter.next() { + Some(SquareBracketBlock(content)) + => Ok(Some(SimpleSelectorResult(try!(parse_attribute_selector(content, namespaces))))), + _ => panic!("Implementation error, this should not happen."), + }, + Some(&Colon) => { + iter.next(); + match iter.next() { + Some(Ident(name)) => match parse_simple_pseudo_class(context, name.as_slice()) { + Err(()) => { + match name.as_slice().to_ascii_lower().as_slice() { + // Supported CSS 2.1 pseudo-elements only. + // ** Do not add to this list! ** + "before" => Ok(Some(PseudoElementResult(Before))), + "after" => Ok(Some(PseudoElementResult(After))), +// "first-line" => PseudoElementResult(FirstLine), +// "first-letter" => PseudoElementResult(FirstLetter), + _ => Err(()) + } + }, + Ok(result) => Ok(Some(SimpleSelectorResult(result))), + }, + Some(Function(name, arguments)) + => { + Ok(Some(SimpleSelectorResult(try!(parse_functional_pseudo_class( + context, + name, + arguments, + namespaces, + inside_negation))))) + } + Some(Colon) => { + match iter.next() { + Some(Ident(name)) + => Ok(Some(PseudoElementResult(try!(parse_pseudo_element(name))))), + _ => Err(()), + } + } + _ => Err(()), + } + } + _ => Ok(None), + } +} -fn parse_simple_pseudo_class(name: &str) -> Result<SimpleSelector, ()> { +fn parse_simple_pseudo_class(context: &ParserContext, name: &str) -> Result<SimpleSelector,()> { match name.to_ascii_lower().as_slice() { "any-link" => Ok(AnyLink), "link" => Ok(Link), @@ -507,31 +575,12 @@ 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(()) - } -} - - -fn parse_functional_pseudo_class(name: String, arguments: Vec<ComponentValue>, - namespaces: &NamespaceMap, inside_negation: bool) - -> Result<SimpleSelector, ()> { - match name.as_slice().to_ascii_lower().as_slice() { -// "lang" => parse_lang(arguments), - "nth-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthChild(a, b)), - "nth-last-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastChild(a, b)), - "nth-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthOfType(a, b)), - "nth-last-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastOfType(a, b)), - "not" => if inside_negation { Err(()) } else { parse_negation(arguments, namespaces) }, + "-servo-nonzero-border" if context.origin == UserAgentOrigin => Ok(ServoNonzeroBorder), +// "empty" => Ok(Empty), _ => Err(()) } } - fn parse_pseudo_element(name: String) -> Result<PseudoElement, ()> { match name.as_slice().to_ascii_lower().as_slice() { // All supported pseudo-elements @@ -556,21 +605,6 @@ fn parse_pseudo_element(name: String) -> Result<PseudoElement, ()> { //} -/// Level 3: Parse **one** simple_selector -fn parse_negation(arguments: Vec<ComponentValue>, namespaces: &NamespaceMap) - -> Result<SimpleSelector, ()> { - let iter = &mut arguments.into_iter().peekable(); - match try!(parse_type_selector(iter, namespaces)) { - Some(type_selector) => Ok(Negation(type_selector)), - None => { - match try!(parse_one_simple_selector(iter, namespaces, /* inside_negation = */ true)) { - Some(SimpleSelectorResult(simple_selector)) => Ok(Negation(vec![simple_selector])), - _ => Err(()) - } - }, - } -} - /// Assuming the next token is an ident, consume it and return its value #[inline] @@ -598,6 +632,7 @@ mod tests { use sync::Arc; use cssparser; use namespaces::NamespaceMap; + use selector_matching::AuthorOrigin; use string_cache::Atom; use super::*; @@ -606,7 +641,10 @@ mod tests { } fn parse_ns(input: &str, namespaces: &NamespaceMap) -> Result<Vec<Selector>, ()> { - parse_selector_list(cssparser::tokenize(input).map(|(v, _)| v), namespaces) + let context = ParserContext { + origin: AuthorOrigin, + }; + parse_selector_list(&context, cssparser::tokenize(input).map(|(v, _)| v), namespaces) } fn specificity(a: u32, b: u32, c: u32) -> u32 { diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index efec013ee2d..824172af037 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -10,12 +10,11 @@ use encoding::EncodingRef; use cssparser::{decode_stylesheet_bytes, tokenize, parse_stylesheet_rules, ToCss}; use cssparser::ast::*; -use selectors; +use selectors::{mod, ParserContext}; use properties; use errors::{ErrorLoggerIterator, log_css_error}; use namespaces::{NamespaceMap, parse_namespace_rule}; -use media_queries::{Device, MediaRule, parse_media_rule}; -use media_queries; +use media_queries::{mod, Device, MediaRule}; use font_face::{FontFaceRule, Source, parse_font_face_rule, iter_font_face_rules_inner}; use selector_matching::StylesheetOrigin; @@ -53,9 +52,12 @@ impl Stylesheet { Stylesheet::from_bytes(bytes.as_slice(), base_url, protocol_encoding_label, environment_encoding, origin) } - pub fn from_bytes( - bytes: &[u8], base_url: Url, protocol_encoding_label: Option<&str>, - environment_encoding: Option<EncodingRef>, origin: StylesheetOrigin) -> Stylesheet { + pub fn from_bytes(bytes: &[u8], + base_url: Url, + protocol_encoding_label: Option<&str>, + environment_encoding: Option<EncodingRef>, + origin: StylesheetOrigin) + -> Stylesheet { // TODO: bytes.as_slice could be bytes.container_as_bytes() let (string, _) = decode_stylesheet_bytes( bytes.as_slice(), protocol_encoding_label, environment_encoding); @@ -67,6 +69,11 @@ impl Stylesheet { static STATE_IMPORTS: uint = 2; static STATE_NAMESPACES: uint = 3; static STATE_BODY: uint = 4; + + let parser_context = ParserContext { + origin: origin, + }; + let mut state: uint = STATE_CHARSET; let mut rules = vec!(); @@ -77,7 +84,7 @@ impl Stylesheet { match rule { QualifiedRule_(rule) => { next_state = STATE_BODY; - parse_style_rule(rule, &mut rules, &namespaces, &base_url) + parse_style_rule(&parser_context, rule, &mut rules, &namespaces, &base_url) }, AtRule_(rule) => { let lower_name = rule.name.as_slice().to_ascii_lower(); @@ -114,7 +121,12 @@ impl Stylesheet { }, _ => { next_state = STATE_BODY; - parse_nested_at_rule(lower_name.as_slice(), rule, &mut rules, &namespaces, &base_url) + parse_nested_at_rule(&parser_context, + lower_name.as_slice(), + rule, + &mut rules, + &namespaces, + &base_url) }, } }, @@ -128,13 +140,36 @@ impl Stylesheet { } } +// lower_name is passed explicitly to avoid computing it twice. +pub fn parse_nested_at_rule(context: &ParserContext, + lower_name: &str, + rule: AtRule, + parent_rules: &mut Vec<CSSRule>, + namespaces: &NamespaceMap, + base_url: &Url) { + match lower_name { + "media" => { + media_queries::parse_media_rule(context, rule, parent_rules, namespaces, base_url) + } + "font-face" => parse_font_face_rule(rule, parent_rules, base_url), + _ => log_css_error(rule.location, + format!("Unsupported at-rule: @{:s}", lower_name).as_slice()) + } +} -pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut Vec<CSSRule>, - namespaces: &NamespaceMap, base_url: &Url) { - let QualifiedRule { location, prelude, block} = rule; +pub fn parse_style_rule(context: &ParserContext, + rule: QualifiedRule, + parent_rules: &mut Vec<CSSRule>, + namespaces: &NamespaceMap, + base_url: &Url) { + let QualifiedRule { + location, + prelude, + block + } = rule; // FIXME: avoid doing this for valid selectors let serialized = prelude.iter().to_css(); - match selectors::parse_selector_list(prelude.into_iter(), namespaces) { + match selectors::parse_selector_list(context, prelude.into_iter(), namespaces) { Ok(selectors) => parent_rules.push(CSSStyleRule(StyleRule{ selectors: selectors, declarations: properties::parse_property_declaration_list(block.into_iter(), base_url) @@ -144,19 +179,6 @@ pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut Vec<CSSRule>, } } - -// lower_name is passed explicitly to avoid computing it twice. -pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule, - parent_rules: &mut Vec<CSSRule>, namespaces: &NamespaceMap, base_url: &Url) { - match lower_name { - "media" => parse_media_rule(rule, parent_rules, namespaces, base_url), - "font-face" => parse_font_face_rule(rule, parent_rules, base_url), - _ => log_css_error(rule.location, - format!("Unsupported at-rule: @{:s}", lower_name).as_slice()) - } -} - - pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device, callback: |&StyleRule|) { for rule in rules.iter() { diff --git a/components/util/str.rs b/components/util/str.rs index ebc494c2642..7b2cfdf5107 100644 --- a/components/util/str.rs +++ b/components/util/str.rs @@ -4,7 +4,7 @@ use geometry::Au; -use cssparser::{mod, RGBAColor}; +use cssparser::{mod, RGBA, RGBAColor}; use std::ascii::AsciiExt; use std::from_str::FromStr; use std::iter::Filter; @@ -186,19 +186,8 @@ pub fn parse_length(mut value: &str) -> LengthOrPercentageOrAuto { } } -/// A "simple color" per HTML5 § 2.4.6. -#[deriving(Show)] -pub struct SimpleColor { - /// The red component of the color, [0, 255]. - pub red: u8, - /// The green component of the color, [0, 255]. - pub green: u8, - /// The blue component of the color, [0, 255]. - pub blue: u8, -} - /// Parses a legacy color per HTML5 § 2.4.6. If unparseable, `Err` is returned. -pub fn parse_legacy_color(mut input: &str) -> Result<SimpleColor,()> { +pub fn parse_legacy_color(mut input: &str) -> Result<RGBA,()> { // Steps 1 and 2. if input.len() == 0 { return Err(()) @@ -214,27 +203,22 @@ pub fn parse_legacy_color(mut input: &str) -> Result<SimpleColor,()> { // Step 5. match cssparser::parse_color_keyword(input) { - Ok(RGBAColor(rgba)) => { - return Ok(SimpleColor { - red: (rgba.red * 255.0) as u8, - green: (rgba.green * 255.0) as u8, - blue: (rgba.blue * 255.0) as u8, - }) - } + Ok(RGBAColor(rgba)) => return Ok(rgba), _ => {} } // Step 6. if input.len() == 4 { - match (input.char_at(0), - hex(input.char_at(1)), - hex(input.char_at(2)), - hex(input.char_at(3))) { - ('#', Ok(r), Ok(g), Ok(b)) => { - return Ok(SimpleColor { - red: r * 17, - green: g * 17, - blue: b * 17, + match (input.as_bytes()[0], + hex(input.as_bytes()[1] as char), + hex(input.as_bytes()[2] as char), + hex(input.as_bytes()[3] as char)) { + (b'#', Ok(r), Ok(g), Ok(b)) => { + return Ok(RGBA { + red: (r as f32) * 17.0 / 255.0, + green: (g as f32) * 17.0 / 255.0, + blue: (b as f32) * 17.0 / 255.0, + alpha: 1.0, }) } _ => {} @@ -253,8 +237,11 @@ pub fn parse_legacy_color(mut input: &str) -> Result<SimpleColor,()> { let mut input = new_input.as_slice(); // Step 8. - if input.len() > 128 { - input = input.slice_to(128) + for (char_count, (index, _)) in input.char_indices().enumerate() { + if char_count == 128 { + input = input.slice_to(index); + break + } } // Step 9. @@ -301,10 +288,11 @@ pub fn parse_legacy_color(mut input: &str) -> Result<SimpleColor,()> { } // Steps 15-20. - return Ok(SimpleColor { - red: (hex(red[0] as char).unwrap() << 4) | hex(red[1] as char).unwrap(), - green: (hex(green[0] as char).unwrap() << 4) | hex(green[1] as char).unwrap(), - blue: (hex(blue[0] as char).unwrap() << 4) | hex(blue[1] as char).unwrap(), + return Ok(RGBA { + red: hex_string(red).unwrap() as f32 / 255.0, + green: hex_string(green).unwrap() as f32 / 255.0, + blue: hex_string(blue).unwrap() as f32 / 255.0, + alpha: 1.0, }); fn hex(ch: char) -> Result<u8,()> { @@ -315,6 +303,18 @@ pub fn parse_legacy_color(mut input: &str) -> Result<SimpleColor,()> { _ => Err(()), } } + + fn hex_string(string: &[u8]) -> Result<u8,()> { + match string.len() { + 0 => Err(()), + 1 => hex(string[0] as char), + _ => { + let upper = try!(hex(string[0] as char)); + let lower = try!(hex(string[1] as char)); + Ok((upper << 4) | lower) + } + } + } } diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 460ffbd04df..ed23163657b 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -380,6 +380,7 @@ dependencies = [ name = "layout" version = "0.0.1" dependencies = [ + "cssparser 0.1.0 (git+https://github.com/servo/rust-cssparser)", "encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)", "geom 0.1.0 (git+https://github.com/servo/rust-geom)", "gfx 0.0.1", @@ -657,6 +658,7 @@ dependencies = [ name = "util" version = "0.0.1" dependencies = [ + "cssparser 0.1.0 (git+https://github.com/servo/rust-cssparser)", "geom 0.1.0 (git+https://github.com/servo/rust-geom)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)", "string_cache 0.0.0 (git+https://github.com/servo/string-cache)", diff --git a/tests/ref/basic.list b/tests/ref/basic.list index d522369e4c3..5d993a5fe9c 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -210,5 +210,6 @@ fragment=top != ../html/acid2.html acid2_ref.html != list_style_type_a.html list_style_type_ref.html == list_style_position_a.html list_style_position_ref.html == table_colspan_simple_a.html table_colspan_simple_ref.html +== table_colspan_fixed_a.html table_colspan_fixed_ref.html == legacy_td_bgcolor_attribute_a.html legacy_td_bgcolor_attribute_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 index 44c32e2cdc6..d04789c3b08 100644 --- a/tests/ref/legacy_table_border_attribute_a.html +++ b/tests/ref/legacy_table_border_attribute_a.html @@ -1,9 +1,16 @@ <!DOCTYPE html> <html> +<head> +<style> +table { + border-color: red; +} +</style> +</head> <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> +<table border=10><tr><td style="border: none">:-)</td></tr></table> +<table border=mimi><tr><td style="border: none">:-)</td></tr></table> +<table border=0><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 index 0b513372ac7..ed6eea4fda6 100644 --- a/tests/ref/legacy_table_border_attribute_ref.html +++ b/tests/ref/legacy_table_border_attribute_ref.html @@ -1,8 +1,9 @@ <!DOCTYPE html> <html> +<head> <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: outset red 10px"><tr><td>:-)</td></tr></table> +<table style="border: outset red 1px"><tr><td>:-)</td></tr></table> <table style="border: none"><tr><td>:-)</td></tr></table> </body> </html> diff --git a/tests/ref/table_colspan_fixed_a.html b/tests/ref/table_colspan_fixed_a.html new file mode 100644 index 00000000000..4f775195d53 --- /dev/null +++ b/tests/ref/table_colspan_fixed_a.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<style> +table { + width: 300px; + table-layout: fixed; +} +td[colspan="2"] { + background-color: blue; + color: white; +} +td[colspan="3"] { + background-color: green; + color: white; +} +</style> +<body> +<table border=0 cellspacing=0 cellpadding=0> + <tr><td width=100> </td><td width=100> </td><td width=100> </td></tr> + <tr><td colspan=2> </td><td> </td></tr> + <tr><td> </td><td colspan=2> </td></tr> + <tr><td colspan=3> </td></tr> +</table> +</body> +</html> + diff --git a/tests/ref/table_colspan_fixed_ref.html b/tests/ref/table_colspan_fixed_ref.html new file mode 100644 index 00000000000..36a8756fb14 --- /dev/null +++ b/tests/ref/table_colspan_fixed_ref.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<style> +table { + table-layout: fixed; + width: 300px; +} +td.two { + background-color: blue; + color: white; +} +td.three { + background-color: green; + color: white; +} +</style> +<body> +<table border=0 cellspacing=0 cellpadding=0> + <tr><td width=100> </td><td width=100> </td><td width=100> </td></tr> + <tr><td class=two> </td><td class=two></td><td> </td></tr> + <tr><td> <td class=two> </td><td class=two></td></tr> + <tr><td class=three> </td><td class=three></td><td class=three></td></tr> +</table> +</body> +</html> + |