From 1c5d58180d58325676a287119123d27655a1fdf2 Mon Sep 17 00:00:00 2001 From: Cameron Zwarich Date: Tue, 13 May 2014 00:37:52 -0700 Subject: [PATCH 01/20] Add the basic CSSStyleDeclaration CSSOM interface. This just includes the .webidl file (with some of the functionality commented out) and the stub implementations for the bindings. This is another step towards #1721. --- components/script/dom/cssstyledeclaration.rs | 68 +++++++++++++++++++ .../dom/webidls/CSSStyleDeclaration.webidl | 31 +++++++++ components/script/lib.rs | 1 + 3 files changed, 100 insertions(+) create mode 100644 components/script/dom/cssstyledeclaration.rs create mode 100644 components/script/dom/webidls/CSSStyleDeclaration.webidl diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs new file mode 100644 index 00000000000..873d7dfb6a2 --- /dev/null +++ b/components/script/dom/cssstyledeclaration.rs @@ -0,0 +1,68 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; +use dom::bindings::error::{ErrorResult, Fallible}; +use dom::bindings::utils::{Reflectable, Reflector}; +use dom::bindings::js::JSRef; +use servo_util::str::DOMString; + +#[dom_struct] +pub struct CSSStyleDeclaration { + reflector_: Reflector, +} + +impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { + fn CssText(self) -> DOMString { + "".to_string() + } + + fn SetCssText(self, _cssText: DOMString) -> ErrorResult { + Ok(()) + } + + fn Length(self) -> u32 { + 0 + } + + fn Item(self, _index: u32) -> DOMString { + "".to_string() + } + + fn GetPropertyValue(self, _property: DOMString) -> DOMString { + "".to_string() + } + + fn GetPropertyPriority(self, _property: DOMString) -> DOMString { + "".to_string() + } + + fn SetProperty(self, _property: DOMString, _value: DOMString, + _priority: DOMString) -> ErrorResult { + Ok(()) + } + + fn SetPropertyValue(self, _property: DOMString, _value: DOMString) -> ErrorResult { + Ok(()) + } + + fn SetPropertyPriority(self, _property: DOMString, _priority: DOMString) -> ErrorResult { + Ok(()) + } + + fn RemoveProperty(self, _property: DOMString) -> Fallible { + Ok("".to_string()) + } + + fn IndexedGetter(self, _index: u32, _found: &mut bool) -> DOMString { + "".to_string() + } +} + +impl Reflectable for CSSStyleDeclaration { + fn reflector<'a>(&'a self) -> &'a Reflector { + &self.reflector_ + } +} + diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl new file mode 100644 index 00000000000..09079fe0fec --- /dev/null +++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface + * + * Copyright © 2013 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. + */ + +interface CSSStyleDeclaration { + [SetterThrows] + attribute DOMString cssText; + readonly attribute unsigned long length; + getter DOMString item(unsigned long index); + DOMString getPropertyValue(DOMString property); + DOMString getPropertyPriority(DOMString property); + [Throws] + void setProperty(DOMString property, [TreatNullAs=EmptyString] DOMString value, + [TreatNullAs=EmptyString] optional DOMString priority = ""); + [Throws] + void setPropertyValue(DOMString property, [TreatNullAs=EmptyString] DOMString value); + [Throws] + void setPropertyPriority(DOMString property, [TreatNullAs=EmptyString] DOMString priority); + [Throws] + DOMString removeProperty(DOMString property); +// Not implemented yet: +// readonly attribute CSSRule? parentRule; +// attribute DOMString cssFloat; +}; + diff --git a/components/script/lib.rs b/components/script/lib.rs index 26f773f6006..c818df7cb00 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -88,6 +88,7 @@ pub mod dom { pub mod browsercontext; pub mod canvasrenderingcontext2d; pub mod characterdata; + pub mod cssstyledeclaration; pub mod domrect; pub mod domrectlist; pub mod domstringmap; From 4da0ca8ace1a18f0d37525b55025d57c908c7c81 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 18 Sep 2014 12:53:04 -0400 Subject: [PATCH 02/20] Add stub CSS2Properties type. --- components/script/dom/css2properties.rs | 64 +++++++++++++++++++ components/script/dom/cssstyledeclaration.rs | 1 - .../script/dom/webidls/CSS2Properties.webidl | 17 +++++ components/script/lib.rs | 1 + 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 components/script/dom/css2properties.rs create mode 100644 components/script/dom/webidls/CSS2Properties.webidl diff --git a/components/script/dom/css2properties.rs b/components/script/dom/css2properties.rs new file mode 100644 index 00000000000..95de3b782d1 --- /dev/null +++ b/components/script/dom/css2properties.rs @@ -0,0 +1,64 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::CSS2PropertiesBinding::CSS2PropertiesMethods; +use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; +use dom::bindings::codegen::InheritTypes::CSSStyleDeclarationCast; +use dom::bindings::utils::{Reflectable, Reflector}; +use dom::bindings::js::JSRef; +use dom::cssstyledeclaration::CSSStyleDeclaration; +use servo_util::str::DOMString; + +#[dom_struct] +pub struct CSS2Properties { + declaration: CSSStyleDeclaration, +} + +impl<'a> CSS2PropertiesMethods for JSRef<'a, CSS2Properties> { + fn Color(self) -> DOMString { + "".to_string() + } + + fn SetColor(self, _value: DOMString) { + } + + fn Background(self) -> DOMString { + "".to_string() + } + + fn SetBackground(self, _value: DOMString) { + } + + fn Display(self) -> DOMString { + "".to_string() + } + + fn SetDisplay(self, _value: DOMString) { + } + + fn Width(self) -> DOMString { + "".to_string() + } + + fn SetWidth(self, _value: DOMString) { + } + + fn Height(self) -> DOMString { + "".to_string() + } + + fn SetHeight(self, _value: DOMString) { + } + + fn IndexedGetter(self, index: u32, found: &mut bool) -> DOMString { + let decl: JSRef = CSSStyleDeclarationCast::from_ref(self); + decl.IndexedGetter(index, found) + } +} + +impl Reflectable for CSS2Properties { + fn reflector<'a>(&'a self) -> &'a Reflector { + self.declaration.reflector() + } +} diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 873d7dfb6a2..d9687fd17f3 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -65,4 +65,3 @@ impl Reflectable for CSSStyleDeclaration { &self.reflector_ } } - diff --git a/components/script/dom/webidls/CSS2Properties.webidl b/components/script/dom/webidls/CSS2Properties.webidl new file mode 100644 index 00000000000..818a41522ad --- /dev/null +++ b/components/script/dom/webidls/CSS2Properties.webidl @@ -0,0 +1,17 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * http://dev.w3.org/csswg/cssom/ + * + */ + +interface CSS2Properties : CSSStyleDeclaration { + [TreatNullAs=EmptyString] attribute DOMString color; + [TreatNullAs=EmptyString] attribute DOMString display; + [TreatNullAs=EmptyString] attribute DOMString background; + [TreatNullAs=EmptyString] attribute DOMString width; + [TreatNullAs=EmptyString] attribute DOMString height; +}; diff --git a/components/script/lib.rs b/components/script/lib.rs index c818df7cb00..a956a26d876 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -88,6 +88,7 @@ pub mod dom { pub mod browsercontext; pub mod canvasrenderingcontext2d; pub mod characterdata; + pub mod css2properties; pub mod cssstyledeclaration; pub mod domrect; pub mod domrectlist; From 2cfa8e85a69cf04fa97b1e5792a9e0d8eb7f30b6 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 18 Sep 2014 15:08:24 -0400 Subject: [PATCH 03/20] Stub in some uses of getPropertyValue and sketch out its implementation. --- components/script/dom/css2properties.rs | 63 +++++++++------- components/script/dom/cssstyledeclaration.rs | 73 ++++++++++++++++++- .../script/dom/webidls/CSS2Properties.webidl | 5 ++ 3 files changed, 114 insertions(+), 27 deletions(-) diff --git a/components/script/dom/css2properties.rs b/components/script/dom/css2properties.rs index 95de3b782d1..db1787f42a3 100644 --- a/components/script/dom/css2properties.rs +++ b/components/script/dom/css2properties.rs @@ -15,41 +15,54 @@ pub struct CSS2Properties { declaration: CSSStyleDeclaration, } +macro_rules! css_getter( + ( $idlattr:ident, $cssprop:expr ) => ( + fn $idlattr(self) -> DOMString { + let decl: JSRef = CSSStyleDeclarationCast::from_ref(self); + decl.GetPropertyValue($cssprop.to_string()) + } + ); +) + +macro_rules! css_setter( + ( $fnname:ident, $cssprop:expr ) => ( + fn $fnname(self, value: DOMString) { + let decl: JSRef = CSSStyleDeclarationCast::from_ref(self); + decl.SetPropertyValue($cssprop.to_string(), value).unwrap(); + } + ); +) + impl<'a> CSS2PropertiesMethods for JSRef<'a, CSS2Properties> { - fn Color(self) -> DOMString { - "".to_string() - } + css_getter!(Color, "color") + css_setter!(SetColor, "color") - fn SetColor(self, _value: DOMString) { - } + css_getter!(Background, "background") + css_setter!(SetBackground, "background") - fn Background(self) -> DOMString { - "".to_string() - } + css_getter!(BackgroundColor, "background-color") + css_setter!(SetBackgroundColor, "background-color") - fn SetBackground(self, _value: DOMString) { - } + css_getter!(BackgroundPosition, "background-position") + css_setter!(SetBackgroundPosition, "background-position") - fn Display(self) -> DOMString { - "".to_string() - } + css_getter!(BackgroundImage, "background-image") + css_setter!(SetBackgroundImage, "background-image") - fn SetDisplay(self, _value: DOMString) { - } + css_getter!(BackgroundRepeat, "background-repeat") + css_setter!(SetBackgroundRepeat, "background-repeat") - fn Width(self) -> DOMString { - "".to_string() - } + css_getter!(BackgroundAttachment, "background-attachment") + css_setter!(SetBackgroundAttachment, "background-attachment") - fn SetWidth(self, _value: DOMString) { - } + css_getter!(Display, "display") + css_setter!(SetDisplay, "display") - fn Height(self) -> DOMString { - "".to_string() - } + css_getter!(Width, "width") + css_setter!(SetWidth, "width") - fn SetHeight(self, _value: DOMString) { - } + css_getter!(Height, "height") + css_setter!(SetHeight, "height") fn IndexedGetter(self, index: u32, found: &mut bool) -> DOMString { let decl: JSRef = CSSStyleDeclarationCast::from_ref(self); diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index d9687fd17f3..f2865a5aced 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -7,12 +7,43 @@ use dom::bindings::error::{ErrorResult, Fallible}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::js::JSRef; use servo_util::str::DOMString; +use string_cache::atom::Atom; +use std::ascii::AsciiExt; #[dom_struct] pub struct CSSStyleDeclaration { reflector_: Reflector, } +fn get_longhands_from_shorthand(shorthand: &Atom) -> Vec { + 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) -> DOMString { + let mut result = property; + result.push_str(": "); + for declaration in list.iter() { + result.push_str(serialize_declaration(declaration).as_slice()); + } + result +} + +fn serialize_declaration(_declaration: &Declaration) -> DOMString { + "".to_string() +} + +fn get_declaration(_property: &Atom) -> Option { + None +} + impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { fn CssText(self) -> DOMString { "".to_string() @@ -30,8 +61,46 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { "".to_string() } - fn GetPropertyValue(self, _property: DOMString) -> DOMString { - "".to_string() + //http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue + fn GetPropertyValue(self, property: DOMString) -> DOMString { + // 1. Let property be property converted to ASCII lowercase. + 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() { + // 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() { + // 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); + + // 2. If declaration is null, return the empty string and terminate these + // steps. + if declaration.is_none() { + return "".to_string(); + } + + // 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); + } + + // 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)) + .unwrap_or("".to_string()) } fn GetPropertyPriority(self, _property: DOMString) -> DOMString { diff --git a/components/script/dom/webidls/CSS2Properties.webidl b/components/script/dom/webidls/CSS2Properties.webidl index 818a41522ad..69efb8a066d 100644 --- a/components/script/dom/webidls/CSS2Properties.webidl +++ b/components/script/dom/webidls/CSS2Properties.webidl @@ -12,6 +12,11 @@ interface CSS2Properties : CSSStyleDeclaration { [TreatNullAs=EmptyString] attribute DOMString color; [TreatNullAs=EmptyString] attribute DOMString display; [TreatNullAs=EmptyString] attribute DOMString background; + [TreatNullAs=EmptyString] attribute DOMString backgroundColor; + [TreatNullAs=EmptyString] attribute DOMString backgroundPosition; + [TreatNullAs=EmptyString] attribute DOMString backgroundRepeat; + [TreatNullAs=EmptyString] attribute DOMString backgroundImage; + [TreatNullAs=EmptyString] attribute DOMString backgroundAttachment; [TreatNullAs=EmptyString] attribute DOMString width; [TreatNullAs=EmptyString] attribute DOMString height; }; From 2e14b653bf3fd1e43d099fee6e404c2cc562ffac Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 18 Sep 2014 15:34:55 -0400 Subject: [PATCH 04/20] Add a style property to HTMLElement. --- components/script/dom/css2properties.rs | 25 ++++++++++++++++--- components/script/dom/cssstyledeclaration.rs | 10 +++++++- components/script/dom/htmlelement.rs | 24 +++++++++++++++--- .../dom/webidls/ElementCSSInlineStyle.webidl | 11 ++++++++ .../script/dom/webidls/HTMLElement.webidl | 1 + 5 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 components/script/dom/webidls/ElementCSSInlineStyle.webidl diff --git a/components/script/dom/css2properties.rs b/components/script/dom/css2properties.rs index db1787f42a3..cafb721e6ac 100644 --- a/components/script/dom/css2properties.rs +++ b/components/script/dom/css2properties.rs @@ -2,17 +2,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::bindings::codegen::Bindings::CSS2PropertiesBinding; use dom::bindings::codegen::Bindings::CSS2PropertiesBinding::CSS2PropertiesMethods; use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; use dom::bindings::codegen::InheritTypes::CSSStyleDeclarationCast; -use dom::bindings::utils::{Reflectable, Reflector}; -use dom::bindings::js::JSRef; +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::window::Window; use servo_util::str::DOMString; #[dom_struct] pub struct CSS2Properties { - declaration: CSSStyleDeclaration, + cssstyledeclaration: CSSStyleDeclaration, } macro_rules! css_getter( @@ -33,6 +36,20 @@ macro_rules! css_setter( ); ) +impl CSS2Properties { + fn new_inherited() -> CSS2Properties { + CSS2Properties { + cssstyledeclaration: CSSStyleDeclaration::new_inherited(), + } + } + + pub fn new(global: &JSRef) -> Temporary { + reflect_dom_object(box CSS2Properties::new_inherited(), + global::Window(*global), + CSS2PropertiesBinding::Wrap) + } +} + impl<'a> CSS2PropertiesMethods for JSRef<'a, CSS2Properties> { css_getter!(Color, "color") css_setter!(SetColor, "color") @@ -72,6 +89,6 @@ impl<'a> CSS2PropertiesMethods for JSRef<'a, CSS2Properties> { impl Reflectable for CSS2Properties { fn reflector<'a>(&'a self) -> &'a Reflector { - self.declaration.reflector() + self.cssstyledeclaration.reflector() } } diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index f2865a5aced..58b6de0ed33 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -4,8 +4,8 @@ use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; use dom::bindings::error::{ErrorResult, Fallible}; -use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::js::JSRef; +use dom::bindings::utils::{Reflectable, Reflector}; use servo_util::str::DOMString; use string_cache::atom::Atom; use std::ascii::AsciiExt; @@ -44,6 +44,14 @@ fn get_declaration(_property: &Atom) -> Option { None } +impl CSSStyleDeclaration { + pub fn new_inherited() -> CSSStyleDeclaration { + CSSStyleDeclaration { + reflector_: Reflector::new() + } + } +} + impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { fn CssText(self) -> DOMString { "".to_string() diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index f8a8ea7ce5c..cf7915f3269 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -10,10 +10,12 @@ use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods; use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived}; -use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast}; +use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast, CSSStyleDeclarationCast}; use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived}; -use dom::bindings::js::{JSRef, Temporary}; +use dom::bindings::js::{JSRef, Temporary, MutNullableJS}; use dom::bindings::utils::{Reflectable, Reflector}; +use dom::cssstyledeclaration::CSSStyleDeclaration; +use dom::css2properties::CSS2Properties; use dom::document::Document; use dom::element::{Element, ElementTypeId, ActivationElementHelpers}; use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; @@ -24,9 +26,12 @@ use servo_util::str::DOMString; use string_cache::Atom; +use std::default::Default; + #[dom_struct] pub struct HTMLElement { - element: Element + element: Element, + style_decl: MutNullableJS, } impl HTMLElementDerived for EventTarget { @@ -42,7 +47,8 @@ impl HTMLElementDerived for EventTarget { impl HTMLElement { pub fn new_inherited(type_id: ElementTypeId, tag_name: DOMString, prefix: Option, document: JSRef) -> HTMLElement { HTMLElement { - element: Element::new_inherited(type_id, tag_name, ns!(HTML), prefix, document) + element: Element::new_inherited(type_id, tag_name, ns!(HTML), prefix, document), + style_decl: Default::default(), } } @@ -65,6 +71,16 @@ impl<'a> PrivateHTMLElementHelpers for JSRef<'a, HTMLElement> { } impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> { + fn Style(self) -> Temporary { + if self.style_decl.get().is_none() { + let global = window_from_node(self); + let style_props = CSS2Properties::new(&*global.root()).root(); + let style_decl: JSRef = CSSStyleDeclarationCast::from_ref(*style_props); + self.style_decl.assign(Some(style_decl)); + } + self.style_decl.get().unwrap() + } + make_getter!(Title) make_setter!(SetTitle, "title") diff --git a/components/script/dom/webidls/ElementCSSInlineStyle.webidl b/components/script/dom/webidls/ElementCSSInlineStyle.webidl new file mode 100644 index 00000000000..85e14fab10e --- /dev/null +++ b/components/script/dom/webidls/ElementCSSInlineStyle.webidl @@ -0,0 +1,11 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//http://dev.w3.org/csswg/cssom/#elementcssinlinestyle + +[NoInterfaceObject] +interface ElementCSSInlineStyle { + [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style; +}; diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl index 359ef11f0a7..39c7699900d 100644 --- a/components/script/dom/webidls/HTMLElement.webidl +++ b/components/script/dom/webidls/HTMLElement.webidl @@ -46,3 +46,4 @@ interface HTMLElement : Element { //readonly attribute boolean? commandChecked; }; HTMLElement implements GlobalEventHandlers; +HTMLElement implements ElementCSSInlineStyle; From 505e1855a331c046c61417c750f45486363885c1 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 19 Sep 2014 13:06:19 -0400 Subject: [PATCH 05/20] Implement something like CSS value serialization. Fetch actual inline style declarations from owning elements. --- components/script/dom/css2properties.rs | 11 +- components/script/dom/cssstyledeclaration.rs | 85 ++++---- components/script/dom/htmlelement.rs | 4 +- components/script/dom/node.rs | 2 +- components/style/lib.rs | 4 +- components/style/properties/common_types.rs | 121 +++++++++++- components/style/properties/mod.rs.mako | 196 ++++++++++++++++++- tests/html/test_style.html | 7 + 8 files changed, 375 insertions(+), 55 deletions(-) create mode 100644 tests/html/test_style.html 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) -> CSS2Properties { CSS2Properties { - cssstyledeclaration: CSSStyleDeclaration::new_inherited(), + cssstyledeclaration: CSSStyleDeclaration::new_inherited(Some(owner)), } } - pub fn new(global: &JSRef) -> Temporary { - reflect_dom_object(box CSS2Properties::new_inherited(), - global::Window(*global), + pub fn new(global: JSRef, owner: JSRef) -> Temporary { + 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>, } -fn get_longhands_from_shorthand(shorthand: &Atom) -> Vec { - 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) -> DOMString { - let mut result = property; - result.push_str(": "); +fn serialize_list(list: &Vec) -> 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 { - None +fn serialize_value(declaration: &PropertyDeclaration) -> DOMString { + declaration.value().unwrap() } impl CSSStyleDeclaration { - pub fn new_inherited() -> CSSStyleDeclaration { + pub fn new_inherited(owner: Option>) -> 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; +} + +impl<'a> PrivateCSSStyleDeclarationHelpers for JSRef<'a, CSSStyleDeclaration> { + fn get_declaration(self, property: &Atom) -> Option { + self.owner.root().and_then(|owner| { + let element: JSRef = 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 { 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 = 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, - _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 { @@ -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 { @@ -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 { @@ -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 { @@ -296,6 +349,16 @@ pub mod specified { pub stops: Vec, } + 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, } + 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 { 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 | | | pub fn from_component_value(input: &ComponentValue, _base_url: &Url) -> Result { @@ -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 /// | | 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), } + 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: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; + /*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 { @@ -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; @@ -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 { // depending on whether the property is inherited. } +impl DeclaredValue { + pub fn specified_value(&self) -> Option { + 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 { + 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, base_url: &Url, @@ -2964,6 +3144,18 @@ pub fn cascade_anonymous(parent_style: &ComputedValues) -> ComputedValues { result } +pub fn longhands_from_shorthand(shorthand: &str) -> Option> { + 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 @@ +
+ From 6f8a9b6d46779ed0f7a5296af1c2173ca2910c38 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sat, 20 Sep 2014 20:37:05 -0400 Subject: [PATCH 06/20] Implement setting element style properties. Improve serialization to return initial values when unspecified. --- components/script/dom/cssstyledeclaration.rs | 77 ++++++++++++++++---- components/script/dom/element.rs | 37 ++++++++++ components/style/lib.rs | 1 + components/style/properties/common_types.rs | 47 ++++++++++++ components/style/properties/mod.rs.mako | 67 ++++++++++++++++- tests/html/test_style.html | 9 ++- 6 files changed, 218 insertions(+), 20 deletions(-) diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index a2eb7e152d6..062ecdc0c81 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -3,16 +3,20 @@ * 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::codegen::InheritTypes::{NodeCast, ElementCast}; use dom::bindings::error::{ErrorResult, Fallible}; use dom::bindings::js::{JS, JSRef, OptionalRootedRootable}; use dom::bindings::utils::{Reflectable, Reflector}; +use dom::document::DocumentHelpers; use dom::element::{Element, ElementHelpers}; use dom::htmlelement::HTMLElement; +use dom::node::{document_from_node, NodeDamage, Node}; use servo_util::str::DOMString; -use string_cache::atom::Atom; -use style::longhands_from_shorthand; +use string_cache::Atom; +use style::{is_supported_property, longhands_from_shorthand, parse_style_attribute}; use style::PropertyDeclaration; +use url::Url; + use std::ascii::AsciiExt; #[dom_struct] @@ -31,7 +35,7 @@ fn serialize_list(list: &Vec) -> DOMString { } fn serialize_value(declaration: &PropertyDeclaration) -> DOMString { - declaration.value().unwrap() + declaration.value() } impl CSSStyleDeclaration { @@ -51,15 +55,7 @@ impl<'a> PrivateCSSStyleDeclarationHelpers for JSRef<'a, CSSStyleDeclaration> { fn get_declaration(self, property: &Atom) -> Option { self.owner.root().and_then(|owner| { let element: JSRef = 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 - }) + element.get_inline_style_declaration(property).map(|decl| decl.clone()) }) } } @@ -131,7 +127,60 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { Ok(()) } - fn SetPropertyValue(self, _property: DOMString, _value: DOMString) -> ErrorResult { + fn SetPropertyValue(self, property: DOMString, value: DOMString) -> ErrorResult { + // 1. If the readonly flag is set, throw a NoModificationAllowedError exception + // and terminate these steps. + //TODO + + // 2. Let property be property converted to ASCII lowercase. + let property = Atom::from_slice(property.as_slice().to_ascii_lower().as_slice()); + + // 3. If property is not a case-sensitive match for a supported CSS property, + // terminate this algorithm. + if !is_supported_property(property.as_slice()) { + return Ok(()); + } + + // 4. If value is the empty string, invoke removeProperty() with property as argument + // and terminate this algorithm. + if value.is_empty() { + //TODO: self.RemoveProperty(property) + return Ok(()); + } + + // 5. Let component value list be the result of parsing value for property property. + let mut synthesized_declaration = property.as_slice().to_string(); + synthesized_declaration.push_str(": "); + synthesized_declaration.push_str(value.as_slice()); + //XXXjdm need page url + let decl_block = parse_style_attribute(synthesized_declaration.as_slice(), + &Url::parse("http://localhost").unwrap()); + + // 6. If component value list is null terminate these steps. + if decl_block.normal.len() == 0 { + return Ok(()); + } + + let owner = self.owner.root(); + let element: JSRef = ElementCast::from_ref(**owner.as_ref().unwrap()); + + assert!(decl_block.important.len() == 0); + for decl in decl_block.normal.iter() { + // 7. If property is a shorthand property, then for each longhand property + // longhand that property maps to, in canonical order, set the CSS + // declaration value longhand to the appropriate value(s) from component + // value list, and with the list of declarations being the declarations. + + // 8. Otherwise, set the CSS declaration value property to the + // value component value list, and with the list of declarations + // being the declarations. + + element.update_inline_style(decl.clone()); + } + + let document = document_from_node(element).root(); + let node: JSRef = NodeCast::from_ref(element); + document.content_changed(node, NodeDamage::NodeStyleDamaged); Ok(()) } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index ec97ee451e5..385585b6f95 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -60,6 +60,7 @@ use std::ascii::AsciiExt; use std::cell::{Ref, RefMut}; use std::default::Default; use std::mem; +use std::sync::Arc; use string_cache::{Atom, Namespace, QualName}; use url::UrlParser; @@ -465,6 +466,8 @@ pub trait ElementHelpers<'a> { fn style_attribute(self) -> &'a DOMRefCell>; fn summarize(self) -> Vec; fn is_void(self) -> bool; + fn update_inline_style(self, property_decl: style::PropertyDeclaration); + fn get_inline_style_declaration(self, property: &Atom) -> Option; } impl<'a> ElementHelpers<'a> for JSRef<'a, Element> { @@ -522,6 +525,40 @@ impl<'a> ElementHelpers<'a> for JSRef<'a, Element> { _ => false } } + + fn update_inline_style(self, property_decl: style::PropertyDeclaration) { + let mut inline_declarations = self.style_attribute.borrow_mut(); + let exists = inline_declarations.is_some(); + if exists { + let declarations = inline_declarations.as_mut().unwrap(); + for declaration in declarations.normal.make_unique() + .iter_mut() + .chain(declarations.important.make_unique().iter_mut()) { + if declaration.name().as_slice() == property_decl.name().as_slice() { + *declaration = property_decl; + return; + } + } + declarations.normal.make_unique().push(property_decl); + } else { + *inline_declarations = Some(style::PropertyDeclarationBlock { + important: Arc::new(vec!()), + normal: Arc::new(vec!(property_decl)), + }); + } + } + + fn get_inline_style_declaration(self, property: &Atom) -> Option { + let mut inline_declarations = self.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 + }) + } } pub trait AttributeHandlers { diff --git a/components/style/lib.rs b/components/style/lib.rs index f3cf3c843e2..fec6c2d5b61 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -43,6 +43,7 @@ pub use selector_matching::{matches, matches_simple_selector, common_style_affec 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, longhands_from_shorthand}; +pub use properties::is_supported_property; 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 52309ad41b6..245654bd118 100644 --- a/components/style/properties/common_types.rs +++ b/components/style/properties/common_types.rs @@ -650,6 +650,15 @@ pub mod computed { Percentage(CSSFloat), Auto, } + impl fmt::Show for LengthOrPercentageOrAuto { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &LengthOrPercentageOrAuto::Length(length) => write!(f, "{}", length), + &LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage), + &LengthOrPercentageOrAuto::Auto => write!(f, "auto"), + } + } + } #[allow(non_snake_case)] pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto, context: &Context) -> LengthOrPercentageOrAuto { @@ -669,6 +678,15 @@ pub mod computed { Percentage(CSSFloat), None, } + impl fmt::Show for LengthOrPercentageOrNone { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &LengthOrPercentageOrNone::Length(length) => write!(f, "{}", length), + &LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage), + &LengthOrPercentageOrNone::None => write!(f, "none"), + } + } + } #[allow(non_snake_case)] pub fn compute_LengthOrPercentageOrNone(value: specified::LengthOrPercentageOrNone, context: &Context) -> LengthOrPercentageOrNone { @@ -689,6 +707,15 @@ pub mod computed { LinearGradient(LinearGradient), } + impl fmt::Show for Image { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Image::Url(ref url) => write!(f, "url({})", url), + &Image::LinearGradient(ref grad) => write!(f, "linear-gradient({})", grad), + } + } + } + /// Computed values for a CSS linear gradient. #[deriving(Clone, PartialEq)] pub struct LinearGradient { @@ -699,6 +726,16 @@ pub mod computed { pub stops: Vec, } + impl fmt::Show for LinearGradient { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let _ = write!(f, "{}", self.angle_or_corner); + for stop in self.stops.iter() { + let _ = write!(f, ", {}", stop); + } + Ok(()) + } + } + /// Computed values for one color stop in a linear gradient. #[deriving(Clone, PartialEq)] pub struct ColorStop { @@ -710,6 +747,16 @@ pub mod computed { pub position: Option, } + impl fmt::Show for ColorStop { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let _ = write!(f, "{}", self.color); + self.position.map(|pos| { + let _ = write!(f, " {}", pos); + }); + Ok(()) + } + } + impl LinearGradient { pub fn compute(value: specified::LinearGradient, context: &Context) -> LinearGradient { let specified::LinearGradient { diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako index 9bb5b8a49fc..003800069e6 100644 --- a/components/style/properties/mod.rs.mako +++ b/components/style/properties/mod.rs.mako @@ -593,12 +593,22 @@ pub mod longhands { } pub mod computed_value { use super::super::{Au, CSSFloat}; + use std::fmt; #[deriving(PartialEq, Clone)] pub enum T { Normal, Length(Au), Number(CSSFloat), } + impl fmt::Show for T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &T::Normal => write!(f, "normal"), + &T::Length(length) => write!(f, "{}%", length), + &T::Number(number) => write!(f, "{}", number), + } + } + } } #[inline] pub fn get_initial_value() -> computed_value::T { T::Normal } @@ -656,6 +666,7 @@ pub mod longhands { } pub mod computed_value { use super::super::{Au, CSSFloat}; + use std::fmt; #[allow(non_camel_case_types)] #[deriving(PartialEq, Clone)] pub enum T { @@ -665,6 +676,17 @@ pub mod longhands { Length(Au), Percentage(CSSFloat), } + impl fmt::Show for T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + % for keyword in vertical_align_keywords: + &T::${to_rust_ident(keyword)} => write!(f, "${keyword}"), + % endfor + &T::Length(length) => write!(f, "{}", length), + &T::Percentage(number) => write!(f, "{}%", number), + } + } + } } #[inline] pub fn get_initial_value() -> computed_value::T { T::baseline } @@ -1143,12 +1165,22 @@ pub mod longhands { } } pub mod computed_value { + use std::fmt; #[deriving(PartialEq, Clone)] pub enum T { % for weight in range(100, 901, 100): Weight${weight}, % endfor } + impl fmt::Show for T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + % for weight in range(100, 901, 100): + &T::Weight${weight} => write!(f, "{}", ${weight}i), + % endfor + } + } + } impl T { pub fn is_bold(self) -> bool { match self { @@ -1672,6 +1704,7 @@ pub mod longhands { pub mod computed_value { use super::super::Au; use super::super::super::computed; + use std::fmt; pub type T = Vec; @@ -1684,6 +1717,17 @@ pub mod longhands { pub color: computed::CSSColor, pub inset: bool, } + + impl fmt::Show for BoxShadow { + 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, self.color); + Ok(()) + } + } } #[inline] @@ -2456,7 +2500,8 @@ impl DeclaredValue { pub fn specified_value(&self) -> Option { match self { &DeclaredValue::SpecifiedValue(ref inner) => Some(format!("{}", inner)), - _ => None, + &DeclaredValue::Initial => None, + &DeclaredValue::Inherit => Some("inherit".to_string()), } } } @@ -2488,14 +2533,16 @@ impl PropertyDeclaration { } } - pub fn value(&self) -> Option { + pub fn value(&self) -> String { match self { % for property in LONGHANDS: % if property.derived_from is None: - &PropertyDeclaration::${property.camel_case}Declaration(ref value) => value.specified_value(), + &PropertyDeclaration::${property.camel_case}Declaration(ref value) => + value.specified_value() + .unwrap_or_else(|| format!("{}", longhands::${property.ident}::get_initial_value())), % endif % endfor - _ => None, + decl => panic!("unsupported property declaration: {}", decl.name()), } } @@ -3144,6 +3191,18 @@ pub fn cascade_anonymous(parent_style: &ComputedValues) -> ComputedValues { result } +pub fn is_supported_property(property: &str) -> bool { + match property { + % for property in SHORTHANDS: + "${property.name}" => true, + % endfor + % for property in LONGHANDS: + "${property.name}" => true, + % endfor + _ => false, + } +} + pub fn longhands_from_shorthand(shorthand: &str) -> Option> { match shorthand { % for property in SHORTHANDS: diff --git a/tests/html/test_style.html b/tests/html/test_style.html index 362dae2e0dc..a9226ade0d5 100644 --- a/tests/html/test_style.html +++ b/tests/html/test_style.html @@ -1,6 +1,11 @@ -
+
test text!
+ + + +
+ + + From 442c28d9f7c3ed5561e391486714c11f7d0d1835 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Thu, 2 Oct 2014 09:31:38 +1000 Subject: [PATCH 09/20] Fixups for rust upgrade and jsref changes. --- components/style/properties/mod.rs.mako | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako index d4b78651b33..17ba476a345 100644 --- a/components/style/properties/mod.rs.mako +++ b/components/style/properties/mod.rs.mako @@ -839,8 +839,6 @@ pub mod longhands { pub mod computed_value { use super::super::super::common_types::computed; pub type T = Option; - //#[deriving(Clone, PartialEq)] - //pub type T = super::SpecifiedValue; } #[deriving(Clone)] pub type SpecifiedValue = common_specified::CSSImage; From 037f6c2cae30d1ca96df00ebb2d95abbb1d8c913 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Tue, 21 Oct 2014 09:11:52 +1000 Subject: [PATCH 10/20] Rebase and update new css properties. --- components/style/properties/mod.rs.mako | 1 + 1 file changed, 1 insertion(+) diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako index 17ba476a345..cfa47473fe0 100644 --- a/components/style/properties/mod.rs.mako +++ b/components/style/properties/mod.rs.mako @@ -467,6 +467,7 @@ pub mod longhands { pub type SpecifiedValue = computed_value::T; pub mod computed_value { use std::fmt; + #[deriving(PartialEq, Clone)] pub enum T { Auto, From abca00009cd8b7b7956ea56d07efbbf6c5acba62 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 27 Nov 2014 15:33:36 -0500 Subject: [PATCH 11/20] Add z-index support. --- components/script/dom/css2properties.rs | 3 +++ components/script/dom/webidls/CSS2Properties.webidl | 2 ++ 2 files changed, 5 insertions(+) diff --git a/components/script/dom/css2properties.rs b/components/script/dom/css2properties.rs index cb2a8f61a5e..9c00f596501 100644 --- a/components/script/dom/css2properties.rs +++ b/components/script/dom/css2properties.rs @@ -256,6 +256,9 @@ impl<'a> CSS2PropertiesMethods for JSRef<'a, CSS2Properties> { css_getter!(Right, "right") css_setter!(SetRight, "right") + css_getter!(ZIndex, "z-index") + css_setter!(SetZIndex, "z-index") + fn IndexedGetter(self, index: u32, found: &mut bool) -> DOMString { let decl: JSRef = CSSStyleDeclarationCast::from_ref(self); decl.IndexedGetter(index, found) diff --git a/components/script/dom/webidls/CSS2Properties.webidl b/components/script/dom/webidls/CSS2Properties.webidl index 603cc18dfd2..8341cce9926 100644 --- a/components/script/dom/webidls/CSS2Properties.webidl +++ b/components/script/dom/webidls/CSS2Properties.webidl @@ -100,4 +100,6 @@ interface CSS2Properties : CSSStyleDeclaration { [TreatNullAs=EmptyString] attribute DOMString width; [TreatNullAs=EmptyString] attribute DOMString minWidth; [TreatNullAs=EmptyString] attribute DOMString maxWidth; + + [TreatNullAs=EmptyString] attribute DOMString zIndex; }; From acf86a65e4005b7f53786424e6ac32d0ffa45004 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 27 Nov 2014 15:51:59 -0500 Subject: [PATCH 12/20] Move test_htmlelement_style.html out of the automatic tests because they don't all pass. --- tests/{content => html}/cssprops.js | 0 tests/{content => html}/test_htmlelement_style.html | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/{content => html}/cssprops.js (100%) rename tests/{content => html}/test_htmlelement_style.html (76%) diff --git a/tests/content/cssprops.js b/tests/html/cssprops.js similarity index 100% rename from tests/content/cssprops.js rename to tests/html/cssprops.js diff --git a/tests/content/test_htmlelement_style.html b/tests/html/test_htmlelement_style.html similarity index 76% rename from tests/content/test_htmlelement_style.html rename to tests/html/test_htmlelement_style.html index da821228252..778043e8494 100644 --- a/tests/content/test_htmlelement_style.html +++ b/tests/html/test_htmlelement_style.html @@ -1,6 +1,6 @@ - + From 9d82e06e6479ec963b0c42d2abf6a6c912a0cea2 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 11 Dec 2014 19:54:47 -0500 Subject: [PATCH 13/20] Implement RemoveProperty, SetProperty, and supported property indices. --- components/script/dom/css2properties.rs | 2 +- components/script/dom/cssstyledeclaration.rs | 161 ++++++++++++------ components/script/dom/element.rs | 57 ++++++- .../dom/webidls/CSSStyleDeclaration.webidl | 14 +- .../dom/webidls/ElementCSSInlineStyle.webidl | 2 +- components/style/properties/mod.rs.mako | 7 + 6 files changed, 173 insertions(+), 70 deletions(-) diff --git a/components/script/dom/css2properties.rs b/components/script/dom/css2properties.rs index 9c00f596501..a760e3b0364 100644 --- a/components/script/dom/css2properties.rs +++ b/components/script/dom/css2properties.rs @@ -40,7 +40,7 @@ macro_rules! css_setter( impl CSS2Properties { fn new_inherited(owner: JSRef) -> CSS2Properties { CSS2Properties { - cssstyledeclaration: CSSStyleDeclaration::new_inherited(Some(owner)), + cssstyledeclaration: CSSStyleDeclaration::new_inherited(owner), } } diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 062ecdc0c81..871fe865f0b 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -4,25 +4,25 @@ use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast}; -use dom::bindings::error::{ErrorResult, Fallible}; +use dom::bindings::error::ErrorResult; use dom::bindings::js::{JS, JSRef, OptionalRootedRootable}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::DocumentHelpers; use dom::element::{Element, ElementHelpers}; +use dom::node::window_from_node; use dom::htmlelement::HTMLElement; use dom::node::{document_from_node, NodeDamage, Node}; use servo_util::str::DOMString; use string_cache::Atom; use style::{is_supported_property, longhands_from_shorthand, parse_style_attribute}; use style::PropertyDeclaration; -use url::Url; use std::ascii::AsciiExt; #[dom_struct] pub struct CSSStyleDeclaration { reflector_: Reflector, - owner: Option>, + owner: JS, } fn serialize_list(list: &Vec) -> DOMString { @@ -39,10 +39,10 @@ fn serialize_value(declaration: &PropertyDeclaration) -> DOMString { } impl CSSStyleDeclaration { - pub fn new_inherited(owner: Option>) -> CSSStyleDeclaration { + pub fn new_inherited(owner: JSRef) -> CSSStyleDeclaration { CSSStyleDeclaration { reflector_: Reflector::new(), - owner: owner.map(|owner| JS::from_rooted(owner)), + owner: JS::from_rooted(owner), } } } @@ -53,28 +53,39 @@ trait PrivateCSSStyleDeclarationHelpers { impl<'a> PrivateCSSStyleDeclarationHelpers for JSRef<'a, CSSStyleDeclaration> { fn get_declaration(self, property: &Atom) -> Option { - self.owner.root().and_then(|owner| { - let element: JSRef = ElementCast::from_ref(*owner); - element.get_inline_style_declaration(property).map(|decl| decl.clone()) - }) + let owner = self.owner.root(); + let element: JSRef = ElementCast::from_ref(*owner); + element.get_inline_style_declaration(property).map(|decl| decl.clone()) } } impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { - fn CssText(self) -> DOMString { - "".to_string() - } - - fn SetCssText(self, _cssText: DOMString) -> ErrorResult { - Ok(()) - } - fn Length(self) -> u32 { - 0 + let owner = self.owner.root(); + let elem: JSRef = ElementCast::from_ref(*owner); + let style_attribute = elem.style_attribute().borrow(); + style_attribute.as_ref().map(|declarations| { + declarations.normal.len() + declarations.important.len() + }).unwrap_or(0) as u32 } - fn Item(self, _index: u32) -> DOMString { - "".to_string() + fn Item(self, index: u32) -> DOMString { + let owner = self.owner.root(); + let elem: JSRef = ElementCast::from_ref(*owner); + let style_attribute = elem.style_attribute().borrow(); + style_attribute.as_ref().and_then(|declarations| { + if index as uint > declarations.normal.len() { + declarations.important + .iter() + .nth(index as uint - declarations.normal.len()) + .map(|decl| format!("{} !important", decl)) + } else { + declarations.normal + .iter() + .nth(index as uint) + .map(|decl| format!("{}", decl)) + } + }).unwrap_or("".to_string()) } //http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue @@ -98,10 +109,10 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { // 2. If declaration is null, return the empty string and terminate these // steps. - //XXXjdm ambiguous? this suggests that if we're missing a longhand we return nothing at all. - if declaration.is_some() { + match declaration { // 3. Append the declaration to list. - list.push(declaration.unwrap()); + Some(declaration) => list.push(declaration), + None => return "".to_string(), } } @@ -114,26 +125,19 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { // declaration and terminate these steps. // 4. Return the empty string. let declaration = self.get_declaration(&property); - declaration.as_ref().map(|declaration| serialize_value(declaration)) + declaration.as_ref() + .map(|declaration| serialize_value(declaration)) .unwrap_or("".to_string()) } - fn GetPropertyPriority(self, _property: DOMString) -> DOMString { - "".to_string() - } - - fn SetProperty(self, _property: DOMString, _value: DOMString, - _priority: DOMString) -> ErrorResult { - Ok(()) - } - - fn SetPropertyValue(self, property: DOMString, value: DOMString) -> ErrorResult { + fn SetProperty(self, property: DOMString, value: DOMString, + priority: DOMString) -> ErrorResult { // 1. If the readonly flag is set, throw a NoModificationAllowedError exception // and terminate these steps. //TODO // 2. Let property be property converted to ASCII lowercase. - let property = Atom::from_slice(property.as_slice().to_ascii_lower().as_slice()); + let property = property.as_slice().to_ascii_lower(); // 3. If property is not a case-sensitive match for a supported CSS property, // terminate this algorithm. @@ -144,38 +148,50 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { // 4. If value is the empty string, invoke removeProperty() with property as argument // and terminate this algorithm. if value.is_empty() { - //TODO: self.RemoveProperty(property) + self.RemoveProperty(property.clone()); return Ok(()); } - // 5. Let component value list be the result of parsing value for property property. - let mut synthesized_declaration = property.as_slice().to_string(); + // 5. If priority is not the empty string and is not an ASCII case-insensitive match + // for the string "important", terminate this algorithm. + let priority = priority.as_slice().to_ascii_lower(); + if priority.as_slice() != "!important" && !priority.is_empty() { + return Ok(()); + } + + // 6. Let `component value list` be the result of parsing value for property `property`. + let mut synthesized_declaration = String::from_str(property.as_slice()); synthesized_declaration.push_str(": "); synthesized_declaration.push_str(value.as_slice()); - //XXXjdm need page url - let decl_block = parse_style_attribute(synthesized_declaration.as_slice(), - &Url::parse("http://localhost").unwrap()); - // 6. If component value list is null terminate these steps. + let owner = self.owner.root(); + let window = window_from_node(*owner).root(); + let page = window.page(); + let decl_block = parse_style_attribute(synthesized_declaration.as_slice(), + &page.get_url()); + + // 7. If `component value list` is null terminate these steps. if decl_block.normal.len() == 0 { return Ok(()); } let owner = self.owner.root(); - let element: JSRef = ElementCast::from_ref(**owner.as_ref().unwrap()); + let element: JSRef = ElementCast::from_ref(*owner); + //XXXjdm https://www.w3.org/Bugs/Public/show_bug.cgi?id=27589 assert!(decl_block.important.len() == 0); + for decl in decl_block.normal.iter() { - // 7. If property is a shorthand property, then for each longhand property + // 8. If property is a shorthand property, then for each longhand property // longhand that property maps to, in canonical order, set the CSS // declaration value longhand to the appropriate value(s) from component // value list, and with the list of declarations being the declarations. - // 8. Otherwise, set the CSS declaration value property to the + // 9. Otherwise, set the CSS declaration value property to the // value component value list, and with the list of declarations // being the declarations. - element.update_inline_style(decl.clone()); + element.update_inline_style(decl.clone(), !priority.is_empty()); } let document = document_from_node(element).root(); @@ -184,16 +200,57 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { Ok(()) } - fn SetPropertyPriority(self, _property: DOMString, _priority: DOMString) -> ErrorResult { - Ok(()) + fn SetPropertyValue(self, property: DOMString, value: DOMString) -> ErrorResult { + self.SetProperty(property, value, "".to_string()) } - fn RemoveProperty(self, _property: DOMString) -> Fallible { - Ok("".to_string()) + fn RemoveProperty(self, property: DOMString) -> DOMString { + // 1. If the readonly flag is set, throw a NoModificationAllowedError exception + // and terminate these steps. + //TODO + + // 2. Let `property` be property converted to ASCII lowercase. + let property = property.as_slice().to_ascii_lower(); + + // 3. Let `value` be the return value of invoking getPropertyValue() with `property` + // as argument. + let value = self.GetPropertyValue(property.clone()); + + // 4. If `property` is a shorthand property, for each longhand property `longhand` that + // `property` maps to, invoke removeProperty() with `longhand` as argument. + let longhand_properties = longhands_from_shorthand(property.as_slice()); + match longhand_properties { + Some(longhands) => { + for longhand in longhands.iter() { + self.RemoveProperty(longhand.clone()); + } + } + + // 5. Otherwise, if `property` is a case-sensitive match for a property name of a + // CSS declaration in the declarations, remove that CSS declaration. + None => { + let owner = self.owner.root(); + let elem: JSRef = ElementCast::from_ref(*owner); + elem.remove_inline_style_property(property) + } + } + + // 6. Return value. + value } - fn IndexedGetter(self, _index: u32, _found: &mut bool) -> DOMString { - "".to_string() + fn CssFloat(self) -> DOMString { + self.GetPropertyValue("float".to_string()) + } + + fn SetCssFloat(self, value: DOMString) -> ErrorResult { + self.SetPropertyValue("float".to_string(), value) + } + + fn IndexedGetter(self, index: u32, found: &mut bool) -> DOMString { + let rval = self.Item(index); + *found = index < self.Length(); + rval } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index cbb3bf74027..fa4d6d5c08a 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -466,7 +466,8 @@ pub trait ElementHelpers<'a> { fn style_attribute(self) -> &'a DOMRefCell>; fn summarize(self) -> Vec; fn is_void(self) -> bool; - fn update_inline_style(self, property_decl: style::PropertyDeclaration); + fn remove_inline_style_property(self, property: DOMString); + fn update_inline_style(self, property_decl: style::PropertyDeclaration, important: bool); fn get_inline_style_declaration(self, property: &Atom) -> Option; } @@ -526,26 +527,64 @@ impl<'a> ElementHelpers<'a> for JSRef<'a, Element> { } } - fn update_inline_style(self, property_decl: style::PropertyDeclaration) { + fn remove_inline_style_property(self, property: DOMString) { + //FIXME: Rust bug incorrectly thinks inline_declarations doesn't need mut, + // and allow(unused_mut) on this method does nothing. + let mut inline_declarations = self.style_attribute.borrow_mut(); + inline_declarations.as_mut().map(|declarations| { + let index = declarations.normal + .iter() + .position(|decl| decl.name() == property); + match index { + Some(index) => { + declarations.normal.make_unique().remove(index); + return; + } + None => () + } + + let index = declarations.important + .iter() + .position(|decl| decl.name() == property); + match index { + Some(index) => { + declarations.important.make_unique().remove(index); + return; + } + None => () + } + }); + } + + fn update_inline_style(self, property_decl: style::PropertyDeclaration, important: bool) { //FIXME: Rust bug incorrectly thinks inline_declarations doesn't need mut, // and allow(unused_mut) on this method does nothing. let mut inline_declarations = self.style_attribute.borrow_mut(); let exists = inline_declarations.is_some(); if exists { let declarations = inline_declarations.deref_mut().as_mut().unwrap(); - for declaration in declarations.normal.make_unique() - .iter_mut() - .chain(declarations.important.make_unique().iter_mut()) { - if declaration.name().as_slice() == property_decl.name().as_slice() { + let mut existing_declarations = if important { + declarations.important.clone() + } else { + declarations.normal.clone() + }; + for declaration in existing_declarations.make_unique().iter_mut() { + if declaration.name() == property_decl.name() { *declaration = property_decl; return; } } - declarations.normal.make_unique().push(property_decl); + existing_declarations.make_unique().push(property_decl); } else { + let (important, normal) = if important { + (vec!(property_decl), vec!()) + } else { + (vec!(), vec!(property_decl)) + }; + *inline_declarations = Some(style::PropertyDeclarationBlock { - important: Arc::new(vec!()), - normal: Arc::new(vec!(property_decl)), + important: Arc::new(important), + normal: Arc::new(normal), }); } } diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl index 09079fe0fec..75b4bbeffc9 100644 --- a/components/script/dom/webidls/CSSStyleDeclaration.webidl +++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl @@ -9,23 +9,23 @@ */ interface CSSStyleDeclaration { - [SetterThrows] - attribute DOMString cssText; + //[SetterThrows] + // attribute DOMString cssText; readonly attribute unsigned long length; getter DOMString item(unsigned long index); DOMString getPropertyValue(DOMString property); - DOMString getPropertyPriority(DOMString property); + //DOMString getPropertyPriority(DOMString property); [Throws] void setProperty(DOMString property, [TreatNullAs=EmptyString] DOMString value, [TreatNullAs=EmptyString] optional DOMString priority = ""); [Throws] void setPropertyValue(DOMString property, [TreatNullAs=EmptyString] DOMString value); - [Throws] - void setPropertyPriority(DOMString property, [TreatNullAs=EmptyString] DOMString priority); - [Throws] + //[Throws] + //void setPropertyPriority(DOMString property, [TreatNullAs=EmptyString] DOMString priority); DOMString removeProperty(DOMString property); // Not implemented yet: // readonly attribute CSSRule? parentRule; -// attribute DOMString cssFloat; + [SetterThrows] + attribute DOMString cssFloat; }; diff --git a/components/script/dom/webidls/ElementCSSInlineStyle.webidl b/components/script/dom/webidls/ElementCSSInlineStyle.webidl index 85e14fab10e..bf7a7b92b9e 100644 --- a/components/script/dom/webidls/ElementCSSInlineStyle.webidl +++ b/components/script/dom/webidls/ElementCSSInlineStyle.webidl @@ -7,5 +7,5 @@ [NoInterfaceObject] interface ElementCSSInlineStyle { - [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style; + [SameObject/*, PutForwards=cssText*/] readonly attribute CSSStyleDeclaration style; }; diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako index cfa47473fe0..d1301681449 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; use std::fmt::Show; use servo_util::logical_geometry::{WritingMode, LogicalMargin}; @@ -2673,6 +2674,12 @@ impl PropertyDeclaration { } } +impl Show for PropertyDeclaration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}: {}", self.name(), self.value()) + } +} + pub mod style_structs { use super::longhands; From 3cfe8ab53e200eddc8d2bda8ad6c118b7761188c Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 12 Dec 2014 12:58:42 -0500 Subject: [PATCH 14/20] Address review comments. --- components/script/dom/cssstyledeclaration.rs | 119 ++++++++---------- components/script/dom/element.rs | 57 ++++----- components/script/dom/htmlelement.rs | 10 +- components/script/dom/node.rs | 2 +- .../script/dom/webidls/CSS2Properties.webidl | 3 +- .../dom/webidls/CSSStyleDeclaration.webidl | 3 +- components/script/lib.rs | 2 +- tests/content/harness.js | 6 +- tests/html/cssprops.js | 7 +- tests/html/test_style.html | 4 +- 10 files changed, 92 insertions(+), 121 deletions(-) diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 871fe865f0b..7a69990cc21 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -63,103 +63,95 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { fn Length(self) -> u32 { let owner = self.owner.root(); let elem: JSRef = ElementCast::from_ref(*owner); - let style_attribute = elem.style_attribute().borrow(); - style_attribute.as_ref().map(|declarations| { - declarations.normal.len() + declarations.important.len() - }).unwrap_or(0) as u32 + let len = match *elem.style_attribute().borrow() { + Some(ref declarations) => declarations.normal.len() + declarations.important.len(), + None => 0 + }; + len as u32 } fn Item(self, index: u32) -> DOMString { let owner = self.owner.root(); let elem: JSRef = ElementCast::from_ref(*owner); let style_attribute = elem.style_attribute().borrow(); - style_attribute.as_ref().and_then(|declarations| { + let result = style_attribute.as_ref().and_then(|declarations| { if index as uint > declarations.normal.len() { declarations.important - .iter() - .nth(index as uint - declarations.normal.len()) + .as_slice() + .get(index as uint - declarations.normal.len()) .map(|decl| format!("{} !important", decl)) } else { declarations.normal - .iter() - .nth(index as uint) + .as_slice() + .get(index as uint) .map(|decl| format!("{}", decl)) } - }).unwrap_or("".to_string()) + }); + + result.unwrap_or("".to_string()) } - //http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue + // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue fn GetPropertyValue(self, property: DOMString) -> DOMString { - // 1. Let property be property converted to ASCII lowercase. + // Step 1 let property = Atom::from_slice(property.as_slice().to_ascii_lower().as_slice()); - // 2. If property is a shorthand property, then follow these substeps: + // Step 2 let longhand_properties = longhands_from_shorthand(property.as_slice()); - if longhand_properties.is_some() { - // 1. Let list be a new empty array. + if let Some(longhand_properties) = longhand_properties { + // Step 2.1 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.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. + // Step 2.2 + for longhand in longhand_properties.iter() { + // Step 2.2.1 let declaration = self.get_declaration(&Atom::from_slice(longhand.as_slice())); - // 2. If declaration is null, return the empty string and terminate these - // steps. + // Step 2.2.2 & 2.2.3 match declaration { - // 3. Append the declaration to list. Some(declaration) => list.push(declaration), None => return "".to_string(), } } - // 3. Return the serialization of list and terminate these steps. + // Step 2.3 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 = self.get_declaration(&property); - declaration.as_ref() - .map(|declaration| serialize_value(declaration)) - .unwrap_or("".to_string()) + // Step 3 & 4 + if let Some(ref declaration) = self.get_declaration(&property) { + serialize_value(declaration) + } else { + "".to_string() + } } + // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty fn SetProperty(self, property: DOMString, value: DOMString, priority: DOMString) -> ErrorResult { - // 1. If the readonly flag is set, throw a NoModificationAllowedError exception - // and terminate these steps. - //TODO + //TODO: disallow modifications if readonly flag is set - // 2. Let property be property converted to ASCII lowercase. + // Step 2 let property = property.as_slice().to_ascii_lower(); - // 3. If property is not a case-sensitive match for a supported CSS property, - // terminate this algorithm. + // Step 3 if !is_supported_property(property.as_slice()) { return Ok(()); } - // 4. If value is the empty string, invoke removeProperty() with property as argument - // and terminate this algorithm. + // Step 4 if value.is_empty() { - self.RemoveProperty(property.clone()); + self.RemoveProperty(property); return Ok(()); } - // 5. If priority is not the empty string and is not an ASCII case-insensitive match - // for the string "important", terminate this algorithm. + // Step 5 let priority = priority.as_slice().to_ascii_lower(); if priority.as_slice() != "!important" && !priority.is_empty() { return Ok(()); } - // 6. Let `component value list` be the result of parsing value for property `property`. + // Step 6 let mut synthesized_declaration = String::from_str(property.as_slice()); synthesized_declaration.push_str(": "); synthesized_declaration.push_str(value.as_slice()); @@ -170,7 +162,7 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { let decl_block = parse_style_attribute(synthesized_declaration.as_slice(), &page.get_url()); - // 7. If `component value list` is null terminate these steps. + // Step 7 if decl_block.normal.len() == 0 { return Ok(()); } @@ -178,19 +170,9 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { let owner = self.owner.root(); let element: JSRef = ElementCast::from_ref(*owner); - //XXXjdm https://www.w3.org/Bugs/Public/show_bug.cgi?id=27589 - assert!(decl_block.important.len() == 0); - + // Step 8 for decl in decl_block.normal.iter() { - // 8. If property is a shorthand property, then for each longhand property - // longhand that property maps to, in canonical order, set the CSS - // declaration value longhand to the appropriate value(s) from component - // value list, and with the list of declarations being the declarations. - - // 9. Otherwise, set the CSS declaration value property to the - // value component value list, and with the list of declarations - // being the declarations. - + // Step 9 element.update_inline_style(decl.clone(), !priority.is_empty()); } @@ -200,49 +182,48 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { Ok(()) } + // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertyvalue fn SetPropertyValue(self, property: DOMString, value: DOMString) -> ErrorResult { self.SetProperty(property, value, "".to_string()) } + // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-removeproperty fn RemoveProperty(self, property: DOMString) -> DOMString { - // 1. If the readonly flag is set, throw a NoModificationAllowedError exception - // and terminate these steps. - //TODO + //TODO: disallow modifications if readonly flag is set - // 2. Let `property` be property converted to ASCII lowercase. + // Step 2 let property = property.as_slice().to_ascii_lower(); - // 3. Let `value` be the return value of invoking getPropertyValue() with `property` - // as argument. + // Step 3 let value = self.GetPropertyValue(property.clone()); - // 4. If `property` is a shorthand property, for each longhand property `longhand` that - // `property` maps to, invoke removeProperty() with `longhand` as argument. let longhand_properties = longhands_from_shorthand(property.as_slice()); match longhand_properties { Some(longhands) => { + // Step 4 for longhand in longhands.iter() { self.RemoveProperty(longhand.clone()); } } - // 5. Otherwise, if `property` is a case-sensitive match for a property name of a - // CSS declaration in the declarations, remove that CSS declaration. None => { + // Step 5 let owner = self.owner.root(); let elem: JSRef = ElementCast::from_ref(*owner); elem.remove_inline_style_property(property) } } - // 6. Return value. + // Step 6 value } + // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat fn CssFloat(self) -> DOMString { self.GetPropertyValue("float".to_string()) } + // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat fn SetCssFloat(self, value: DOMString) -> ErrorResult { self.SetPropertyValue("float".to_string(), value) } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index fa4d6d5c08a..06de6d4ce29 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -528,8 +528,6 @@ impl<'a> ElementHelpers<'a> for JSRef<'a, Element> { } fn remove_inline_style_property(self, property: DOMString) { - //FIXME: Rust bug incorrectly thinks inline_declarations doesn't need mut, - // and allow(unused_mut) on this method does nothing. let mut inline_declarations = self.style_attribute.borrow_mut(); inline_declarations.as_mut().map(|declarations| { let index = declarations.normal @@ -557,47 +555,44 @@ impl<'a> ElementHelpers<'a> for JSRef<'a, Element> { } fn update_inline_style(self, property_decl: style::PropertyDeclaration, important: bool) { - //FIXME: Rust bug incorrectly thinks inline_declarations doesn't need mut, - // and allow(unused_mut) on this method does nothing. - let mut inline_declarations = self.style_attribute.borrow_mut(); - let exists = inline_declarations.is_some(); - if exists { - let declarations = inline_declarations.deref_mut().as_mut().unwrap(); - let mut existing_declarations = if important { - declarations.important.clone() + let mut inline_declarations = self.style_attribute().borrow_mut(); + if let Some(ref mut declarations) = *inline_declarations.deref_mut() { + let existing_declarations = if important { + declarations.important.make_unique() } else { - declarations.normal.clone() + declarations.normal.make_unique() }; - for declaration in existing_declarations.make_unique().iter_mut() { + + for declaration in existing_declarations.iter_mut() { if declaration.name() == property_decl.name() { *declaration = property_decl; return; } } - existing_declarations.make_unique().push(property_decl); - } else { - let (important, normal) = if important { - (vec!(property_decl), vec!()) - } else { - (vec!(), vec!(property_decl)) - }; - - *inline_declarations = Some(style::PropertyDeclarationBlock { - important: Arc::new(important), - normal: Arc::new(normal), - }); + existing_declarations.push(property_decl); + return; } + + let (important, normal) = if important { + (vec!(property_decl), vec!()) + } else { + (vec!(), vec!(property_decl)) + }; + + *inline_declarations = Some(style::PropertyDeclarationBlock { + important: Arc::new(important), + normal: Arc::new(normal), + }); } fn get_inline_style_declaration(self, property: &Atom) -> Option { - let mut inline_declarations = self.style_attribute.borrow(); + let inline_declarations = self.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 + declarations.normal + .iter() + .chain(declarations.important.iter()) + .find(|decl| decl.matches(property.as_slice())) + .map(|decl| decl.clone()) }) } } diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index e37b37b3c55..48acd297574 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -72,13 +72,11 @@ impl<'a> PrivateHTMLElementHelpers for JSRef<'a, HTMLElement> { impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> { fn Style(self) -> Temporary { - if self.style_decl.get().is_none() { + self.style_decl.or_init(|| { let global = window_from_node(self).root(); - let style_props = CSS2Properties::new(*global, self).root(); - let style_decl: JSRef = CSSStyleDeclarationCast::from_ref(*style_props); - self.style_decl.assign(Some(style_decl)); - } - self.style_decl.get().unwrap() + let style_props = CSS2Properties::new(*global, self); + CSSStyleDeclarationCast::from_temporary(style_props) + }) } make_getter!(Title) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 234e1c8c707..50647862007 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, - pub shared_data: SharedLayoutData, + _shared_data: SharedLayoutData, _data: *const (), } diff --git a/components/script/dom/webidls/CSS2Properties.webidl b/components/script/dom/webidls/CSS2Properties.webidl index 8341cce9926..9e1832cfb25 100644 --- a/components/script/dom/webidls/CSS2Properties.webidl +++ b/components/script/dom/webidls/CSS2Properties.webidl @@ -4,7 +4,8 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://dev.w3.org/csswg/cssom/ + * http://mxr.mozilla.org/mozilla-central/source/dom/webidl/CSS2Properties.webidl.in + * http://mxr.mozilla.org/mozilla-central/source/dom/bindings/GenerateCSS2PropertiesWebIDL.py * */ diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl index 75b4bbeffc9..35b332ca736 100644 --- a/components/script/dom/webidls/CSSStyleDeclaration.webidl +++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl @@ -23,8 +23,7 @@ interface CSSStyleDeclaration { //[Throws] //void setPropertyPriority(DOMString property, [TreatNullAs=EmptyString] DOMString priority); DOMString removeProperty(DOMString property); -// Not implemented yet: -// readonly attribute CSSRule? parentRule; + //readonly attribute CSSRule? parentRule; [SetterThrows] attribute DOMString cssFloat; }; diff --git a/components/script/lib.rs b/components/script/lib.rs index a956a26d876..028cd333468 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -5,7 +5,7 @@ #![comment = "The Servo Parallel Browser Project"] #![license = "MPL"] -#![feature(default_type_params, globs, macro_rules, phase, unsafe_destructor)] +#![feature(default_type_params, globs, macro_rules, phase, unsafe_destructor, if_let)] #![deny(unused_imports)] #![deny(unused_variables)] diff --git a/tests/content/harness.js b/tests/content/harness.js index 8931e4bf65f..2738ca2e6a6 100644 --- a/tests/content/harness.js +++ b/tests/content/harness.js @@ -12,17 +12,17 @@ function expect(num) { function _fail(s, m) { _tests++; // string split to avoid problems with tests that end up printing the value of window._fail. - console.log(_oneline("TEST-UNEXPECTED" + "-FAIL | " + s + ": " + m)); + window.alert(_oneline("TEST-UNEXPECTED" + "-FAIL | " + s + ": " + m)); } function _pass(s, m) { _tests++; - //console.log(_oneline("TEST-PASS | " + s + ": " + m)); + window.alert(_oneline("TEST-PASS | " + s + ": " + m)); } function _printer(opstr, op) { return function (a, b, msg) { - var f = op(a,b) ? _pass : _fail; + let f = op(a,b) ? _pass : _fail; if (!msg) msg = ""; f(a + " " + opstr + " " + b, msg); }; diff --git a/tests/html/cssprops.js b/tests/html/cssprops.js index 21d0224535f..f96bd513709 100644 --- a/tests/html/cssprops.js +++ b/tests/html/cssprops.js @@ -3,10 +3,8 @@ function run_tests(properties) { var name = Object.keys(properties)[property]; var generator = create_value_generator(properties[name]); var prop = properties[name].property || name; - //setTimeout(function(name, generator, prop) { - while (run_test(name, generator, prop)) { - } - //}, 0, name, generator, prop); + while (run_test(name, generator, prop)) { + } } } @@ -85,7 +83,6 @@ function to_idl(property) { } function run_test(property, generator, prop) { - //console.log("testing " + property + ' ' + to_idl(property)); var elem = document.createElement('div'); document.getElementById('parent').appendChild(elem); var style = generate_inline_style(property, generator()); diff --git a/tests/html/test_style.html b/tests/html/test_style.html index 478d99b96ab..edf5012b304 100644 --- a/tests/html/test_style.html +++ b/tests/html/test_style.html @@ -1,9 +1,9 @@
test text!