mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #6798 - dzbarsky:gCS, r=pcwalton
Implement getComputedStyle It's not quite done but can probably be reviewed anyway. I still need to finish up a few of the ToCss impls, I just got lazy and wanted to make sure things worked. The computation of the used values is definitely not right, I'm going to investigate that. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6798) <!-- Reviewable:end -->
This commit is contained in:
commit
acbca7b3aa
24 changed files with 886 additions and 152 deletions
|
@ -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]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue