style: Rewrite the restyle hints code to allow different kinds of element snapshots, and use it for Gecko.

This is a rewrite for how style interfaces with its consumers in order to allow
different representations for an element snapshot.

This also changes the requirements of an element snapshot, requiring them to
only implement MatchAttr, instead of MatchAttrGeneric. This is important for
stylo since implementing MatchAttrGeneric is way more difficult for us given the
atom limitations. This also allows for more performant implementations in the
Gecko side of things.
This commit is contained in:
Emilio Cobos Álvarez 2016-07-15 16:31:20 -07:00
parent ca9bc23b39
commit 611e611215
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
15 changed files with 565 additions and 246 deletions

View file

@ -7,7 +7,6 @@
use gecko_bindings::bindings;
use gecko_bindings::bindings::Gecko_ChildrenCount;
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_GetElementId;
use gecko_bindings::bindings::Gecko_GetNodeData;
use gecko_bindings::bindings::ServoNodeData;
use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentElement};
@ -20,7 +19,6 @@ use gecko_bindings::bindings::{Gecko_GetPrevSibling, Gecko_GetPrevSiblingElement
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;
@ -30,29 +28,25 @@ use libc::uintptr_t;
use selectors::Element;
use selectors::matching::DeclarationBlock;
use selectors::parser::{AttrSelector, NamespaceConstraint};
use snapshot::GeckoElementSnapshot;
use snapshot_helpers;
use std::marker::PhantomData;
use std::ops::BitOr;
use std::ptr;
use std::slice;
use std::sync::Arc;
use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
use style::data::PrivateStyleData;
use style::dom::{OpaqueNode, PresentationalHintsSynthetizer};
use style::dom::{TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
use style::element_state::ElementState;
#[allow(unused_imports)] // Used in commented-out code.
use style::error_reporting::StdoutErrorReporter;
use style::gecko_selector_impl::{GeckoSelectorImpl, NonTSPseudoClass};
#[allow(unused_imports)] // Used in commented-out code.
use style::parser::ParserContextExtraData;
#[allow(unused_imports)] // Used in commented-out code.
use style::properties::{ComputedValues, parse_style_attribute};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
use style::refcell::{Ref, RefCell, RefMut};
use style::restyle_hints::ElementSnapshot;
use style::selector_impl::ElementExt;
use style::sink::Push;
#[allow(unused_imports)] // Used in commented-out code.
use url::Url;
pub type NonOpaqueStyleData = *mut RefCell<PrivateStyleData>;
@ -324,7 +318,7 @@ impl<'ld> TDocument for GeckoDocument<'ld> {
}
}
fn drain_modified_elements(&self) -> Vec<(GeckoElement<'ld>, ElementSnapshot)> {
fn drain_modified_elements(&self) -> Vec<(GeckoElement<'ld>, GeckoElementSnapshot)> {
unimplemented!()
/*
let elements = unsafe { self.document.drain_modified_elements() };
@ -497,48 +491,30 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
fn get_id(&self) -> Option<Atom> {
unsafe {
let ptr = Gecko_GetElementId(self.element);
if ptr.is_null() {
None
} else {
Some(Atom::from(ptr))
}
let ptr = unsafe {
bindings::Gecko_AtomAttrValue(self.element,
atom!("id").as_ptr())
};
if ptr.is_null() {
None
} else {
Some(Atom::from(ptr))
}
}
fn has_class(&self, name: &Atom) -> bool {
unsafe {
let mut class: *mut nsIAtom = ptr::null_mut();
let mut list: *mut *mut nsIAtom = ptr::null_mut();
let length = Gecko_ClassOrClassList(self.element, &mut class, &mut list);
match length {
0 => false,
1 => name.as_ptr() == class,
n => {
let classes = slice::from_raw_parts(list, n as usize);
classes.iter().any(|ptr| name.as_ptr() == *ptr)
}
}
}
snapshot_helpers::has_class(self.element,
name,
Gecko_ClassOrClassList)
}
fn each_class<F>(&self, mut callback: F) where F: FnMut(&Atom) {
unsafe {
let mut class: *mut nsIAtom = ptr::null_mut();
let mut list: *mut *mut nsIAtom = ptr::null_mut();
let length = Gecko_ClassOrClassList(self.element, &mut class, &mut list);
match length {
0 => {}
1 => Atom::with(class, &mut callback),
n => {
let classes = slice::from_raw_parts(list, n as usize);
for c in classes {
Atom::with(*c, &mut callback)
}
}
}
}
fn each_class<F>(&self, callback: F)
where F: FnMut(&Atom)
{
snapshot_helpers::each_class(self.element,
callback,
Gecko_ClassOrClassList)
}
fn is_html_element_in_html_document(&self) -> bool {
@ -548,9 +524,9 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
}
trait AttrSelectorHelpers {
pub trait AttrSelectorHelpers {
fn ns_or_null(&self) -> *mut nsIAtom;
fn select_name<'le>(&self, el: &GeckoElement<'le>) -> *mut nsIAtom;
fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom;
}
impl AttrSelectorHelpers for AttrSelector {
@ -561,13 +537,12 @@ impl AttrSelectorHelpers for AttrSelector {
}
}
fn select_name<'le>(&self, el: &GeckoElement<'le>) -> *mut nsIAtom {
if el.is_html_element_in_html_document() {
fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom {
if is_html_element_in_html_document {
self.lower_name.as_ptr()
} else {
self.name.as_ptr()
}
}
}
@ -577,14 +552,14 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_HasAttr(self.element,
attr.ns_or_null(),
attr.select_name(self))
attr.select_name(self.is_html_element_in_html_document()))
}
}
fn match_attr_equals(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
unsafe {
bindings::Gecko_AttrEquals(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr(),
/* ignoreCase = */ false)
}
@ -593,7 +568,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrEquals(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr(),
/* ignoreCase = */ false)
}
@ -602,7 +577,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrIncludes(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
@ -610,7 +585,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrDashEquals(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
@ -618,7 +593,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrHasPrefix(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
@ -626,7 +601,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrHasSubstring(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
@ -634,13 +609,16 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrHasSuffix(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
}
impl<'le> ElementExt for GeckoElement<'le> {
type Snapshot = GeckoElementSnapshot;
#[inline]
fn is_link(&self) -> bool {
self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink)
}