diff options
author | David Zbarsky <dzbarsky@gmail.com> | 2015-07-27 23:05:18 -0400 |
---|---|---|
committer | David Zbarsky <dzbarsky@gmail.com> | 2015-07-29 20:17:50 -0400 |
commit | e484d6b5e3f378a33fabf5ff64cb9a7f76f3ba68 (patch) | |
tree | 49235a86cc3949b27d2262c8bfb11af5c964a249 /components/script | |
parent | 416931f4be43826d3b2a96905c22f626c88b603c (diff) | |
download | servo-e484d6b5e3f378a33fabf5ff64cb9a7f76f3ba68.tar.gz servo-e484d6b5e3f378a33fabf5ff64cb9a7f76f3ba68.zip |
Implement getComputedStyle
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 2 | ||||
-rw-r--r-- | components/script/dom/cssstyledeclaration.rs | 22 | ||||
-rw-r--r-- | components/script/dom/htmlelement.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/Window.webidl | 7 | ||||
-rw-r--r-- | components/script/dom/window.rs | 38 | ||||
-rw-r--r-- | components/script/layout_interface.rs | 7 |
6 files changed, 74 insertions, 4 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index ad8da0e41b0..741921af652 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -63,6 +63,7 @@ use msg::constellation_msg::ConstellationChan; use net_traits::image::base::Image; use profile_traits::mem::ProfilerChan; use util::str::{LengthOrPercentageOrAuto}; +use selectors::parser::PseudoElement; use serde::{Deserialize, Serialize}; use std::cell::{Cell, UnsafeCell, RefCell}; use std::collections::{HashMap, HashSet}; @@ -304,6 +305,7 @@ no_jsmanaged_fields!(LineCapStyle, LineJoinStyle, CompositionOrBlending); no_jsmanaged_fields!(RepetitionStyle); no_jsmanaged_fields!(WebGLError); no_jsmanaged_fields!(ProfilerChan); +no_jsmanaged_fields!(PseudoElement); impl JSTraceable for Box<ScriptChan+Send> { #[inline] diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index d3c1af656d4..99e70f9c387 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -11,9 +11,10 @@ use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::document::DocumentHelpers; use dom::element::{ElementHelpers, StylePriority}; use dom::htmlelement::HTMLElement; -use dom::node::{window_from_node, document_from_node, NodeDamage}; +use dom::node::{window_from_node, document_from_node, NodeDamage, NodeHelpers}; use dom::window::{Window, WindowHelpers}; use util::str::DOMString; +use selectors::parser::PseudoElement; use string_cache::Atom; use style::properties::{is_supported_property, longhands_from_shorthand, parse_style_attribute}; use style::properties::PropertyDeclaration; @@ -27,6 +28,7 @@ pub struct CSSStyleDeclaration { reflector_: Reflector, owner: JS<HTMLElement>, readonly: bool, + pseudo: Option<PseudoElement>, } #[derive(PartialEq)] @@ -56,17 +58,20 @@ fn serialize_list(list: &Vec<PropertyDeclaration>) -> DOMString { impl CSSStyleDeclaration { pub fn new_inherited(owner: &HTMLElement, + pseudo: Option<PseudoElement>, modification_access: CSSModificationAccess) -> CSSStyleDeclaration { CSSStyleDeclaration { reflector_: Reflector::new(), owner: JS::from_ref(owner), + pseudo: pseudo, readonly: modification_access == CSSModificationAccess::Readonly, } } pub fn new(global: &Window, owner: &HTMLElement, + pseudo: Option<PseudoElement>, modification_access: CSSModificationAccess) -> Root<CSSStyleDeclaration> { - reflect_dom_object(box CSSStyleDeclaration::new_inherited(owner, modification_access), + reflect_dom_object(box CSSStyleDeclaration::new_inherited(owner, pseudo, modification_access), GlobalRef::Window(global), CSSStyleDeclarationBinding::Wrap) } @@ -75,6 +80,7 @@ impl CSSStyleDeclaration { trait PrivateCSSStyleDeclarationHelpers { fn get_declaration(self, property: &Atom) -> Option<PropertyDeclaration>; fn get_important_declaration(self, property: &Atom) -> Option<PropertyDeclaration>; + fn get_computed_style(self, property: &Atom) -> Option<DOMString>; } impl<'a> PrivateCSSStyleDeclarationHelpers for &'a CSSStyleDeclaration { @@ -89,6 +95,13 @@ impl<'a> PrivateCSSStyleDeclarationHelpers for &'a CSSStyleDeclaration { let element = ElementCast::from_ref(owner.r()); element.get_important_inline_style_declaration(property).map(|decl| decl.clone()) } + + fn get_computed_style(self, property: &Atom) -> Option<DOMString> { + let owner = self.owner.root(); + let node = NodeCast::from_ref(owner.r()); + let addr = node.to_trusted_node_address(); + window_from_node(owner.r()).resolved_style_query(addr, self.pseudo.clone(), property) + } } impl<'a> CSSStyleDeclarationMethods for &'a CSSStyleDeclaration { @@ -129,6 +142,11 @@ impl<'a> CSSStyleDeclarationMethods for &'a CSSStyleDeclaration { // Step 1 let property = Atom::from_slice(&property.to_ascii_lowercase()); + if self.readonly { + // Readonly style declarations are used for getComputedStyle. + return self.get_computed_style(&property).unwrap_or("".to_owned()); + } + // Step 2 let longhand_properties = longhands_from_shorthand(&property); if let Some(longhand_properties) = longhand_properties { diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 85574373c30..513a9d39775 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -135,7 +135,7 @@ impl<'a> HTMLElementMethods for &'a HTMLElement { fn Style(self) -> Root<CSSStyleDeclaration> { self.style_decl.or_init(|| { let global = window_from_node(self); - CSSStyleDeclaration::new(global.r(), self, CSSModificationAccess::ReadWrite) + CSSStyleDeclaration::new(global.r(), self, None, CSSModificationAccess::ReadWrite) }) } diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index 54c112cec41..1fa85ffbe63 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -90,6 +90,13 @@ partial interface Window { /*[Replaceable]*/ readonly attribute Performance performance; }; +// https://drafts.csswg.org/cssom/#extensions-to-the-window-interface +partial interface Window { + //CSSStyleDeclaration getComputedStyle(Element elt, optional DOMString? pseudoElt); + [NewObject] + CSSStyleDeclaration getComputedStyle(HTMLElement elt, optional DOMString pseudoElt); +}; + // http://dev.w3.org/csswg/cssom-view/#extensions-to-the-window-interface partial interface Window { //MediaQueryList matchMedia(DOMString query); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index e00164d3c93..d4f2a36eabf 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -20,9 +20,11 @@ use dom::bindings::utils::{GlobalStaticData, Reflectable, WindowProxyHandler}; use dom::browsercontext::BrowsingContext; use dom::console::Console; use dom::crypto::Crypto; +use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration}; use dom::document::{Document, DocumentHelpers}; use dom::element::Element; use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; +use dom::htmlelement::HTMLElement; use dom::location::Location; use dom::navigator::Navigator; use dom::node::{window_from_node, TrustedNodeAddress, NodeHelpers}; @@ -30,7 +32,7 @@ use dom::performance::Performance; use dom::screen::Screen; use dom::storage::Storage; use layout_interface::{ReflowGoal, ReflowQueryType, LayoutRPC, LayoutChan, Reflow, Msg}; -use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ScriptReflow}; +use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ResolvedStyleResponse, ScriptReflow}; use page::Page; use script_task::{TimerSource, ScriptChan, ScriptPort, NonWorkerScriptChan}; use script_task::ScriptMsg; @@ -47,6 +49,7 @@ use net_traits::ResourceTask; use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask}; use net_traits::storage_task::{StorageTask, StorageType}; use profile_traits::mem; +use string_cache::Atom; use util::geometry::{self, Au, MAX_RECT}; use util::{breakpoint, opts}; use util::str::{DOMString,HTML_SPACE_CHARACTERS}; @@ -58,10 +61,12 @@ use js::jsapi::{JSContext, HandleValue}; use js::jsapi::{JS_GC, JS_GetRuntime, JSAutoCompartment, JSAutoRequest}; use js::rust::Runtime; use js::rust::CompileOptionsWrapper; +use selectors::parser::PseudoElement; use url::{Url, UrlParser}; use libc; use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD}; +use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::{Cell, Ref, RefMut, RefCell}; use std::collections::HashSet; @@ -539,6 +544,23 @@ impl<'a> WindowMethods for &'a Window { chan.send(Err(WebDriverJSError::Timeout)).unwrap(); } } + + // https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle + fn GetComputedStyle(self, + element: &HTMLElement, + pseudo: Option<DOMString>) -> Root<CSSStyleDeclaration> { + // Steps 1-4. + let pseudo = match pseudo.map(|s| s.to_ascii_lowercase()) { + Some(ref pseudo) if pseudo == ":before" || pseudo == "::before" => + Some(PseudoElement::Before), + Some(ref pseudo) if pseudo == ":after" || pseudo == "::after" => + Some(PseudoElement::After), + _ => None + }; + + // Step 5. + CSSStyleDeclaration::new(self, element, pseudo, CSSModificationAccess::Readonly) + } } pub trait WindowHelpers { @@ -553,6 +575,8 @@ pub trait WindowHelpers { fn content_box_query(self, content_box_request: TrustedNodeAddress) -> Rect<Au>; fn content_boxes_query(self, content_boxes_request: TrustedNodeAddress) -> Vec<Rect<Au>>; fn client_rect_query(self, node_geometry_request: TrustedNodeAddress) -> Rect<i32>; + fn resolved_style_query(self, element: TrustedNodeAddress, + pseudo: Option<PseudoElement>, property: &Atom) -> Option<String>; fn handle_reflow_complete_msg(self, reflow_id: u32); fn set_fragment_name(self, fragment: Option<String>); fn steal_fragment_name(self) -> Option<String>; @@ -791,6 +815,17 @@ impl<'a> WindowHelpers for &'a Window { self.layout_rpc.node_geometry().client_rect } + fn resolved_style_query(self, + element: TrustedNodeAddress, + pseudo: Option<PseudoElement>, + property: &Atom) -> Option<String> { + self.reflow(ReflowGoal::ForScriptQuery, + ReflowQueryType::ResolvedStyleQuery(element, pseudo, property.clone()), + ReflowReason::Query); + let ResolvedStyleResponse(resolved) = self.layout_rpc.resolved_style(); + resolved + } + fn handle_reflow_complete_msg(self, reflow_id: u32) { let last_reflow_id = self.last_reflow_id.get(); if last_reflow_id == reflow_id { @@ -1098,6 +1133,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason: ReflowQueryType::ContentBoxQuery(_n) => "\tContentBoxQuery", ReflowQueryType::ContentBoxesQuery(_n) => "\tContentBoxesQuery", ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery", + ReflowQueryType::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery", }); debug_msg.push_str(match *reason { diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index d94f6e4a581..092938b8797 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -21,8 +21,10 @@ use net_traits::PendingAsyncLoad; use profile_traits::mem::ReportsChan; use script_traits::{ConstellationControlMsg, LayoutControlMsg, ScriptControlChan}; use script_traits::{OpaqueScriptLayoutChannel, StylesheetLoadResponder, UntrustedNodeAddress}; +use selectors::parser::PseudoElement; use std::any::Any; use std::sync::mpsc::{channel, Receiver, Sender}; +use string_cache::Atom; use style::animation::PropertyAnimation; use style::media_queries::MediaQueryList; use style::stylesheets::Stylesheet; @@ -100,8 +102,11 @@ pub trait LayoutRPC { /// Requests the node containing the point of interest fn hit_test(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<HitTestResponse, ()>; fn mouse_over(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<MouseOverResponse, ()>; + /// Query layout for the resolved value of a given CSS property + fn resolved_style(&self) -> ResolvedStyleResponse; } + pub struct ContentBoxResponse(pub Rect<Au>); pub struct ContentBoxesResponse(pub Vec<Rect<Au>>); pub struct NodeGeometryResponse { @@ -109,6 +114,7 @@ pub struct NodeGeometryResponse { } pub struct HitTestResponse(pub UntrustedNodeAddress); pub struct MouseOverResponse(pub Vec<UntrustedNodeAddress>); +pub struct ResolvedStyleResponse(pub Option<String>); /// Why we're doing reflow. #[derive(PartialEq, Copy, Clone, Debug)] @@ -126,6 +132,7 @@ pub enum ReflowQueryType { ContentBoxQuery(TrustedNodeAddress), ContentBoxesQuery(TrustedNodeAddress), NodeGeometryQuery(TrustedNodeAddress), + ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, Atom), } /// Information needed for a reflow. |