diff options
author | Josh Matthews <josh@joshmatthews.net> | 2014-09-19 13:06:19 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2014-12-18 12:54:02 -0500 |
commit | 505e1855a331c046c61417c750f45486363885c1 (patch) | |
tree | bdd88e16418df0fa51e3d235eddd1d1c0b23e0c2 | |
parent | 2e14b653bf3fd1e43d099fee6e404c2cc562ffac (diff) | |
download | servo-505e1855a331c046c61417c750f45486363885c1.tar.gz servo-505e1855a331c046c61417c750f45486363885c1.zip |
Implement something like CSS value serialization. Fetch actual inline style declarations from owning elements.
-rw-r--r-- | components/script/dom/css2properties.rs | 11 | ||||
-rw-r--r-- | components/script/dom/cssstyledeclaration.rs | 85 | ||||
-rw-r--r-- | components/script/dom/htmlelement.rs | 4 | ||||
-rw-r--r-- | components/script/dom/node.rs | 2 | ||||
-rw-r--r-- | components/style/lib.rs | 4 | ||||
-rw-r--r-- | components/style/properties/common_types.rs | 121 | ||||
-rw-r--r-- | components/style/properties/mod.rs.mako | 196 | ||||
-rw-r--r-- | tests/html/test_style.html | 7 |
8 files changed, 375 insertions, 55 deletions
diff --git a/components/script/dom/css2properties.rs b/components/script/dom/css2properties.rs index cafb721e6ac..a2b5c818885 100644 --- a/components/script/dom/css2properties.rs +++ b/components/script/dom/css2properties.rs @@ -10,6 +10,7 @@ use dom::bindings::global; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::cssstyledeclaration::CSSStyleDeclaration; +use dom::htmlelement::HTMLElement; use dom::window::Window; use servo_util::str::DOMString; @@ -37,15 +38,15 @@ macro_rules! css_setter( ) impl CSS2Properties { - fn new_inherited() -> CSS2Properties { + fn new_inherited(owner: JSRef<HTMLElement>) -> CSS2Properties { CSS2Properties { - cssstyledeclaration: CSSStyleDeclaration::new_inherited(), + cssstyledeclaration: CSSStyleDeclaration::new_inherited(Some(owner)), } } - pub fn new(global: &JSRef<Window>) -> Temporary<CSS2Properties> { - reflect_dom_object(box CSS2Properties::new_inherited(), - global::Window(*global), + pub fn new(global: JSRef<Window>, owner: JSRef<HTMLElement>) -> Temporary<CSS2Properties> { + reflect_dom_object(box CSS2Properties::new_inherited(owner), + global::Window(global), CSS2PropertiesBinding::Wrap) } } diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 58b6de0ed33..a2eb7e152d6 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -3,55 +3,67 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; +use dom::bindings::codegen::InheritTypes::ElementCast; use dom::bindings::error::{ErrorResult, Fallible}; -use dom::bindings::js::JSRef; +use dom::bindings::js::{JS, JSRef, OptionalRootedRootable}; use dom::bindings::utils::{Reflectable, Reflector}; +use dom::element::{Element, ElementHelpers}; +use dom::htmlelement::HTMLElement; use servo_util::str::DOMString; use string_cache::atom::Atom; +use style::longhands_from_shorthand; +use style::PropertyDeclaration; use std::ascii::AsciiExt; #[dom_struct] pub struct CSSStyleDeclaration { reflector_: Reflector, + owner: Option<JS<HTMLElement>>, } -fn get_longhands_from_shorthand(shorthand: &Atom) -> Vec<Atom> { - match shorthand.as_slice() { - "background" => - vec!(Atom::from_slice("background-color"), Atom::from_slice("background-position"), - Atom::from_slice("background-attachment"), Atom::from_slice("background-image"), - Atom::from_slice("background-repeat")), - _ => vec!(), - } -} - -type Declaration = int; - -fn serialize_list(property: String, list: Vec<Declaration>) -> DOMString { - let mut result = property; - result.push_str(": "); +fn serialize_list(list: &Vec<PropertyDeclaration>) -> DOMString { + let mut result = String::new(); for declaration in list.iter() { - result.push_str(serialize_declaration(declaration).as_slice()); + result.push_str(serialize_value(declaration).as_slice()); + result.push_str(" "); } result } -fn serialize_declaration(_declaration: &Declaration) -> DOMString { - "".to_string() -} - -fn get_declaration(_property: &Atom) -> Option<Declaration> { - None +fn serialize_value(declaration: &PropertyDeclaration) -> DOMString { + declaration.value().unwrap() } impl CSSStyleDeclaration { - pub fn new_inherited() -> CSSStyleDeclaration { + pub fn new_inherited(owner: Option<JSRef<HTMLElement>>) -> CSSStyleDeclaration { CSSStyleDeclaration { - reflector_: Reflector::new() + reflector_: Reflector::new(), + owner: owner.map(|owner| JS::from_rooted(owner)), } } } +trait PrivateCSSStyleDeclarationHelpers { + fn get_declaration(self, property: &Atom) -> Option<PropertyDeclaration>; +} + +impl<'a> PrivateCSSStyleDeclarationHelpers for JSRef<'a, CSSStyleDeclaration> { + fn get_declaration(self, property: &Atom) -> Option<PropertyDeclaration> { + self.owner.root().and_then(|owner| { + let element: JSRef<Element> = ElementCast::from_ref(*owner); + let inline_declarations = element.style_attribute().borrow(); + inline_declarations.as_ref().and_then(|declarations| { + for declaration in declarations.normal.iter().chain(declarations.important.iter()) { + if declaration.matches(property.as_slice()) { + return Some(declaration.clone()); + } + } + None + }) + }) + } +} + impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { fn CssText(self) -> DOMString { "".to_string() @@ -75,39 +87,38 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { let property = Atom::from_slice(property.as_slice().to_ascii_lower().as_slice()); // 2. If property is a shorthand property, then follow these substeps: - let longhand_properties = get_longhands_from_shorthand(&property); - if !longhand_properties.is_empty() { + let longhand_properties = longhands_from_shorthand(property.as_slice()); + if longhand_properties.is_some() { // 1. Let list be a new empty array. let mut list = vec!(); // 2. For each longhand property longhand that property maps to, in canonical order, // follow these substeps: - for longhand in longhand_properties.iter() { + for longhand in longhand_properties.unwrap().iter() { // 1. If longhand is a case-sensitive match for a property name of a // CSS declaration in the declarations, let declaration be that CSS // declaration, or null otherwise. - let declaration = get_declaration(longhand); + let declaration = self.get_declaration(&Atom::from_slice(longhand.as_slice())); // 2. If declaration is null, return the empty string and terminate these // steps. - if declaration.is_none() { - return "".to_string(); + //XXXjdm ambiguous? this suggests that if we're missing a longhand we return nothing at all. + if declaration.is_some() { + // 3. Append the declaration to list. + list.push(declaration.unwrap()); } - - // 3. Append the declaration to list. - list.push(declaration.unwrap()); } // 3. Return the serialization of list and terminate these steps. - return serialize_list(property.as_slice().to_string(), list); + return serialize_list(&list); } // 3. If property is a case-sensitive match for a property name of a CSS declaration // in the declarations, return the result of invoking serialize a CSS value of that // declaration and terminate these steps. // 4. Return the empty string. - let declaration = get_declaration(&property); - declaration.as_ref().map(|declaration| serialize_declaration(declaration)) + let declaration = self.get_declaration(&property); + declaration.as_ref().map(|declaration| serialize_value(declaration)) .unwrap_or("".to_string()) } diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index cf7915f3269..e37b37b3c55 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -73,8 +73,8 @@ impl<'a> PrivateHTMLElementHelpers for JSRef<'a, HTMLElement> { impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> { fn Style(self) -> Temporary<CSSStyleDeclaration> { if self.style_decl.get().is_none() { - let global = window_from_node(self); - let style_props = CSS2Properties::new(&*global.root()).root(); + let global = window_from_node(self).root(); + let style_props = CSS2Properties::new(*global, self).root(); let style_decl: JSRef<CSSStyleDeclaration> = CSSStyleDeclarationCast::from_ref(*style_props); self.style_decl.assign(Some(style_decl)); } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 50647862007..234e1c8c707 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -194,7 +194,7 @@ pub struct SharedLayoutData { /// Encapsulates the abstract layout data. pub struct LayoutData { chan: Option<LayoutChan>, - _shared_data: SharedLayoutData, + pub shared_data: SharedLayoutData, _data: *const (), } diff --git a/components/style/lib.rs b/components/style/lib.rs index 6d256792028..f3cf3c843e2 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -5,7 +5,7 @@ #![comment = "The Servo Parallel Browser Project"] #![license = "MPL"] -#![feature(globs, macro_rules)] +#![feature(globs, macro_rules, if_let)] #![deny(unused_imports)] #![deny(unused_variables)] @@ -42,7 +42,7 @@ pub use selector_matching::{CommonStyleAffectingAttributeInfo, CommonStyleAffect pub use selector_matching::{matches, matches_simple_selector, common_style_affecting_attributes}; 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::{cascade, cascade_anonymous, computed, longhands_from_shorthand}; pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs}; pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult}; diff --git a/components/style/properties/common_types.rs b/components/style/properties/common_types.rs index 69b3576f410..52309ad41b6 100644 --- a/components/style/properties/common_types.rs +++ b/components/style/properties/common_types.rs @@ -13,6 +13,7 @@ pub type CSSFloat = f64; pub mod specified { use std::ascii::AsciiExt; use std::f64::consts::PI; + use std::fmt::{Formatter, FormatError, Show}; use url::Url; use cssparser::ast; use cssparser::ast::*; @@ -20,7 +21,7 @@ pub mod specified { use super::{Au, CSSFloat}; pub use cssparser::Color as CSSColor; - #[deriving(Clone, Show)] + #[deriving(Clone)] pub enum Length { Au(Au), // application units Em(CSSFloat), @@ -40,6 +41,17 @@ pub mod specified { // Vmin(CSSFloat), // Vmax(CSSFloat), } + impl Show for Length { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + match self { + &Length::Au(length) => write!(f, "{}", length), + &Length::Em(length) => write!(f, "{}em", length), + &Length::Ex(length) => write!(f, "{}ex", length), + &Length::Rem(length) => write!(f, "{}rem", length), + &Length::ServoCharacterWidth(_) => panic!("internal CSS values should never be serialized"), + } + } + } const AU_PER_PX: CSSFloat = 60.; const AU_PER_IN: CSSFloat = AU_PER_PX * 96.; const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54; @@ -83,12 +95,19 @@ pub mod specified { } } - #[deriving(Clone, Show)] + #[deriving(Clone)] pub enum LengthOrPercentage { Length(Length), Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] } - + impl Show for LengthOrPercentage { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + match self { + &LengthOrPercentage::Length(length) => write!(f, "{}", length), + &LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage), + } + } + } impl LengthOrPercentage { fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Result<LengthOrPercentage, ()> { @@ -120,6 +139,15 @@ pub mod specified { Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] Auto, } + impl Show for LengthOrPercentageOrAuto { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + match self { + &LengthOrPercentageOrAuto::Length(length) => write!(f, "{}", length), + &LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage), + &LengthOrPercentageOrAuto::Auto => write!(f, "auto"), + } + } + } impl LengthOrPercentageOrAuto { fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Result<LengthOrPercentageOrAuto, ()> { @@ -151,6 +179,15 @@ pub mod specified { Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] None, } + impl Show for LengthOrPercentageOrNone { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + match self { + &LengthOrPercentageOrNone::Length(length) => write!(f, "{}", length), + &LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage), + &LengthOrPercentageOrNone::None => write!(f, "none"), + } + } + } impl LengthOrPercentageOrNone { fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Result<LengthOrPercentageOrNone, ()> { @@ -219,6 +256,13 @@ pub mod specified { #[deriving(Clone, PartialEq, PartialOrd)] pub struct Angle(pub CSSFloat); + impl Show for Angle { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + let Angle(value) = *self; + write!(f, "{}", value) + } + } + impl Angle { pub fn radians(self) -> f64 { let Angle(radians) = self; @@ -253,6 +297,15 @@ pub mod specified { LinearGradient(LinearGradient), } + impl Show for Image { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + match self { + &Image::Url(ref url) => write!(f, "url({})", url), + &Image::LinearGradient(ref grad) => write!(f, "linear-gradient({})", grad), + } + } + } + impl Image { pub fn from_component_value(component_value: &ComponentValue, base_url: &Url) -> Result<Image,()> { @@ -296,6 +349,16 @@ pub mod specified { pub stops: Vec<ColorStop>, } + impl Show for LinearGradient { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + let _ = write!(f, "{}", self.angle_or_corner); + for stop in self.stops.iter() { + let _ = write!(f, ", {}", stop); + } + Ok(()) + } + } + /// Specified values for an angle or a corner in a linear gradient. #[deriving(Clone, PartialEq)] pub enum AngleOrCorner { @@ -303,6 +366,15 @@ pub mod specified { Corner(HorizontalDirection, VerticalDirection), } + impl Show for AngleOrCorner { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + match self { + &AngleOrCorner::Angle(angle) => write!(f, "{}", angle), + &AngleOrCorner::Corner(horiz, vert) => write!(f, "to {} {}", horiz, vert), + } + } + } + /// Specified values for one color stop in a linear gradient. #[deriving(Clone)] pub struct ColorStop { @@ -314,18 +386,46 @@ pub mod specified { pub position: Option<LengthOrPercentage>, } + impl Show for ColorStop { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + let _ = write!(f, "{}", self.color); + self.position.map(|pos| { + let _ = write!(f, " {}", pos); + }); + Ok(()) + } + } + #[deriving(Clone, PartialEq)] pub enum HorizontalDirection { Left, Right, } + impl Show for HorizontalDirection { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + match self { + &HorizontalDirection::Left => write!(f, "left"), + &HorizontalDirection::Right => write!(f, "right"), + } + } + } + #[deriving(Clone, PartialEq)] pub enum VerticalDirection { Top, Bottom, } + impl Show for VerticalDirection { + fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + match self { + &VerticalDirection::Top => write!(f, "top"), + &VerticalDirection::Bottom => write!(f, "bottom"), + } + } + } + fn parse_color_stop(source: ParserIter) -> Result<ColorStop,()> { let color = match source.next() { Some(color) => try!(CSSColor::parse(color)), @@ -466,6 +566,7 @@ pub mod computed { pub use super::super::longhands::computed_as_specified as compute_CSSColor; use super::*; use super::super::longhands; + use std::fmt; use url::Url; pub struct Context { @@ -518,11 +619,19 @@ pub mod computed { } } - #[deriving(PartialEq, Clone, Show)] + #[deriving(PartialEq, Clone)] pub enum LengthOrPercentage { Length(Au), Percentage(CSSFloat), } + impl fmt::Show for LengthOrPercentage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &LengthOrPercentage::Length(length) => write!(f, "{}", length), + &LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage), + } + } + } #[allow(non_snake_case)] pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context) @@ -535,7 +644,7 @@ pub mod computed { } } - #[deriving(PartialEq, Clone, Show)] + #[deriving(PartialEq, Clone)] pub enum LengthOrPercentageOrAuto { Length(Au), Percentage(CSSFloat), @@ -554,7 +663,7 @@ pub mod computed { } } - #[deriving(PartialEq, Clone, Show)] + #[deriving(PartialEq, Clone)] pub enum LengthOrPercentageOrNone { Length(Au), Percentage(CSSFloat), diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako index f82c821a8bb..9bb5b8a49fc 100644 --- a/components/style/properties/mod.rs.mako +++ b/components/style/properties/mod.rs.mako @@ -5,6 +5,7 @@ // This file is a Mako template: http://www.makotemplates.org/ pub use std::ascii::AsciiExt; +use std::fmt::Show; use servo_util::logical_geometry::{WritingMode, LogicalMargin}; use sync::Arc; @@ -159,13 +160,23 @@ pub mod longhands { <%self:single_component_value name="${name}" experimental="${experimental}"> ${caller.body()} pub mod computed_value { + use std::fmt; #[allow(non_camel_case_types)] - #[deriving(PartialEq, Clone, FromPrimitive, Show)] + #[deriving(PartialEq, Clone, FromPrimitive)] pub enum T { % for value in values.split(): ${to_rust_ident(value)}, % endfor } + impl fmt::Show for T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + % for value in values.split(): + &T::${to_rust_ident(value)} => write!(f, "${value}"), + % endfor + } + } + } } pub type SpecifiedValue = computed_value::T; #[inline] pub fn get_initial_value() -> computed_value::T { @@ -455,11 +466,20 @@ pub mod longhands { pub use super::computed_as_specified as to_computed_value; pub type SpecifiedValue = computed_value::T; pub mod computed_value { + use std::fmt; #[deriving(PartialEq, Clone)] pub enum T { Auto, Number(i32), } + impl fmt::Show for T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &T::Auto => write!(f, "auto"), + &T::Number(number) => write!(f, "{}", number), + } + } + } impl T { pub fn number_or_zero(self) -> i32 { @@ -538,6 +558,7 @@ pub mod longhands { ${switch_to_style_struct("InheritedBox")} <%self:single_component_value name="line-height"> + use std::fmt; #[deriving(Clone)] pub enum SpecifiedValue { Normal, @@ -545,6 +566,15 @@ pub mod longhands { Number(CSSFloat), // percentage are the same as em. } + impl fmt::Show for SpecifiedValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &SpecifiedValue::Normal => write!(f, "normal"), + &SpecifiedValue::Length(length) => write!(f, "{}%", length), + &SpecifiedValue::Number(number) => write!(f, "{}", number), + } + } + } /// normal | <number> | <length> | <percentage> pub fn from_component_value(input: &ComponentValue, _base_url: &Url) -> Result<SpecifiedValue, ()> { @@ -586,6 +616,7 @@ pub mod longhands { ${switch_to_style_struct("Box")} <%self:single_component_value name="vertical-align"> + use std::fmt; <% vertical_align_keywords = ( "baseline sub super top text-top middle bottom text-bottom".split()) %> #[allow(non_camel_case_types)] @@ -596,6 +627,16 @@ pub mod longhands { % endfor LengthOrPercentage(specified::LengthOrPercentage), } + impl fmt::Show for SpecifiedValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + % for keyword in vertical_align_keywords: + &SpecifiedValue::${to_rust_ident(keyword)} => write!(f, "${keyword}"), + % endfor + &SpecifiedValue::LengthOrPercentage(lop) => write!(f, "{}", lop), + } + } + } /// baseline | sub | super | top | text-top | middle | bottom | text-bottom /// | <percentage> | <length> pub fn from_component_value(input: &ComponentValue, _base_url: &Url) @@ -660,10 +701,18 @@ pub mod longhands { <%self:longhand name="content"> pub use super::computed_as_specified as to_computed_value; pub mod computed_value { + use std::fmt; #[deriving(PartialEq, Clone)] pub enum ContentItem { StringContent(String), } + impl fmt::Show for ContentItem { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &ContentItem::StringContent(ref s) => write!(f, "{}", s), + } + } + } #[allow(non_camel_case_types)] #[deriving(PartialEq, Clone)] pub enum T { @@ -671,6 +720,20 @@ pub mod longhands { none, Content(Vec<ContentItem>), } + impl fmt::Show for T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &T::normal => write!(f, "normal"), + &T::none => write!(f, "none"), + &T::Content(ref content) => { + for c in content.iter() { + let _ = write!(f, "{} ", c); + } + Ok(()) + } + } + } + } } pub type SpecifiedValue = computed_value::T; #[inline] pub fn get_initial_value() -> computed_value::T { T::normal } @@ -784,14 +847,24 @@ pub mod longhands { </%self:single_component_value> <%self:longhand name="background-position"> + use std::fmt; + pub mod computed_value { use super::super::super::common_types::computed::LengthOrPercentage; + use std::fmt; #[deriving(PartialEq, Clone)] pub struct T { pub horizontal: LengthOrPercentage, pub vertical: LengthOrPercentage, } + impl fmt::Show for T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let _ = write!(f, "{}", self.horizontal); + let _ = write!(f, "{}", self.vertical); + Ok(()) + } + } } #[deriving(Clone)] @@ -799,6 +872,13 @@ pub mod longhands { pub horizontal: specified::LengthOrPercentage, pub vertical: specified::LengthOrPercentage, } + impl fmt::Show for SpecifiedValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let _ = write!(f, "{}", self.horizontal); + let _ = write!(f, "{}", self.vertical); + Ok(()) + } + } impl SpecifiedValue { fn new(first: specified::PositionComponent, second: specified::PositionComponent) @@ -927,6 +1007,7 @@ pub mod longhands { <%self:longhand name="font-family"> pub use super::computed_as_specified as to_computed_value; pub mod computed_value { + use std::fmt; #[deriving(PartialEq, Clone)] pub enum FontFamily { FamilyName(String), @@ -944,7 +1025,22 @@ pub mod longhands { } } } + impl fmt::Show for FontFamily { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &FontFamily::FamilyName(ref name) => write!(f, "{}", name), + } + } + } pub type T = Vec<FontFamily>; + /*impl fmt::Show for T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for font in self.iter() { + write!(f, "{} ", font); + } + Ok(()) + } + }*/ } pub type SpecifiedValue = computed_value::T; @@ -998,6 +1094,7 @@ pub mod longhands { ${single_keyword("font-variant", "normal small-caps")} <%self:single_component_value name="font-weight"> + use std::fmt; #[deriving(Clone)] pub enum SpecifiedValue { Bolder, @@ -1006,6 +1103,17 @@ pub mod longhands { SpecifiedWeight${weight}, % endfor } + impl fmt::Show for SpecifiedValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &SpecifiedValue::Bolder => write!(f, "bolder"), + &SpecifiedValue::Lighter => write!(f, "lighter"), + % for weight in range(100, 901, 100): + &SpecifiedValue::SpecifiedWeight${weight} => write!(f, "{}", ${weight}i), + % endfor + } + } + } /// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 pub fn from_component_value(input: &ComponentValue, _base_url: &Url) -> Result<SpecifiedValue, ()> { @@ -1193,6 +1301,7 @@ pub mod longhands { <%self:longhand name="text-decoration"> pub use super::computed_as_specified as to_computed_value; + use std::fmt; #[deriving(PartialEq, Clone)] pub struct SpecifiedValue { pub underline: bool, @@ -1201,6 +1310,20 @@ pub mod longhands { // 'blink' is accepted in the parser but ignored. // Just not blinking the text is a conforming implementation per CSS 2.1. } + impl fmt::Show for SpecifiedValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.underline { + let _ = write!(f, "underline "); + } + if self.overline { + let _ = write!(f, "overline "); + } + if self.line_through { + let _ = write!(f, "line-through "); + } + Ok(()) + } + } pub mod computed_value { pub type T = super::SpecifiedValue; #[allow(non_upper_case_globals)] @@ -1518,6 +1641,7 @@ pub mod longhands { <%self:longhand name="box-shadow"> use cssparser; + use std::fmt; pub type SpecifiedValue = Vec<SpecifiedBoxShadow>; @@ -1531,6 +1655,20 @@ pub mod longhands { pub inset: bool, } + impl fmt::Show for SpecifiedBoxShadow { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.inset { + let _ = write!(f, "inset "); + } + let _ = write!(f, "{} {} {} {}", self.offset_x, self.offset_y, + self.blur_radius, self.spread_radius); + if let Some(ref color) = self.color { + let _ = write!(f, "{}", color); + } + Ok(()) + } + } + pub mod computed_value { use super::super::Au; use super::super::super::computed; @@ -2314,6 +2452,15 @@ pub enum DeclaredValue<T> { // depending on whether the property is inherited. } +impl<T: Show> DeclaredValue<T> { + pub fn specified_value(&self) -> Option<String> { + match self { + &DeclaredValue::SpecifiedValue(ref inner) => Some(format!("{}", inner)), + _ => None, + } + } +} + #[deriving(Clone)] pub enum PropertyDeclaration { % for property in LONGHANDS: @@ -2329,8 +2476,41 @@ pub enum PropertyDeclarationParseResult { ValidOrIgnoredDeclaration, } - impl PropertyDeclaration { + pub fn name(&self) -> String { + match self { + % for property in LONGHANDS: + % if property.derived_from is None: + &PropertyDeclaration::${property.camel_case}Declaration(..) => "${property.name}".to_string(), + % endif + % endfor + _ => "".to_string(), + } + } + + pub fn value(&self) -> Option<String> { + match self { + % for property in LONGHANDS: + % if property.derived_from is None: + &PropertyDeclaration::${property.camel_case}Declaration(ref value) => value.specified_value(), + % endif + % endfor + _ => None, + } + } + + pub fn matches(&self, name: &str) -> bool { + let name_lower = name.as_slice().to_ascii_lower(); + match (self, name_lower.as_slice()) { + % for property in LONGHANDS: + % if property.derived_from is None: + (&PropertyDeclaration::${property.camel_case}Declaration(..), "${property.name}") => true, + % endif + % endfor + _ => false, + } + } + pub fn parse(name: &str, value: &[ComponentValue], result_list: &mut Vec<PropertyDeclaration>, base_url: &Url, @@ -2964,6 +3144,18 @@ pub fn cascade_anonymous(parent_style: &ComputedValues) -> ComputedValues { result } +pub fn longhands_from_shorthand(shorthand: &str) -> Option<Vec<String>> { + match shorthand { + % for property in SHORTHANDS: + "${property.name}" => Some(vec!( + % for sub in property.sub_properties: + "${sub.name}".to_string(), + % endfor + )), + % endfor + _ => None, + } +} // Only re-export the types for computed values. pub mod computed_values { diff --git a/tests/html/test_style.html b/tests/html/test_style.html new file mode 100644 index 00000000000..362dae2e0dc --- /dev/null +++ b/tests/html/test_style.html @@ -0,0 +1,7 @@ +<div id="test" style="display: block; background-color: black; background-position: top left;"></div> +<script> +alert(document.getElementById('test').style.display); +alert(document.getElementById('test').style.background); +alert(document.getElementById('test').style.backgroundColor); +alert(document.getElementById('test').style.backgroundPosition); +</script> |