servo: Merge #11787 - Stop parsing style attributes during restyle in geckolib (from heycam:style-attr); r=bholley
authorCameron McCormack <cam@mcc.id.au>
Thu, 23 Jun 2016 21:46:25 -0500
changeset 339124 2bc0a7b175deb1e87814e9508559ffb9d5f20400
parent 339123 fbc9291683849c99e9f962de2095f54e9470d319
child 339125 ba547265f5b3d4ee09515147adaac2bf24c06415
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1280772
servo: Merge #11787 - Stop parsing style attributes during restyle in geckolib (from heycam:style-attr); r=bholley <!-- Please describe your changes on the following line: --> This allows `PropertyDeclarationBlock`s parsed for `style=""` attributes to be stored on a Gecko node so that we don't have to re-parse it each time we compute style for an element. Works with [Gecko bug 1280772](https://bugzilla.mozilla.org/show_bug.cgi?id=1280772). r? @bholley CC @emilio --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 581c8ba1c867ad378dee79b05b11648726ce5efb
servo/ports/geckolib/gecko_bindings/bindings.rs
servo/ports/geckolib/glue.rs
servo/ports/geckolib/wrapper.rs
--- a/servo/ports/geckolib/gecko_bindings/bindings.rs
+++ b/servo/ports/geckolib/gecko_bindings/bindings.rs
@@ -129,16 +129,18 @@ pub enum nsIURI { }
 pub enum Element { }
 pub type RawGeckoElement = Element;
 pub enum nsIDocument { }
 pub type RawGeckoDocument = nsIDocument;
 pub enum ServoNodeData { }
 pub enum ServoComputedValues { }
 pub enum RawServoStyleSheet { }
 pub enum RawServoStyleSet { }
+pub enum nsHTMLCSSStyleSheet { }
+pub enum ServoDeclarationBlock { }
 pub type ThreadSafePrincipalHolder = nsMainThreadPtrHolder<nsIPrincipal>;
 pub type ThreadSafeURIHolder = nsMainThreadPtrHolder<nsIURI>;
 extern "C" {
     pub fn Gecko_ChildrenCount(node: *mut RawGeckoNode) -> u32;
     pub fn Gecko_NodeIsElement(node: *mut RawGeckoNode) -> bool;
     pub fn Gecko_GetParentNode(node: *mut RawGeckoNode) -> *mut RawGeckoNode;
     pub fn Gecko_GetFirstChild(node: *mut RawGeckoNode) -> *mut RawGeckoNode;
     pub fn Gecko_GetLastChild(node: *mut RawGeckoNode) -> *mut RawGeckoNode;
@@ -165,16 +167,18 @@ extern "C" {
     pub fn Gecko_IsUnvisitedLink(element: *mut RawGeckoElement) -> bool;
     pub fn Gecko_IsRootElement(element: *mut RawGeckoElement) -> bool;
     pub fn Gecko_LocalName(element: *mut RawGeckoElement) -> *mut nsIAtom;
     pub fn Gecko_Namespace(element: *mut RawGeckoElement) -> *mut nsIAtom;
     pub fn Gecko_GetElementId(element: *mut RawGeckoElement) -> *mut nsIAtom;
     pub fn Gecko_ClassOrClassList(element: *mut RawGeckoElement,
                                   class_: *mut *mut nsIAtom,
                                   classList: *mut *mut *mut nsIAtom) -> u32;
+    pub fn Gecko_GetServoDeclarationBlock(element: *mut RawGeckoElement)
+     -> *mut ServoDeclarationBlock;
     pub fn Gecko_GetNodeData(node: *mut RawGeckoNode) -> *mut ServoNodeData;
     pub fn Gecko_SetNodeData(node: *mut RawGeckoNode,
                              data: *mut ServoNodeData);
     pub fn Servo_DropNodeData(data: *mut ServoNodeData);
     pub fn Gecko_Atomize(aString: *const ::std::os::raw::c_char, aLength: u32)
      -> *mut nsIAtom;
     pub fn Gecko_AddRefAtom(aAtom: *mut nsIAtom);
     pub fn Gecko_ReleaseAtom(aAtom: *mut nsIAtom);
@@ -237,16 +241,28 @@ extern "C" {
     pub fn Servo_RemoveStyleSheet(sheet: *mut RawServoStyleSheet,
                                   set: *mut RawServoStyleSet);
     pub fn Servo_InsertStyleSheetBefore(sheet: *mut RawServoStyleSheet,
                                         reference: *mut RawServoStyleSheet,
                                         set: *mut RawServoStyleSet);
     pub fn Servo_StyleSheetHasRules(sheet: *mut RawServoStyleSheet) -> bool;
     pub fn Servo_InitStyleSet() -> *mut RawServoStyleSet;
     pub fn Servo_DropStyleSet(set: *mut RawServoStyleSet);
+    pub fn Servo_ParseStyleAttribute(bytes: *const u8, length: u8,
+                                     cache: *mut nsHTMLCSSStyleSheet)
+     -> *mut ServoDeclarationBlock;
+    pub fn Servo_DropDeclarationBlock(declarations:
+                                          *mut ServoDeclarationBlock);
+    pub fn Servo_GetDeclarationBlockCache(declarations:
+                                              *mut ServoDeclarationBlock)
+     -> *mut nsHTMLCSSStyleSheet;
+    pub fn Servo_SetDeclarationBlockImmutable(declarations:
+                                                  *mut ServoDeclarationBlock);
+    pub fn Servo_ClearDeclarationBlockCachePointer(declarations:
+                                                       *mut ServoDeclarationBlock);
     pub fn Servo_GetComputedValues(node: *mut RawGeckoNode)
      -> *mut ServoComputedValues;
     pub fn Servo_GetComputedValuesForAnonymousBox(parentStyleOrNull:
                                                       *mut ServoComputedValues,
                                                   pseudoTag: *mut nsIAtom,
                                                   set: *mut RawServoStyleSet)
      -> *mut ServoComputedValues;
     pub fn Servo_GetComputedValuesForPseudoElement(parent_style:
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -4,34 +4,35 @@
 
 #![allow(unsafe_code)]
 
 use app_units::Au;
 use data::PerDocumentStyleData;
 use env_logger;
 use euclid::Size2D;
 use gecko_bindings::bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode};
-use gecko_bindings::bindings::{RawServoStyleSet, RawServoStyleSheet, ServoComputedValues, ServoNodeData};
-use gecko_bindings::bindings::{ThreadSafePrincipalHolder, ThreadSafeURIHolder};
+use gecko_bindings::bindings::{RawServoStyleSet, RawServoStyleSheet, ServoComputedValues};
+use gecko_bindings::bindings::{ServoDeclarationBlock, ServoNodeData, ThreadSafePrincipalHolder};
+use gecko_bindings::bindings::{ThreadSafeURIHolder, nsHTMLCSSStyleSheet};
 use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
 use gecko_bindings::structs::{SheetParsingMode, nsIAtom};
 use properties::GeckoComputedValues;
 use selector_impl::{GeckoSelectorImpl, PseudoElement, SharedStyleContext, Stylesheet};
 use std::marker::PhantomData;
 use std::mem::{forget, transmute};
 use std::ptr;
 use std::slice;
 use std::str::from_utf8_unchecked;
 use std::sync::{Arc, Mutex};
 use style::context::ReflowGoal;
 use style::dom::{TDocument, TElement, TNode};
 use style::error_reporting::StdoutErrorReporter;
 use style::parallel;
 use style::parser::ParserContextExtraData;
-use style::properties::ComputedValues;
+use style::properties::{ComputedValues, PropertyDeclarationBlock};
 use style::selector_impl::{SelectorImplExt, PseudoElementCascadeType};
 use style::stylesheets::Origin;
 use traversal::RecalcStyleOnly;
 use url::Url;
 use util::arc_ptr_eq;
 use wrapper::{GeckoDocument, GeckoElement, GeckoNode, NonOpaqueStyleData};
 
 // TODO: This is ugly and should go away once we get an atom back-end.
@@ -405,8 +406,53 @@ pub extern "C" fn Servo_InitStyleSet() -
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DropStyleSet(data: *mut RawServoStyleSet) -> () {
     unsafe {
         let _ = Box::<PerDocumentStyleData>::from_raw(data as *mut PerDocumentStyleData);
     }
 }
+
+pub struct GeckoDeclarationBlock {
+    pub declarations: Option<PropertyDeclarationBlock>,
+    pub cache: *mut nsHTMLCSSStyleSheet,
+    pub immutable: bool,
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_ParseStyleAttribute(bytes: *const u8, length: u32,
+                                            cache: *mut nsHTMLCSSStyleSheet)
+                                            -> *mut ServoDeclarationBlock {
+    let value = unsafe { from_utf8_unchecked(slice::from_raw_parts(bytes, length as usize)) };
+    let declarations = Box::new(GeckoDeclarationBlock {
+        declarations: GeckoElement::parse_style_attribute(value),
+        cache: cache,
+        immutable: false,
+    });
+    Box::into_raw(declarations) as *mut ServoDeclarationBlock
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_DropDeclarationBlock(declarations: *mut ServoDeclarationBlock) {
+    unsafe {
+        let _ = Box::<GeckoDeclarationBlock>::from_raw(declarations as *mut GeckoDeclarationBlock);
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_GetDeclarationBlockCache(declarations: *mut ServoDeclarationBlock)
+                                                 -> *mut nsHTMLCSSStyleSheet {
+    let declarations = unsafe { (declarations as *const GeckoDeclarationBlock).as_ref().unwrap() };
+    declarations.cache
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_SetDeclarationBlockImmutable(declarations: *mut ServoDeclarationBlock) {
+    let declarations = unsafe { (declarations as *mut GeckoDeclarationBlock).as_mut().unwrap() };
+    declarations.immutable = true;
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_ClearDeclarationBlockCachePointer(declarations: *mut ServoDeclarationBlock) {
+    let declarations = unsafe { (declarations as *mut GeckoDeclarationBlock).as_mut().unwrap() };
+    declarations.cache = ptr::null_mut();
+}
--- a/servo/ports/geckolib/wrapper.rs
+++ b/servo/ports/geckolib/wrapper.rs
@@ -10,22 +10,24 @@ use gecko_bindings::bindings::Gecko_GetE
 use gecko_bindings::bindings::Gecko_GetNodeData;
 use gecko_bindings::bindings::ServoNodeData;
 use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetAttrAsUTF8, Gecko_GetDocumentElement};
 use gecko_bindings::bindings::{Gecko_GetFirstChild, Gecko_GetFirstChildElement};
 use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetLastChildElement};
 use gecko_bindings::bindings::{Gecko_GetNextSibling, Gecko_GetNextSiblingElement};
 use gecko_bindings::bindings::{Gecko_GetParentElement, Gecko_GetParentNode};
 use gecko_bindings::bindings::{Gecko_GetPrevSibling, Gecko_GetPrevSiblingElement};
-use gecko_bindings::bindings::{Gecko_IsHTMLElementInHTMLDocument, Gecko_IsLink, Gecko_IsRootElement, Gecko_IsTextNode};
+use gecko_bindings::bindings::{Gecko_GetServoDeclarationBlock, Gecko_IsHTMLElementInHTMLDocument};
+use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement, Gecko_IsTextNode};
 use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink};
 #[allow(unused_imports)] // Used in commented-out code.
 use gecko_bindings::bindings::{Gecko_LocalName, Gecko_Namespace, Gecko_NodeIsElement, Gecko_SetNodeData};
 use gecko_bindings::bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode};
 use gecko_bindings::structs::nsIAtom;
+use glue::GeckoDeclarationBlock;
 use libc::uintptr_t;
 use properties::GeckoComputedValues;
 use selector_impl::{GeckoSelectorImpl, NonTSPseudoClass, PrivateStyleData};
 use selectors::Element;
 use selectors::matching::DeclarationBlock;
 use selectors::parser::{AttrSelector, NamespaceConstraint};
 use smallvec::VecLike;
 use std::marker::PhantomData;
@@ -312,47 +314,48 @@ impl<'le> GeckoElement<'le> {
             element: el,
             chain: PhantomData,
         }
     }
 
     unsafe fn from_ref(el: &RawGeckoElement) -> GeckoElement<'le> {
         GeckoElement::from_raw(el as *const RawGeckoElement as *mut RawGeckoElement)
     }
+
+    pub fn parse_style_attribute(value: &str) -> Option<PropertyDeclarationBlock> {
+        // FIXME(bholley): Real base URL and error reporter.
+        let base_url = &*DUMMY_BASE_URL;
+        // FIXME(heycam): Needs real ParserContextExtraData so that URLs parse
+        // properly.
+        let extra_data = ParserContextExtraData::default();
+        Some(parse_style_attribute(value, &base_url, Box::new(StdoutErrorReporter), extra_data))
+    }
 }
 
 lazy_static! {
     pub static ref DUMMY_BASE_URL: Url = {
         Url::parse("http://www.example.org").unwrap()
     };
 }
 
+static NO_STYLE_ATTRIBUTE: Option<PropertyDeclarationBlock> = None;
+
 impl<'le> TElement for GeckoElement<'le> {
     type ConcreteNode = GeckoNode<'le>;
     type ConcreteDocument = GeckoDocument<'le>;
 
     fn as_node(&self) -> Self::ConcreteNode {
         unsafe { GeckoNode::from_raw(self.element as *mut RawGeckoNode) }
     }
 
     fn style_attribute(&self) -> &Option<PropertyDeclarationBlock> {
-        panic!("Requires signature modification - only implemented in stylo branch");
-        /*
-        // FIXME(bholley): We should do what Servo does here. Gecko needs to
-        // call into the Servo CSS parser and then cache the resulting block
-        // in the nsAttrValue. That will allow us to borrow it from here.
-        let attr = self.get_attr(&ns!(), &atom!("style"));
-        // FIXME(bholley): Real base URL and error reporter.
-        let base_url = &*DUMMY_BASE_URL;
-        // FIXME(heycam): Needs real ParserContextExtraData so that URLs parse
-        // properly.
-        let extra_data = ParserContextExtraData::default();
-        attr.map(|v| parse_style_attribute(&v, &base_url, Box::new(StdoutErrorReporter),
-                                           extra_data))
-        */
+        unsafe {
+            let ptr = Gecko_GetServoDeclarationBlock(self.element) as *mut GeckoDeclarationBlock;
+            ptr.as_ref().map(|d| &d.declarations).unwrap_or(&NO_STYLE_ATTRIBUTE)
+        }
     }
 
     fn get_state(&self) -> ElementState {
         unsafe {
             ElementState::from_bits_truncate(Gecko_ElementState(self.element) as u16)
         }
     }