aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2014-09-19 13:06:19 -0400
committerJosh Matthews <josh@joshmatthews.net>2014-12-18 12:54:02 -0500
commit505e1855a331c046c61417c750f45486363885c1 (patch)
treebdd88e16418df0fa51e3d235eddd1d1c0b23e0c2
parent2e14b653bf3fd1e43d099fee6e404c2cc562ffac (diff)
downloadservo-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.rs11
-rw-r--r--components/script/dom/cssstyledeclaration.rs85
-rw-r--r--components/script/dom/htmlelement.rs4
-rw-r--r--components/script/dom/node.rs2
-rw-r--r--components/style/lib.rs4
-rw-r--r--components/style/properties/common_types.rs121
-rw-r--r--components/style/properties/mod.rs.mako196
-rw-r--r--tests/html/test_style.html7
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>