aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorDavid Zbarsky <dzbarsky@gmail.com>2015-07-27 23:05:18 -0400
committerDavid Zbarsky <dzbarsky@gmail.com>2015-07-29 20:17:50 -0400
commite484d6b5e3f378a33fabf5ff64cb9a7f76f3ba68 (patch)
tree49235a86cc3949b27d2262c8bfb11af5c964a249 /components/script
parent416931f4be43826d3b2a96905c22f626c88b603c (diff)
downloadservo-e484d6b5e3f378a33fabf5ff64cb9a7f76f3ba68.tar.gz
servo-e484d6b5e3f378a33fabf5ff64cb9a7f76f3ba68.zip
Implement getComputedStyle
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/bindings/trace.rs2
-rw-r--r--components/script/dom/cssstyledeclaration.rs22
-rw-r--r--components/script/dom/htmlelement.rs2
-rw-r--r--components/script/dom/webidls/Window.webidl7
-rw-r--r--components/script/dom/window.rs38
-rw-r--r--components/script/layout_interface.rs7
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.