Implement something like CSS value serialization. Fetch actual inline style declarations from owning elements.

This commit is contained in:
Josh Matthews 2014-09-19 13:06:19 -04:00
parent 2e14b653bf
commit 505e1855a3
8 changed files with 375 additions and 55 deletions

View file

@ -10,6 +10,7 @@ use dom::bindings::global;
use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::cssstyledeclaration::CSSStyleDeclaration; use dom::cssstyledeclaration::CSSStyleDeclaration;
use dom::htmlelement::HTMLElement;
use dom::window::Window; use dom::window::Window;
use servo_util::str::DOMString; use servo_util::str::DOMString;
@ -37,15 +38,15 @@ macro_rules! css_setter(
) )
impl CSS2Properties { impl CSS2Properties {
fn new_inherited() -> CSS2Properties { fn new_inherited(owner: JSRef<HTMLElement>) -> CSS2Properties {
CSS2Properties { CSS2Properties {
cssstyledeclaration: CSSStyleDeclaration::new_inherited(), cssstyledeclaration: CSSStyleDeclaration::new_inherited(Some(owner)),
} }
} }
pub fn new(global: &JSRef<Window>) -> Temporary<CSS2Properties> { pub fn new(global: JSRef<Window>, owner: JSRef<HTMLElement>) -> Temporary<CSS2Properties> {
reflect_dom_object(box CSS2Properties::new_inherited(), reflect_dom_object(box CSS2Properties::new_inherited(owner),
global::Window(*global), global::Window(global),
CSS2PropertiesBinding::Wrap) CSS2PropertiesBinding::Wrap)
} }
} }

View file

@ -3,55 +3,67 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
use dom::bindings::codegen::InheritTypes::ElementCast;
use dom::bindings::error::{ErrorResult, Fallible}; 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::bindings::utils::{Reflectable, Reflector};
use dom::element::{Element, ElementHelpers};
use dom::htmlelement::HTMLElement;
use servo_util::str::DOMString; use servo_util::str::DOMString;
use string_cache::atom::Atom; use string_cache::atom::Atom;
use style::longhands_from_shorthand;
use style::PropertyDeclaration;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
#[dom_struct] #[dom_struct]
pub struct CSSStyleDeclaration { pub struct CSSStyleDeclaration {
reflector_: Reflector, reflector_: Reflector,
owner: Option<JS<HTMLElement>>,
} }
fn get_longhands_from_shorthand(shorthand: &Atom) -> Vec<Atom> { fn serialize_list(list: &Vec<PropertyDeclaration>) -> DOMString {
match shorthand.as_slice() { let mut result = String::new();
"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(": ");
for declaration in list.iter() { 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 result
} }
fn serialize_declaration(_declaration: &Declaration) -> DOMString { fn serialize_value(declaration: &PropertyDeclaration) -> DOMString {
"".to_string() declaration.value().unwrap()
}
fn get_declaration(_property: &Atom) -> Option<Declaration> {
None
} }
impl CSSStyleDeclaration { impl CSSStyleDeclaration {
pub fn new_inherited() -> CSSStyleDeclaration { pub fn new_inherited(owner: Option<JSRef<HTMLElement>>) -> CSSStyleDeclaration {
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> { impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> {
fn CssText(self) -> DOMString { fn CssText(self) -> DOMString {
"".to_string() "".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()); let property = Atom::from_slice(property.as_slice().to_ascii_lower().as_slice());
// 2. If property is a shorthand property, then follow these substeps: // 2. If property is a shorthand property, then follow these substeps:
let longhand_properties = get_longhands_from_shorthand(&property); let longhand_properties = longhands_from_shorthand(property.as_slice());
if !longhand_properties.is_empty() { if longhand_properties.is_some() {
// 1. Let list be a new empty array. // 1. Let list be a new empty array.
let mut list = vec!(); let mut list = vec!();
// 2. For each longhand property longhand that property maps to, in canonical order, // 2. For each longhand property longhand that property maps to, in canonical order,
// follow these substeps: // 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 // 1. If longhand is a case-sensitive match for a property name of a
// CSS declaration in the declarations, let declaration be that CSS // CSS declaration in the declarations, let declaration be that CSS
// declaration, or null otherwise. // 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 // 2. If declaration is null, return the empty string and terminate these
// steps. // steps.
if declaration.is_none() { //XXXjdm ambiguous? this suggests that if we're missing a longhand we return nothing at all.
return "".to_string(); 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. // 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 // 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 // in the declarations, return the result of invoking serialize a CSS value of that
// declaration and terminate these steps. // declaration and terminate these steps.
// 4. Return the empty string. // 4. Return the empty string.
let declaration = get_declaration(&property); let declaration = self.get_declaration(&property);
declaration.as_ref().map(|declaration| serialize_declaration(declaration)) declaration.as_ref().map(|declaration| serialize_value(declaration))
.unwrap_or("".to_string()) .unwrap_or("".to_string())
} }

View file

@ -73,8 +73,8 @@ impl<'a> PrivateHTMLElementHelpers for JSRef<'a, HTMLElement> {
impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> { impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
fn Style(self) -> Temporary<CSSStyleDeclaration> { fn Style(self) -> Temporary<CSSStyleDeclaration> {
if self.style_decl.get().is_none() { if self.style_decl.get().is_none() {
let global = window_from_node(self); let global = window_from_node(self).root();
let style_props = CSS2Properties::new(&*global.root()).root(); let style_props = CSS2Properties::new(*global, self).root();
let style_decl: JSRef<CSSStyleDeclaration> = CSSStyleDeclarationCast::from_ref(*style_props); let style_decl: JSRef<CSSStyleDeclaration> = CSSStyleDeclarationCast::from_ref(*style_props);
self.style_decl.assign(Some(style_decl)); self.style_decl.assign(Some(style_decl));
} }

View file

@ -194,7 +194,7 @@ pub struct SharedLayoutData {
/// Encapsulates the abstract layout data. /// Encapsulates the abstract layout data.
pub struct LayoutData { pub struct LayoutData {
chan: Option<LayoutChan>, chan: Option<LayoutChan>,
_shared_data: SharedLayoutData, pub shared_data: SharedLayoutData,
_data: *const (), _data: *const (),
} }

View file

@ -5,7 +5,7 @@
#![comment = "The Servo Parallel Browser Project"] #![comment = "The Servo Parallel Browser Project"]
#![license = "MPL"] #![license = "MPL"]
#![feature(globs, macro_rules)] #![feature(globs, macro_rules, if_let)]
#![deny(unused_imports)] #![deny(unused_imports)]
#![deny(unused_variables)] #![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::{matches, matches_simple_selector, common_style_affecting_attributes};
pub use selector_matching::{rare_style_affecting_attributes}; pub use selector_matching::{rare_style_affecting_attributes};
pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE, SELECTOR_WHITESPACE}; 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::{PropertyDeclaration, ComputedValues, computed_values, style_structs};
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult}; pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult};

View file

@ -13,6 +13,7 @@ pub type CSSFloat = f64;
pub mod specified { pub mod specified {
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::f64::consts::PI; use std::f64::consts::PI;
use std::fmt::{Formatter, FormatError, Show};
use url::Url; use url::Url;
use cssparser::ast; use cssparser::ast;
use cssparser::ast::*; use cssparser::ast::*;
@ -20,7 +21,7 @@ pub mod specified {
use super::{Au, CSSFloat}; use super::{Au, CSSFloat};
pub use cssparser::Color as CSSColor; pub use cssparser::Color as CSSColor;
#[deriving(Clone, Show)] #[deriving(Clone)]
pub enum Length { pub enum Length {
Au(Au), // application units Au(Au), // application units
Em(CSSFloat), Em(CSSFloat),
@ -40,6 +41,17 @@ pub mod specified {
// Vmin(CSSFloat), // Vmin(CSSFloat),
// Vmax(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_PX: CSSFloat = 60.;
const AU_PER_IN: CSSFloat = AU_PER_PX * 96.; const AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54; 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 { pub enum LengthOrPercentage {
Length(Length), Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] 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 { impl LengthOrPercentage {
fn parse_internal(input: &ComponentValue, negative_ok: bool) fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentage, ()> { -> Result<LengthOrPercentage, ()> {
@ -120,6 +139,15 @@ pub mod specified {
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
Auto, 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 { impl LengthOrPercentageOrAuto {
fn parse_internal(input: &ComponentValue, negative_ok: bool) fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentageOrAuto, ()> { -> Result<LengthOrPercentageOrAuto, ()> {
@ -151,6 +179,15 @@ pub mod specified {
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
None, 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 { impl LengthOrPercentageOrNone {
fn parse_internal(input: &ComponentValue, negative_ok: bool) fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentageOrNone, ()> { -> Result<LengthOrPercentageOrNone, ()> {
@ -219,6 +256,13 @@ pub mod specified {
#[deriving(Clone, PartialEq, PartialOrd)] #[deriving(Clone, PartialEq, PartialOrd)]
pub struct Angle(pub CSSFloat); 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 { impl Angle {
pub fn radians(self) -> f64 { pub fn radians(self) -> f64 {
let Angle(radians) = self; let Angle(radians) = self;
@ -253,6 +297,15 @@ pub mod specified {
LinearGradient(LinearGradient), 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 { impl Image {
pub fn from_component_value(component_value: &ComponentValue, base_url: &Url) pub fn from_component_value(component_value: &ComponentValue, base_url: &Url)
-> Result<Image,()> { -> Result<Image,()> {
@ -296,6 +349,16 @@ pub mod specified {
pub stops: Vec<ColorStop>, 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. /// Specified values for an angle or a corner in a linear gradient.
#[deriving(Clone, PartialEq)] #[deriving(Clone, PartialEq)]
pub enum AngleOrCorner { pub enum AngleOrCorner {
@ -303,6 +366,15 @@ pub mod specified {
Corner(HorizontalDirection, VerticalDirection), 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. /// Specified values for one color stop in a linear gradient.
#[deriving(Clone)] #[deriving(Clone)]
pub struct ColorStop { pub struct ColorStop {
@ -314,18 +386,46 @@ pub mod specified {
pub position: Option<LengthOrPercentage>, 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)] #[deriving(Clone, PartialEq)]
pub enum HorizontalDirection { pub enum HorizontalDirection {
Left, Left,
Right, 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)] #[deriving(Clone, PartialEq)]
pub enum VerticalDirection { pub enum VerticalDirection {
Top, Top,
Bottom, 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,()> { fn parse_color_stop(source: ParserIter) -> Result<ColorStop,()> {
let color = match source.next() { let color = match source.next() {
Some(color) => try!(CSSColor::parse(color)), Some(color) => try!(CSSColor::parse(color)),
@ -466,6 +566,7 @@ pub mod computed {
pub use super::super::longhands::computed_as_specified as compute_CSSColor; pub use super::super::longhands::computed_as_specified as compute_CSSColor;
use super::*; use super::*;
use super::super::longhands; use super::super::longhands;
use std::fmt;
use url::Url; use url::Url;
pub struct Context { pub struct Context {
@ -518,11 +619,19 @@ pub mod computed {
} }
} }
#[deriving(PartialEq, Clone, Show)] #[deriving(PartialEq, Clone)]
pub enum LengthOrPercentage { pub enum LengthOrPercentage {
Length(Au), Length(Au),
Percentage(CSSFloat), 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)] #[allow(non_snake_case)]
pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context) 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 { pub enum LengthOrPercentageOrAuto {
Length(Au), Length(Au),
Percentage(CSSFloat), Percentage(CSSFloat),
@ -554,7 +663,7 @@ pub mod computed {
} }
} }
#[deriving(PartialEq, Clone, Show)] #[deriving(PartialEq, Clone)]
pub enum LengthOrPercentageOrNone { pub enum LengthOrPercentageOrNone {
Length(Au), Length(Au),
Percentage(CSSFloat), Percentage(CSSFloat),

View file

@ -5,6 +5,7 @@
// This file is a Mako template: http://www.makotemplates.org/ // This file is a Mako template: http://www.makotemplates.org/
pub use std::ascii::AsciiExt; pub use std::ascii::AsciiExt;
use std::fmt::Show;
use servo_util::logical_geometry::{WritingMode, LogicalMargin}; use servo_util::logical_geometry::{WritingMode, LogicalMargin};
use sync::Arc; use sync::Arc;
@ -159,13 +160,23 @@ pub mod longhands {
<%self:single_component_value name="${name}" experimental="${experimental}"> <%self:single_component_value name="${name}" experimental="${experimental}">
${caller.body()} ${caller.body()}
pub mod computed_value { pub mod computed_value {
use std::fmt;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[deriving(PartialEq, Clone, FromPrimitive, Show)] #[deriving(PartialEq, Clone, FromPrimitive)]
pub enum T { pub enum T {
% for value in values.split(): % for value in values.split():
${to_rust_ident(value)}, ${to_rust_ident(value)},
% endfor % 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; pub type SpecifiedValue = computed_value::T;
#[inline] pub fn get_initial_value() -> 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 use super::computed_as_specified as to_computed_value;
pub type SpecifiedValue = computed_value::T; pub type SpecifiedValue = computed_value::T;
pub mod computed_value { pub mod computed_value {
use std::fmt;
#[deriving(PartialEq, Clone)] #[deriving(PartialEq, Clone)]
pub enum T { pub enum T {
Auto, Auto,
Number(i32), 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 { impl T {
pub fn number_or_zero(self) -> i32 { pub fn number_or_zero(self) -> i32 {
@ -538,6 +558,7 @@ pub mod longhands {
${switch_to_style_struct("InheritedBox")} ${switch_to_style_struct("InheritedBox")}
<%self:single_component_value name="line-height"> <%self:single_component_value name="line-height">
use std::fmt;
#[deriving(Clone)] #[deriving(Clone)]
pub enum SpecifiedValue { pub enum SpecifiedValue {
Normal, Normal,
@ -545,6 +566,15 @@ pub mod longhands {
Number(CSSFloat), Number(CSSFloat),
// percentage are the same as em. // 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> /// normal | <number> | <length> | <percentage>
pub fn from_component_value(input: &ComponentValue, _base_url: &Url) pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ()> {
@ -586,6 +616,7 @@ pub mod longhands {
${switch_to_style_struct("Box")} ${switch_to_style_struct("Box")}
<%self:single_component_value name="vertical-align"> <%self:single_component_value name="vertical-align">
use std::fmt;
<% vertical_align_keywords = ( <% vertical_align_keywords = (
"baseline sub super top text-top middle bottom text-bottom".split()) %> "baseline sub super top text-top middle bottom text-bottom".split()) %>
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -596,6 +627,16 @@ pub mod longhands {
% endfor % endfor
LengthOrPercentage(specified::LengthOrPercentage), 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 /// baseline | sub | super | top | text-top | middle | bottom | text-bottom
/// | <percentage> | <length> /// | <percentage> | <length>
pub fn from_component_value(input: &ComponentValue, _base_url: &Url) pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
@ -660,10 +701,18 @@ pub mod longhands {
<%self:longhand name="content"> <%self:longhand name="content">
pub use super::computed_as_specified as to_computed_value; pub use super::computed_as_specified as to_computed_value;
pub mod computed_value { pub mod computed_value {
use std::fmt;
#[deriving(PartialEq, Clone)] #[deriving(PartialEq, Clone)]
pub enum ContentItem { pub enum ContentItem {
StringContent(String), 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)] #[allow(non_camel_case_types)]
#[deriving(PartialEq, Clone)] #[deriving(PartialEq, Clone)]
pub enum T { pub enum T {
@ -671,6 +720,20 @@ pub mod longhands {
none, none,
Content(Vec<ContentItem>), 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; pub type SpecifiedValue = computed_value::T;
#[inline] pub fn get_initial_value() -> computed_value::T { T::normal } #[inline] pub fn get_initial_value() -> computed_value::T { T::normal }
@ -784,14 +847,24 @@ pub mod longhands {
</%self:single_component_value> </%self:single_component_value>
<%self:longhand name="background-position"> <%self:longhand name="background-position">
use std::fmt;
pub mod computed_value { pub mod computed_value {
use super::super::super::common_types::computed::LengthOrPercentage; use super::super::super::common_types::computed::LengthOrPercentage;
use std::fmt;
#[deriving(PartialEq, Clone)] #[deriving(PartialEq, Clone)]
pub struct T { pub struct T {
pub horizontal: LengthOrPercentage, pub horizontal: LengthOrPercentage,
pub vertical: 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)] #[deriving(Clone)]
@ -799,6 +872,13 @@ pub mod longhands {
pub horizontal: specified::LengthOrPercentage, pub horizontal: specified::LengthOrPercentage,
pub vertical: 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 { impl SpecifiedValue {
fn new(first: specified::PositionComponent, second: specified::PositionComponent) fn new(first: specified::PositionComponent, second: specified::PositionComponent)
@ -927,6 +1007,7 @@ pub mod longhands {
<%self:longhand name="font-family"> <%self:longhand name="font-family">
pub use super::computed_as_specified as to_computed_value; pub use super::computed_as_specified as to_computed_value;
pub mod computed_value { pub mod computed_value {
use std::fmt;
#[deriving(PartialEq, Clone)] #[deriving(PartialEq, Clone)]
pub enum FontFamily { pub enum FontFamily {
FamilyName(String), 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>; 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; pub type SpecifiedValue = computed_value::T;
@ -998,6 +1094,7 @@ pub mod longhands {
${single_keyword("font-variant", "normal small-caps")} ${single_keyword("font-variant", "normal small-caps")}
<%self:single_component_value name="font-weight"> <%self:single_component_value name="font-weight">
use std::fmt;
#[deriving(Clone)] #[deriving(Clone)]
pub enum SpecifiedValue { pub enum SpecifiedValue {
Bolder, Bolder,
@ -1006,6 +1103,17 @@ pub mod longhands {
SpecifiedWeight${weight}, SpecifiedWeight${weight},
% endfor % 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 /// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
pub fn from_component_value(input: &ComponentValue, _base_url: &Url) pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ()> {
@ -1193,6 +1301,7 @@ pub mod longhands {
<%self:longhand name="text-decoration"> <%self:longhand name="text-decoration">
pub use super::computed_as_specified as to_computed_value; pub use super::computed_as_specified as to_computed_value;
use std::fmt;
#[deriving(PartialEq, Clone)] #[deriving(PartialEq, Clone)]
pub struct SpecifiedValue { pub struct SpecifiedValue {
pub underline: bool, pub underline: bool,
@ -1201,6 +1310,20 @@ pub mod longhands {
// 'blink' is accepted in the parser but ignored. // 'blink' is accepted in the parser but ignored.
// Just not blinking the text is a conforming implementation per CSS 2.1. // 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 mod computed_value {
pub type T = super::SpecifiedValue; pub type T = super::SpecifiedValue;
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
@ -1518,6 +1641,7 @@ pub mod longhands {
<%self:longhand name="box-shadow"> <%self:longhand name="box-shadow">
use cssparser; use cssparser;
use std::fmt;
pub type SpecifiedValue = Vec<SpecifiedBoxShadow>; pub type SpecifiedValue = Vec<SpecifiedBoxShadow>;
@ -1531,6 +1655,20 @@ pub mod longhands {
pub inset: bool, 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 { pub mod computed_value {
use super::super::Au; use super::super::Au;
use super::super::super::computed; use super::super::super::computed;
@ -2314,6 +2452,15 @@ pub enum DeclaredValue<T> {
// depending on whether the property is inherited. // 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)] #[deriving(Clone)]
pub enum PropertyDeclaration { pub enum PropertyDeclaration {
% for property in LONGHANDS: % for property in LONGHANDS:
@ -2329,8 +2476,41 @@ pub enum PropertyDeclarationParseResult {
ValidOrIgnoredDeclaration, ValidOrIgnoredDeclaration,
} }
impl PropertyDeclaration { 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], pub fn parse(name: &str, value: &[ComponentValue],
result_list: &mut Vec<PropertyDeclaration>, result_list: &mut Vec<PropertyDeclaration>,
base_url: &Url, base_url: &Url,
@ -2964,6 +3144,18 @@ pub fn cascade_anonymous(parent_style: &ComputedValues) -> ComputedValues {
result 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. // Only re-export the types for computed values.
pub mod computed_values { pub mod computed_values {

View file

@ -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>