mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Auto merge of #12469 - emilio:stylo, r=bholley
style: Rewrite the restyle hints code to allow different kinds of element snapshots. <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors <!-- Either: --> - [x] These changes do not require tests because refactoring. <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> 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. I don't want to get this merged just yet, mainly because the stylo part is not implemented, but I'd like early feedback from @bholley and/or @heycam: How do you see this approach? I don't think we'll have much problem to implement MatchAttr for our element snapshots, but... worth checking. r? @heycam <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12469) <!-- Reviewable:end -->
This commit is contained in:
commit
1e0321f7dd
18 changed files with 1183 additions and 256 deletions
|
@ -89,8 +89,7 @@ use string_cache::{Atom, Namespace, QualName};
|
|||
use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
|
||||
use style::element_state::*;
|
||||
use style::properties::PropertyDeclarationBlock;
|
||||
use style::restyle_hints::ElementSnapshot;
|
||||
use style::selector_impl::PseudoElement;
|
||||
use style::selector_impl::{PseudoElement, ElementSnapshot};
|
||||
use style::values::specified::Length;
|
||||
use url::Origin as UrlOrigin;
|
||||
use url::Url;
|
||||
|
|
|
@ -122,7 +122,7 @@ use std::sync::Arc;
|
|||
use string_cache::{Atom, QualName};
|
||||
use style::attr::AttrValue;
|
||||
use style::context::ReflowGoal;
|
||||
use style::restyle_hints::ElementSnapshot;
|
||||
use style::selector_impl::ElementSnapshot;
|
||||
use style::str::{split_html_space_chars, str_join};
|
||||
use style::stylesheets::Stylesheet;
|
||||
use time;
|
||||
|
@ -1851,7 +1851,10 @@ impl Document {
|
|||
|
||||
pub fn element_state_will_change(&self, el: &Element) {
|
||||
let mut map = self.modified_elements.borrow_mut();
|
||||
let snapshot = map.entry(JS::from_ref(el)).or_insert(ElementSnapshot::new());
|
||||
let snapshot = map.entry(JS::from_ref(el))
|
||||
.or_insert_with(|| {
|
||||
ElementSnapshot::new(el.html_element_in_html_document())
|
||||
});
|
||||
if snapshot.state.is_none() {
|
||||
snapshot.state = Some(el.state());
|
||||
}
|
||||
|
@ -1859,7 +1862,10 @@ impl Document {
|
|||
|
||||
pub fn element_attr_will_change(&self, el: &Element) {
|
||||
let mut map = self.modified_elements.borrow_mut();
|
||||
let mut snapshot = map.entry(JS::from_ref(el)).or_insert(ElementSnapshot::new());
|
||||
let mut snapshot = map.entry(JS::from_ref(el))
|
||||
.or_insert_with(|| {
|
||||
ElementSnapshot::new(el.html_element_in_html_document())
|
||||
});
|
||||
if snapshot.attrs.is_none() {
|
||||
let attrs = el.attrs()
|
||||
.iter()
|
||||
|
|
|
@ -60,8 +60,7 @@ use style::dom::{PresentationalHintsSynthetizer, OpaqueNode, TDocument, TElement
|
|||
use style::element_state::*;
|
||||
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use style::refcell::{Ref, RefCell, RefMut};
|
||||
use style::restyle_hints::ElementSnapshot;
|
||||
use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl};
|
||||
use style::selector_impl::{ElementSnapshot, NonTSPseudoClass, ServoSelectorImpl};
|
||||
use style::sink::Push;
|
||||
use style::str::is_whitespace;
|
||||
use url::Url;
|
||||
|
|
|
@ -29,7 +29,7 @@ pub enum LengthOrPercentageOrAuto {
|
|||
Length(Au),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum AttrValue {
|
||||
String(String),
|
||||
|
|
|
@ -11,7 +11,7 @@ use data::PrivateStyleData;
|
|||
use element_state::ElementState;
|
||||
use properties::{ComputedValues, PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use refcell::{Ref, RefMut};
|
||||
use restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||
use selector_impl::{ElementExt, SelectorImplExt};
|
||||
use selectors::Element;
|
||||
use selectors::matching::DeclarationBlock;
|
||||
|
@ -192,7 +192,8 @@ pub trait TDocument : Sized + Copy + Clone {
|
|||
|
||||
fn root_node(&self) -> Option<Self::ConcreteNode>;
|
||||
|
||||
fn drain_modified_elements(&self) -> Vec<(Self::ConcreteElement, ElementSnapshot)>;
|
||||
fn drain_modified_elements(&self) -> Vec<(Self::ConcreteElement,
|
||||
<Self::ConcreteElement as ElementExt>::Snapshot)>;
|
||||
}
|
||||
|
||||
pub trait PresentationalHintsSynthetizer {
|
||||
|
|
|
@ -4,24 +4,21 @@
|
|||
|
||||
//! Restyle hints: an optimization to avoid unnecessarily matching selectors.
|
||||
|
||||
use attr::{AttrIdentifier, AttrValue};
|
||||
use element_state::*;
|
||||
use selector_impl::{SelectorImplExt, TheSelectorImpl, AttrString};
|
||||
use selector_impl::{ElementExt, SelectorImplExt, TheSelectorImpl, AttrString};
|
||||
use selectors::matching::matches_compound_selector;
|
||||
use selectors::parser::{AttrSelector, Combinator, CompoundSelector, SelectorImpl, SimpleSelector};
|
||||
use selectors::{Element, MatchAttrGeneric};
|
||||
#[cfg(feature = "gecko")] use selectors::MatchAttr;
|
||||
use selectors::{Element, MatchAttr};
|
||||
use std::clone::Clone;
|
||||
use std::sync::Arc;
|
||||
use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
|
||||
use string_cache::{Atom, BorrowedAtom, BorrowedNamespace};
|
||||
|
||||
/// When the ElementState of an element (like IN_HOVER_STATE) changes, certain
|
||||
/// pseudo-classes (like :hover) may require us to restyle that element, its
|
||||
/// siblings, and/or its descendants. Similarly, when various attributes of an
|
||||
/// element change, we may also need to restyle things with id, class, and attribute
|
||||
/// selectors. Doing this conservatively is expensive, and so we use RestyleHints to
|
||||
/// short-circuit work we know is unnecessary.
|
||||
|
||||
/// element change, we may also need to restyle things with id, class, and
|
||||
/// attribute selectors. Doing this conservatively is expensive, and so we use
|
||||
/// RestyleHints to short-circuit work we know is unnecessary.
|
||||
bitflags! {
|
||||
pub flags RestyleHint: u8 {
|
||||
#[doc = "Rerun selector matching on the element."]
|
||||
|
@ -35,143 +32,153 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
/// In order to compute restyle hints, we perform a selector match against a list of partial
|
||||
/// selectors whose rightmost simple selector may be sensitive to the thing being changed. We
|
||||
/// do this matching twice, once for the element as it exists now and once for the element as it
|
||||
/// existed at the time of the last restyle. If the results of the selector match differ, that means
|
||||
/// that the given partial selector is sensitive to the change, and we compute a restyle hint
|
||||
/// based on its combinator.
|
||||
/// In order to compute restyle hints, we perform a selector match against a
|
||||
/// list of partial selectors whose rightmost simple selector may be sensitive
|
||||
/// to the thing being changed. We do this matching twice, once for the element
|
||||
/// as it exists now and once for the element as it existed at the time of the
|
||||
/// last restyle. If the results of the selector match differ, that means that
|
||||
/// the given partial selector is sensitive to the change, and we compute a
|
||||
/// restyle hint based on its combinator.
|
||||
///
|
||||
/// In order to run selector matching against the old element state, we generate a wrapper for
|
||||
/// the element which claims to have the old state. This is the ElementWrapper logic below.
|
||||
/// In order to run selector matching against the old element state, we generate
|
||||
/// a wrapper for the element which claims to have the old state. This is the
|
||||
/// ElementWrapper logic below.
|
||||
///
|
||||
/// Gecko does this differently for element states, and passes a mask called mStateMask, which
|
||||
/// indicates the states that need to be ignored during selector matching. This saves an ElementWrapper
|
||||
/// allocation and an additional selector match call at the expense of additional complexity inside
|
||||
/// the selector matching logic. This only works for boolean states though, so we still need to
|
||||
/// take the ElementWrapper approach for attribute-dependent style. So we do it the same both ways for
|
||||
/// now to reduce complexity, but it's worth measuring the performance impact (if any) of the
|
||||
/// mStateMask approach.
|
||||
/// Gecko does this differently for element states, and passes a mask called
|
||||
/// mStateMask, which indicates the states that need to be ignored during
|
||||
/// selector matching. This saves an ElementWrapper allocation and an additional
|
||||
/// selector match call at the expense of additional complexity inside the
|
||||
/// selector matching logic. This only works for boolean states though, so we
|
||||
/// still need to take the ElementWrapper approach for attribute-dependent
|
||||
/// style. So we do it the same both ways for now to reduce complexity, but it's
|
||||
/// worth measuring the performance impact (if any) of the mStateMask approach.
|
||||
pub trait ElementSnapshot : Sized + MatchAttr {
|
||||
/// The state of the snapshot, if any.
|
||||
fn state(&self) -> Option<ElementState>;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct ElementSnapshot {
|
||||
pub state: Option<ElementState>,
|
||||
pub attrs: Option<Vec<(AttrIdentifier, AttrValue)>>,
|
||||
/// If this snapshot contains attribute information.
|
||||
fn has_attrs(&self) -> bool;
|
||||
|
||||
/// The ID attribute per this snapshot. Should only be called if
|
||||
/// `has_attrs()` returns true.
|
||||
fn id_attr(&self) -> Option<Atom>;
|
||||
|
||||
/// Whether this snapshot contains the class `name`. Should only be called
|
||||
/// if `has_attrs()` returns true.
|
||||
fn has_class(&self, name: &Atom) -> bool;
|
||||
|
||||
/// A callback that should be called for each class of the snapshot. Should
|
||||
/// only be called if `has_attrs()` returns true.
|
||||
fn each_class<F>(&self, F)
|
||||
where F: FnMut(&Atom);
|
||||
}
|
||||
|
||||
impl ElementSnapshot {
|
||||
pub fn new() -> ElementSnapshot {
|
||||
EMPTY_SNAPSHOT.clone()
|
||||
}
|
||||
|
||||
// Gets an attribute matching |namespace| and |name|, if any. Panics if |attrs| is None.
|
||||
pub fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&AttrValue> {
|
||||
self.attrs.as_ref().unwrap().iter()
|
||||
.find(|&&(ref ident, _)| ident.local_name == *name && ident.namespace == *namespace)
|
||||
.map(|&(_, ref v)| v)
|
||||
}
|
||||
|
||||
// Gets an attribute matching |name| if any, ignoring namespace. Panics if |attrs| is None.
|
||||
pub fn get_attr_ignore_ns(&self, name: &Atom) -> Option<&AttrValue> {
|
||||
self.attrs.as_ref().unwrap().iter()
|
||||
.find(|&&(ref ident, _)| ident.local_name == *name)
|
||||
.map(|&(_, ref v)| v)
|
||||
}
|
||||
}
|
||||
|
||||
static EMPTY_SNAPSHOT: ElementSnapshot = ElementSnapshot { state: None, attrs: None };
|
||||
|
||||
// FIXME(bholley): This implementation isn't going to work for geckolib, because
|
||||
// it's fundamentally based on get_attr/match_attr, which we don't want to support
|
||||
// that configuration due to the overhead of converting between UTF-16 and UTF-8.
|
||||
// We'll need to figure something out when we start using restyle hints with
|
||||
// geckolib, but in the mean time we can just use the trait parameters to
|
||||
// specialize it to the Servo configuration.
|
||||
struct ElementWrapper<'a, E>
|
||||
where E: Element<AttrString=AttrString>,
|
||||
E::Impl: SelectorImplExt {
|
||||
where E: ElementExt
|
||||
{
|
||||
element: E,
|
||||
snapshot: &'a ElementSnapshot,
|
||||
snapshot: Option<&'a E::Snapshot>,
|
||||
}
|
||||
|
||||
impl<'a, E> ElementWrapper<'a, E>
|
||||
where E: Element<AttrString=AttrString>,
|
||||
E::Impl: SelectorImplExt {
|
||||
where E: ElementExt
|
||||
{
|
||||
pub fn new(el: E) -> ElementWrapper<'a, E> {
|
||||
ElementWrapper { element: el, snapshot: &EMPTY_SNAPSHOT }
|
||||
ElementWrapper { element: el, snapshot: None }
|
||||
}
|
||||
|
||||
pub fn new_with_snapshot(el: E, snapshot: &'a ElementSnapshot) -> ElementWrapper<'a, E> {
|
||||
ElementWrapper { element: el, snapshot: snapshot }
|
||||
pub fn new_with_snapshot(el: E, snapshot: &'a E::Snapshot) -> ElementWrapper<'a, E> {
|
||||
ElementWrapper { element: el, snapshot: Some(snapshot) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "gecko"))]
|
||||
impl<'a, E> MatchAttrGeneric for ElementWrapper<'a, E>
|
||||
where E: Element<AttrString=AttrString>,
|
||||
E: MatchAttrGeneric,
|
||||
E::Impl: SelectorImplExt {
|
||||
fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
|
||||
where F: Fn(&str) -> bool {
|
||||
use selectors::parser::NamespaceConstraint;
|
||||
match self.snapshot.attrs {
|
||||
Some(_) => {
|
||||
let html = self.is_html_element_in_html_document();
|
||||
let local_name = if html { &attr.lower_name } else { &attr.name };
|
||||
match attr.namespace {
|
||||
NamespaceConstraint::Specific(ref ns) => self.snapshot.get_attr(ns, local_name),
|
||||
NamespaceConstraint::Any => self.snapshot.get_attr_ignore_ns(local_name),
|
||||
}.map_or(false, |v| test(v))
|
||||
},
|
||||
None => self.element.match_attr(attr, test)
|
||||
impl<'a, E> MatchAttr for ElementWrapper<'a, E>
|
||||
where E: ElementExt<AttrString=AttrString>,
|
||||
{
|
||||
type AttrString = E::AttrString;
|
||||
|
||||
fn match_attr_has(&self, attr: &AttrSelector) -> bool {
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_has(attr),
|
||||
_ => self.element.match_attr_has(attr)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_equals(&self,
|
||||
attr: &AttrSelector,
|
||||
value: &Self::AttrString) -> bool {
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_equals(attr, value),
|
||||
_ => self.element.match_attr_equals(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_equals_ignore_ascii_case(&self,
|
||||
attr: &AttrSelector,
|
||||
value: &Self::AttrString) -> bool {
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_equals_ignore_ascii_case(attr, value),
|
||||
_ => self.element.match_attr_equals_ignore_ascii_case(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_includes(&self,
|
||||
attr: &AttrSelector,
|
||||
value: &Self::AttrString) -> bool {
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_includes(attr, value),
|
||||
_ => self.element.match_attr_includes(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_dash(&self,
|
||||
attr: &AttrSelector,
|
||||
value: &Self::AttrString) -> bool {
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_dash(attr, value),
|
||||
_ => self.element.match_attr_dash(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_prefix(&self,
|
||||
attr: &AttrSelector,
|
||||
value: &Self::AttrString) -> bool {
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_prefix(attr, value),
|
||||
_ => self.element.match_attr_prefix(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_substring(&self,
|
||||
attr: &AttrSelector,
|
||||
value: &Self::AttrString) -> bool {
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_substring(attr, value),
|
||||
_ => self.element.match_attr_substring(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_suffix(&self,
|
||||
attr: &AttrSelector,
|
||||
value: &Self::AttrString) -> bool {
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_suffix(attr, value),
|
||||
_ => self.element.match_attr_suffix(attr, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
impl<'a, E> MatchAttr for ElementWrapper<'a, E>
|
||||
where E: Element<AttrString=AttrString>,
|
||||
E::Impl: SelectorImplExt {
|
||||
type AttrString = AttrString;
|
||||
|
||||
fn match_attr_has(&self, _attr: &AttrSelector) -> bool {
|
||||
panic!("Not implemented for Gecko - this system will need to be redesigned");
|
||||
}
|
||||
|
||||
fn match_attr_equals(&self, _attr: &AttrSelector, _value: &Self::AttrString) -> bool {
|
||||
panic!("Not implemented for Gecko - this system will need to be redesigned");
|
||||
}
|
||||
|
||||
fn match_attr_equals_ignore_ascii_case(&self, _attr: &AttrSelector, _value: &Self::AttrString) -> bool {
|
||||
panic!("Not implemented for Gecko - this system will need to be redesigned");
|
||||
}
|
||||
|
||||
fn match_attr_includes(&self, _attr: &AttrSelector, _value: &Self::AttrString) -> bool {
|
||||
panic!("Not implemented for Gecko - this system will need to be redesigned");
|
||||
}
|
||||
|
||||
fn match_attr_dash(&self, _attr: &AttrSelector, _value: &Self::AttrString) -> bool {
|
||||
panic!("Not implemented for Gecko - this system will need to be redesigned");
|
||||
}
|
||||
|
||||
fn match_attr_prefix(&self, _attr: &AttrSelector, _value: &Self::AttrString) -> bool {
|
||||
panic!("Not implemented for Gecko - this system will need to be redesigned");
|
||||
}
|
||||
|
||||
fn match_attr_substring(&self, _attr: &AttrSelector, _value: &Self::AttrString) -> bool {
|
||||
panic!("Not implemented for Gecko - this system will need to be redesigned");
|
||||
}
|
||||
|
||||
fn match_attr_suffix(&self, _attr: &AttrSelector, _value: &Self::AttrString) -> bool {
|
||||
panic!("Not implemented for Gecko - this system will need to be redesigned");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> Element for ElementWrapper<'a, E>
|
||||
where E: Element<AttrString=AttrString>,
|
||||
E: MatchAttrGeneric,
|
||||
E::Impl: SelectorImplExt {
|
||||
where E: ElementExt<AttrString=AttrString>,
|
||||
E::Impl: SelectorImplExt<AttrString=AttrString> {
|
||||
type Impl = E::Impl;
|
||||
|
||||
fn match_non_ts_pseudo_class(&self,
|
||||
|
@ -180,9 +187,9 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
|||
if flag == ElementState::empty() {
|
||||
self.element.match_non_ts_pseudo_class(pseudo_class)
|
||||
} else {
|
||||
match self.snapshot.state {
|
||||
Some(s) => s.contains(flag),
|
||||
None => self.element.match_non_ts_pseudo_class(pseudo_class)
|
||||
match self.snapshot.and_then(|s| s.state()) {
|
||||
Some(snapshot_state) => snapshot_state.contains(flag),
|
||||
_ => self.element.match_non_ts_pseudo_class(pseudo_class)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,54 +197,65 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
|||
fn parent_element(&self) -> Option<Self> {
|
||||
self.element.parent_element().map(ElementWrapper::new)
|
||||
}
|
||||
|
||||
fn first_child_element(&self) -> Option<Self> {
|
||||
self.element.first_child_element().map(ElementWrapper::new)
|
||||
}
|
||||
|
||||
fn last_child_element(&self) -> Option<Self> {
|
||||
self.element.last_child_element().map(ElementWrapper::new)
|
||||
}
|
||||
|
||||
fn prev_sibling_element(&self) -> Option<Self> {
|
||||
self.element.prev_sibling_element().map(ElementWrapper::new)
|
||||
}
|
||||
|
||||
fn next_sibling_element(&self) -> Option<Self> {
|
||||
self.element.next_sibling_element().map(ElementWrapper::new)
|
||||
}
|
||||
|
||||
fn is_html_element_in_html_document(&self) -> bool {
|
||||
self.element.is_html_element_in_html_document()
|
||||
}
|
||||
|
||||
fn get_local_name(&self) -> BorrowedAtom {
|
||||
self.element.get_local_name()
|
||||
}
|
||||
|
||||
fn get_namespace(&self) -> BorrowedNamespace {
|
||||
self.element.get_namespace()
|
||||
}
|
||||
|
||||
fn get_id(&self) -> Option<Atom> {
|
||||
match self.snapshot.attrs {
|
||||
Some(_) => self.snapshot.get_attr(&ns!(), &atom!("id")).map(|value| value.as_atom().clone()),
|
||||
None => self.element.get_id(),
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.id_attr(),
|
||||
_ => self.element.get_id()
|
||||
}
|
||||
}
|
||||
|
||||
fn has_class(&self, name: &Atom) -> bool {
|
||||
match self.snapshot.attrs {
|
||||
Some(_) => self.snapshot.get_attr(&ns!(), &atom!("class"))
|
||||
.map_or(false, |v| { v.as_tokens().iter().any(|atom| atom == name) }),
|
||||
None => self.element.has_class(name),
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.has_class(name),
|
||||
_ => self.element.has_class(name)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.element.is_empty()
|
||||
}
|
||||
|
||||
fn is_root(&self) -> bool {
|
||||
self.element.is_root()
|
||||
}
|
||||
fn each_class<F>(&self, mut callback: F) where F: FnMut(&Atom) {
|
||||
match self.snapshot.attrs {
|
||||
Some(_) => {
|
||||
if let Some(v) = self.snapshot.get_attr(&ns!(), &atom!("class")) {
|
||||
for c in v.as_tokens() { callback(c) }
|
||||
}
|
||||
}
|
||||
None => self.element.each_class(callback),
|
||||
|
||||
fn each_class<F>(&self, callback: F)
|
||||
where F: FnMut(&Atom) {
|
||||
match self.snapshot {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.each_class(callback),
|
||||
_ => self.element.each_class(callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -296,24 +314,24 @@ impl Sensitivities {
|
|||
}
|
||||
}
|
||||
|
||||
// Mapping between (partial) CompoundSelectors (and the combinator to their right)
|
||||
// and the states and attributes they depend on.
|
||||
//
|
||||
// In general, for all selectors in all applicable stylesheets of the form:
|
||||
//
|
||||
// |a _ b _ c _ d _ e|
|
||||
//
|
||||
// Where:
|
||||
// * |b| and |d| are simple selectors that depend on state (like :hover) or
|
||||
// attributes (like [attr...], .foo, or #foo).
|
||||
// * |a|, |c|, and |e| are arbitrary simple selectors that do not depend on
|
||||
// state or attributes.
|
||||
//
|
||||
// We generate a Dependency for both |a _ b:X _| and |a _ b:X _ c _ d:Y _|, even
|
||||
// though those selectors may not appear on their own in any stylesheet. This allows
|
||||
// us to quickly scan through the dependency sites of all style rules and determine the
|
||||
// maximum effect that a given state or attribute change may have on the style of
|
||||
// elements in the document.
|
||||
/// Mapping between (partial) CompoundSelectors (and the combinator to their
|
||||
/// right) and the states and attributes they depend on.
|
||||
///
|
||||
/// In general, for all selectors in all applicable stylesheets of the form:
|
||||
///
|
||||
/// |a _ b _ c _ d _ e|
|
||||
///
|
||||
/// Where:
|
||||
/// * |b| and |d| are simple selectors that depend on state (like :hover) or
|
||||
/// attributes (like [attr...], .foo, or #foo).
|
||||
/// * |a|, |c|, and |e| are arbitrary simple selectors that do not depend on
|
||||
/// state or attributes.
|
||||
///
|
||||
/// We generate a Dependency for both |a _ b:X _| and |a _ b:X _ c _ d:Y _|,
|
||||
/// even though those selectors may not appear on their own in any stylesheet.
|
||||
/// This allows us to quickly scan through the dependency sites of all style
|
||||
/// rules and determine the maximum effect that a given state or attribute
|
||||
/// change may have on the style of elements in the document.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
struct Dependency {
|
||||
|
@ -368,11 +386,14 @@ impl DependencySet {
|
|||
}
|
||||
|
||||
impl DependencySet {
|
||||
pub fn compute_hint<E>(&self, el: &E, snapshot: &ElementSnapshot, current_state: ElementState)
|
||||
-> RestyleHint
|
||||
where E: Element<Impl=TheSelectorImpl, AttrString=AttrString> + Clone + MatchAttrGeneric {
|
||||
let state_changes = snapshot.state.map_or(ElementState::empty(), |old_state| current_state ^ old_state);
|
||||
let attrs_changed = snapshot.attrs.is_some();
|
||||
pub fn compute_hint<E>(&self, el: &E,
|
||||
snapshot: &E::Snapshot,
|
||||
current_state: ElementState)
|
||||
-> RestyleHint
|
||||
where E: ElementExt + Clone
|
||||
{
|
||||
let state_changes = snapshot.state().map_or_else(ElementState::empty, |old_state| current_state ^ old_state);
|
||||
let attrs_changed = snapshot.has_attrs();
|
||||
let mut hint = RestyleHint::empty();
|
||||
for dep in &self.deps {
|
||||
if state_changes.intersects(dep.sensitivities.states) || (attrs_changed && dep.sensitivities.attrs) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
//! The pseudo-classes and pseudo-elements supported by the style system.
|
||||
|
||||
use element_state::ElementState;
|
||||
use restyle_hints;
|
||||
use selectors::Element;
|
||||
use selectors::parser::SelectorImpl;
|
||||
use std::fmt::Debug;
|
||||
|
@ -13,13 +14,16 @@ use stylesheets::Stylesheet;
|
|||
pub type AttrString = <TheSelectorImpl as SelectorImpl>::AttrString;
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
pub use servo_selector_impl::ServoSelectorImpl;
|
||||
pub use servo_selector_impl::*;
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
pub use servo_selector_impl::{ServoSelectorImpl as TheSelectorImpl, PseudoElement, NonTSPseudoClass};
|
||||
pub use servo_selector_impl::{ServoSelectorImpl as TheSelectorImpl, ServoElementSnapshot as ElementSnapshot};
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use gecko_selector_impl::{GeckoSelectorImpl as TheSelectorImpl, PseudoElement, NonTSPseudoClass};
|
||||
pub use gecko_selector_impl::*;
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use gecko_selector_impl::{GeckoSelectorImpl as TheSelectorImpl};
|
||||
|
||||
/// This function determines if a pseudo-element is eagerly cascaded or not.
|
||||
///
|
||||
|
@ -69,6 +73,8 @@ impl PseudoElementCascadeType {
|
|||
}
|
||||
|
||||
pub trait ElementExt: Element<Impl=TheSelectorImpl, AttrString=<TheSelectorImpl as SelectorImpl>::AttrString> {
|
||||
type Snapshot: restyle_hints::ElementSnapshot<AttrString = Self::AttrString> + 'static;
|
||||
|
||||
fn is_link(&self) -> bool;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,12 +10,12 @@ use error_reporting::StdoutErrorReporter;
|
|||
use keyframes::KeyframesAnimation;
|
||||
use media_queries::{Device, MediaType};
|
||||
use properties::{self, PropertyDeclaration, PropertyDeclarationBlock, ComputedValues};
|
||||
use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet};
|
||||
use selector_impl::{SelectorImplExt, TheSelectorImpl, PseudoElement, AttrString};
|
||||
use restyle_hints::{RestyleHint, DependencySet};
|
||||
use selector_impl::{ElementExt, SelectorImplExt, TheSelectorImpl, PseudoElement, AttrString};
|
||||
use selectors::Element;
|
||||
use selectors::bloom::BloomFilter;
|
||||
use selectors::matching::DeclarationBlock as GenericDeclarationBlock;
|
||||
use selectors::matching::{Rule, SelectorMap};
|
||||
use selectors::{Element, MatchAttrGeneric};
|
||||
use sink::Push;
|
||||
use smallvec::VecLike;
|
||||
use std::collections::HashMap;
|
||||
|
@ -402,15 +402,15 @@ impl Stylist {
|
|||
}
|
||||
|
||||
pub fn compute_restyle_hint<E>(&self, element: &E,
|
||||
snapshot: &ElementSnapshot,
|
||||
snapshot: &E::Snapshot,
|
||||
// NB: We need to pass current_state as an argument because
|
||||
// selectors::Element doesn't provide access to ElementState
|
||||
// directly, and computing it from the ElementState would be
|
||||
// more expensive than getting it directly from the caller.
|
||||
current_state: ElementState)
|
||||
-> RestyleHint
|
||||
where E: Element<Impl=TheSelectorImpl, AttrString=AttrString>
|
||||
+ Clone + MatchAttrGeneric {
|
||||
where E: ElementExt + Clone
|
||||
{
|
||||
self.state_deps.compute_hint(element, snapshot, current_state)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use attr::{AttrIdentifier, AttrValue};
|
||||
use element_state::ElementState;
|
||||
use error_reporting::StdoutErrorReporter;
|
||||
use parser::ParserContextExtraData;
|
||||
use restyle_hints::ElementSnapshot;
|
||||
use selector_impl::{SelectorImplExt, ElementExt, PseudoElementCascadeType, TheSelectorImpl};
|
||||
use selectors::Element;
|
||||
use selectors::parser::{ParserContext, SelectorImpl};
|
||||
use selectors::parser::{AttrSelector, ParserContext, SelectorImpl};
|
||||
use selectors::{Element, MatchAttrGeneric};
|
||||
use std::process;
|
||||
use string_cache::{Atom, Namespace};
|
||||
use stylesheets::{Stylesheet, Origin};
|
||||
use url::Url;
|
||||
use util::opts;
|
||||
|
@ -189,7 +192,84 @@ impl SelectorImplExt for ServoSelectorImpl {
|
|||
}
|
||||
}
|
||||
|
||||
/// Servo's version of an element snapshot.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct ServoElementSnapshot {
|
||||
pub state: Option<ElementState>,
|
||||
pub attrs: Option<Vec<(AttrIdentifier, AttrValue)>>,
|
||||
pub is_html_element_in_html_document: bool,
|
||||
}
|
||||
|
||||
impl ServoElementSnapshot {
|
||||
pub fn new(is_html_element_in_html_document: bool) -> Self {
|
||||
ServoElementSnapshot {
|
||||
state: None,
|
||||
attrs: None,
|
||||
is_html_element_in_html_document: is_html_element_in_html_document,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&AttrValue> {
|
||||
self.attrs.as_ref().unwrap().iter()
|
||||
.find(|&&(ref ident, _)| ident.local_name == *name &&
|
||||
ident.namespace == *namespace)
|
||||
.map(|&(_, ref v)| v)
|
||||
}
|
||||
|
||||
fn get_attr_ignore_ns(&self, name: &Atom) -> Option<&AttrValue> {
|
||||
self.attrs.as_ref().unwrap().iter()
|
||||
.find(|&&(ref ident, _)| ident.local_name == *name)
|
||||
.map(|&(_, ref v)| v)
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementSnapshot for ServoElementSnapshot {
|
||||
fn state(&self) -> Option<ElementState> {
|
||||
self.state.clone()
|
||||
}
|
||||
|
||||
fn has_attrs(&self) -> bool {
|
||||
self.attrs.is_some()
|
||||
}
|
||||
|
||||
fn id_attr(&self) -> Option<Atom> {
|
||||
self.get_attr(&ns!(), &atom!("id")).map(|v| v.as_atom().clone())
|
||||
}
|
||||
|
||||
fn has_class(&self, name: &Atom) -> bool {
|
||||
self.get_attr(&ns!(), &atom!("class"))
|
||||
.map_or(false, |v| v.as_tokens().iter().any(|atom| atom == name))
|
||||
}
|
||||
|
||||
fn each_class<F>(&self, mut callback: F)
|
||||
where F: FnMut(&Atom)
|
||||
{
|
||||
if let Some(v) = self.get_attr(&ns!(), &atom!("class")) {
|
||||
for class in v.as_tokens() {
|
||||
callback(class);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MatchAttrGeneric for ServoElementSnapshot {
|
||||
fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
|
||||
where F: Fn(&str) -> bool
|
||||
{
|
||||
use selectors::parser::NamespaceConstraint;
|
||||
let html = self.is_html_element_in_html_document;
|
||||
let local_name = if html { &attr.lower_name } else { &attr.name };
|
||||
match attr.namespace {
|
||||
NamespaceConstraint::Specific(ref ns) => self.get_attr(ns, local_name),
|
||||
NamespaceConstraint::Any => self.get_attr_ignore_ns(local_name),
|
||||
}.map_or(false, |v| test(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Element<Impl=TheSelectorImpl, AttrString=String>> ElementExt for E {
|
||||
type Snapshot = ServoElementSnapshot;
|
||||
|
||||
fn is_link(&self) -> bool {
|
||||
self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink)
|
||||
}
|
||||
|
|
|
@ -133,6 +133,8 @@ unsafe impl Sync for nsStyleUnion {}
|
|||
impl HeapSizeOf for nsStyleUnion { fn heap_size_of_children(&self) -> usize { 0 } }
|
||||
use structs::nsStyleCoord_CalcValue as CalcValue;
|
||||
use structs::nsStyleCoord_Calc as Calc;
|
||||
use structs::nsRestyleHint;
|
||||
use structs::ServoElementSnapshot;
|
||||
use structs::SheetParsingMode;
|
||||
use structs::nsMainThreadPtrHandle;
|
||||
use structs::nsMainThreadPtrHolder;
|
||||
|
@ -185,6 +187,8 @@ extern "C" {
|
|||
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_AtomAttrValue(element: *mut RawGeckoElement,
|
||||
attribute: *mut nsIAtom) -> *mut nsIAtom;
|
||||
pub fn Gecko_HasAttr(element: *mut RawGeckoElement, ns: *mut nsIAtom,
|
||||
name: *mut nsIAtom) -> bool;
|
||||
pub fn Gecko_AttrEquals(element: *mut RawGeckoElement, ns: *mut nsIAtom,
|
||||
|
@ -207,6 +211,36 @@ extern "C" {
|
|||
pub fn Gecko_ClassOrClassList(element: *mut RawGeckoElement,
|
||||
class_: *mut *mut nsIAtom,
|
||||
classList: *mut *mut *mut nsIAtom) -> u32;
|
||||
pub fn Gecko_SnapshotAtomAttrValue(element: *mut ServoElementSnapshot,
|
||||
attribute: *mut nsIAtom)
|
||||
-> *mut nsIAtom;
|
||||
pub fn Gecko_SnapshotHasAttr(element: *mut ServoElementSnapshot,
|
||||
ns: *mut nsIAtom, name: *mut nsIAtom)
|
||||
-> bool;
|
||||
pub fn Gecko_SnapshotAttrEquals(element: *mut ServoElementSnapshot,
|
||||
ns: *mut nsIAtom, name: *mut nsIAtom,
|
||||
str: *mut nsIAtom, ignoreCase: bool)
|
||||
-> bool;
|
||||
pub fn Gecko_SnapshotAttrDashEquals(element: *mut ServoElementSnapshot,
|
||||
ns: *mut nsIAtom, name: *mut nsIAtom,
|
||||
str: *mut nsIAtom) -> bool;
|
||||
pub fn Gecko_SnapshotAttrIncludes(element: *mut ServoElementSnapshot,
|
||||
ns: *mut nsIAtom, name: *mut nsIAtom,
|
||||
str: *mut nsIAtom) -> bool;
|
||||
pub fn Gecko_SnapshotAttrHasSubstring(element: *mut ServoElementSnapshot,
|
||||
ns: *mut nsIAtom,
|
||||
name: *mut nsIAtom,
|
||||
str: *mut nsIAtom) -> bool;
|
||||
pub fn Gecko_SnapshotAttrHasPrefix(element: *mut ServoElementSnapshot,
|
||||
ns: *mut nsIAtom, name: *mut nsIAtom,
|
||||
str: *mut nsIAtom) -> bool;
|
||||
pub fn Gecko_SnapshotAttrHasSuffix(element: *mut ServoElementSnapshot,
|
||||
ns: *mut nsIAtom, name: *mut nsIAtom,
|
||||
str: *mut nsIAtom) -> bool;
|
||||
pub fn Gecko_SnapshotClassOrClassList(element: *mut ServoElementSnapshot,
|
||||
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;
|
||||
|
@ -331,6 +365,10 @@ extern "C" {
|
|||
set: *mut RawServoStyleSet);
|
||||
pub fn Servo_RestyleSubtree(node: *mut RawGeckoNode,
|
||||
set: *mut RawServoStyleSet);
|
||||
pub fn Servo_ComputeRestyleHint(element: *mut RawGeckoElement,
|
||||
snapshot: *mut ServoElementSnapshot,
|
||||
set: *mut RawServoStyleSet)
|
||||
-> nsRestyleHint;
|
||||
pub fn Servo_StyleWorkerThreadCount() -> u32;
|
||||
pub fn Gecko_Construct_nsStyleFont(ptr: *mut nsStyleFont);
|
||||
pub fn Gecko_CopyConstruct_nsStyleFont(ptr: *mut nsStyleFont,
|
||||
|
|
|
@ -188,10 +188,20 @@ pub const NS_ERROR_MODULE_BASE_OFFSET: ::std::os::raw::c_uint = 69;
|
|||
pub const MOZ_STRING_WITH_OBSOLETE_API: ::std::os::raw::c_uint = 1;
|
||||
pub const NSID_LENGTH: ::std::os::raw::c_uint = 39;
|
||||
pub const NS_NUMBER_OF_FLAGS_IN_REFCNT: ::std::os::raw::c_uint = 2;
|
||||
pub const _STL_PAIR_H: ::std::os::raw::c_uint = 1;
|
||||
pub const _GLIBCXX_UTILITY: ::std::os::raw::c_uint = 1;
|
||||
pub const __cpp_lib_tuple_element_t: ::std::os::raw::c_uint = 201402;
|
||||
pub const __cpp_lib_tuples_by_type: ::std::os::raw::c_uint = 201304;
|
||||
pub const __cpp_lib_exchange_function: ::std::os::raw::c_uint = 201304;
|
||||
pub const __cpp_lib_integer_sequence: ::std::os::raw::c_uint = 201304;
|
||||
pub const NS_EVENT_STATE_HIGHEST_SERVO_BIT: ::std::os::raw::c_uint = 6;
|
||||
pub const DOM_USER_DATA: ::std::os::raw::c_uint = 1;
|
||||
pub const SMIL_MAPPED_ATTR_ANIMVAL: ::std::os::raw::c_uint = 2;
|
||||
pub const TWIPS_PER_POINT_INT: ::std::os::raw::c_uint = 20;
|
||||
pub const POINTS_PER_INCH_INT: ::std::os::raw::c_uint = 72;
|
||||
pub const NS_ATTRNAME_NODEINFO_BIT: ::std::os::raw::c_uint = 1;
|
||||
pub const NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM: ::std::os::raw::c_uint = 12;
|
||||
pub const NS_ATTRVALUE_INTEGERTYPE_BITS: ::std::os::raw::c_uint = 4;
|
||||
pub const NS_FONT_VARIANT_NORMAL: ::std::os::raw::c_uint = 0;
|
||||
pub const NS_FONT_VARIANT_SMALL_CAPS: ::std::os::raw::c_uint = 1;
|
||||
pub const NS_CORNER_TOP_LEFT_X: ::std::os::raw::c_uint = 0;
|
||||
|
@ -2725,6 +2735,12 @@ impl ::std::clone::Clone for nsIExpandedPrincipal {
|
|||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _Make_integer_sequence<_Tp, _ISeq> {
|
||||
pub _phantom0: ::std::marker::PhantomData<_Tp>,
|
||||
pub _phantom1: ::std::marker::PhantomData<_ISeq>,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct nsIURI {
|
||||
pub _base: nsISupports,
|
||||
|
@ -2766,6 +2782,26 @@ pub enum nsIRequest_nsIRequest_h_unnamed_7 {
|
|||
impl ::std::clone::Clone for nsIRequest {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
/**
|
||||
* EventStates is the class used to represent the event states of nsIContent
|
||||
* instances. These states are calculated by IntrinsicState() and
|
||||
* ContentStatesChanged() has to be called when one of them changes thus
|
||||
* informing the layout/style engine of the change.
|
||||
* Event states are associated with pseudo-classes.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct EventStates {
|
||||
pub mStates: ::std::os::raw::c_ulong,
|
||||
}
|
||||
impl ::std::clone::Clone for EventStates {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_EventStates() {
|
||||
assert_eq!(::std::mem::size_of::<EventStates>() , 8usize);
|
||||
assert_eq!(::std::mem::align_of::<EventStates>() , 8usize);
|
||||
}
|
||||
/**
|
||||
* Enum defining the mode in which a sheet is to be parsed. This is
|
||||
* usually, but not always, the same as the cascade level at which the
|
||||
|
@ -2886,7 +2922,7 @@ fn bindgen_test_layout_nsMutationGuard() {
|
|||
extern "C" {
|
||||
#[link_name = "_ZN15nsMutationGuard11sGenerationE"]
|
||||
pub static mut nsMutationGuard_consts_sGeneration:
|
||||
::std::os::raw::c_ulonglong;
|
||||
::std::os::raw::c_ulong;
|
||||
}
|
||||
pub type Float = f32;
|
||||
#[repr(i8)]
|
||||
|
@ -3262,6 +3298,259 @@ pub enum PlaybackDirection {
|
|||
EndGuard_ = 4,
|
||||
}
|
||||
pub type NativeType = AnimationEffectReadOnly;
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct nsAttrName {
|
||||
pub mBits: usize,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsAttrName() {
|
||||
assert_eq!(::std::mem::size_of::<nsAttrName>() , 8usize);
|
||||
assert_eq!(::std::mem::align_of::<nsAttrName>() , 8usize);
|
||||
}
|
||||
pub type nscolor = u32;
|
||||
#[repr(i8)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
|
||||
pub enum nsStyledElementNotElementCSSInlineStyle { }
|
||||
pub enum MiscContainer { }
|
||||
pub enum ServoDeclarationBlock { }
|
||||
pub enum Declaration { }
|
||||
/**
|
||||
* A class used to construct a nsString from a nsStringBuffer (we might
|
||||
* want to move this to nsString at some point).
|
||||
*
|
||||
* WARNING: Note that nsCheapString doesn't take an explicit length -- it
|
||||
* assumes the string is maximally large, given the nsStringBuffer's storage
|
||||
* size. This means the given string buffer *must* be sized exactly correctly
|
||||
* for the string it contains (including one byte for a null terminator). If
|
||||
* it has any unused storage space, then that will result in bogus characters
|
||||
* at the end of our nsCheapString.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct nsCheapString {
|
||||
pub _base: nsString,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsCheapString() {
|
||||
assert_eq!(::std::mem::size_of::<nsCheapString>() , 16usize);
|
||||
assert_eq!(::std::mem::align_of::<nsCheapString>() , 8usize);
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct nsAttrValue {
|
||||
pub mBits: usize,
|
||||
}
|
||||
pub const eSVGTypesBegin: nsAttrValue_ValueType =
|
||||
nsAttrValue_ValueType::eSVGAngle;
|
||||
pub const eSVGTypesEnd: nsAttrValue_ValueType =
|
||||
nsAttrValue_ValueType::eSVGViewBox;
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsAttrValue_ValueType {
|
||||
eString = 0,
|
||||
eAtom = 2,
|
||||
eInteger = 3,
|
||||
eColor = 7,
|
||||
eEnum = 11,
|
||||
ePercent = 15,
|
||||
eGeckoCSSDeclaration = 16,
|
||||
eServoCSSDeclaration = 17,
|
||||
eURL = 18,
|
||||
eImage = 19,
|
||||
eAtomArray = 20,
|
||||
eDoubleValue = 21,
|
||||
eIntMarginValue = 22,
|
||||
eSVGAngle = 23,
|
||||
eSVGIntegerPair = 24,
|
||||
eSVGLength = 25,
|
||||
eSVGLengthList = 26,
|
||||
eSVGNumberList = 27,
|
||||
eSVGNumberPair = 28,
|
||||
eSVGPathData = 29,
|
||||
eSVGPointList = 30,
|
||||
eSVGPreserveAspectRatio = 31,
|
||||
eSVGStringList = 32,
|
||||
eSVGTransformList = 33,
|
||||
eSVGViewBox = 34,
|
||||
}
|
||||
/**
|
||||
* Structure for a mapping from int (enum) values to strings. When you use
|
||||
* it you generally create an array of them.
|
||||
* Instantiate like this:
|
||||
* EnumTable myTable[] = {
|
||||
* { "string1", 1 },
|
||||
* { "string2", 2 },
|
||||
* { 0 }
|
||||
* }
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct nsAttrValue_EnumTable {
|
||||
/** The string the value maps to */
|
||||
pub tag: *const ::std::os::raw::c_char,
|
||||
/** The enum value that maps to this string */
|
||||
pub value: i16,
|
||||
}
|
||||
impl ::std::clone::Clone for nsAttrValue_EnumTable {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsAttrValue_EnumTable() {
|
||||
assert_eq!(::std::mem::size_of::<nsAttrValue_EnumTable>() , 16usize);
|
||||
assert_eq!(::std::mem::align_of::<nsAttrValue_EnumTable>() , 8usize);
|
||||
}
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsAttrValue_ValueBaseType {
|
||||
eStringBase = 0,
|
||||
eOtherBase = 1,
|
||||
eAtomBase = 2,
|
||||
eIntegerBase = 3,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsAttrValue() {
|
||||
assert_eq!(::std::mem::size_of::<nsAttrValue>() , 8usize);
|
||||
assert_eq!(::std::mem::align_of::<nsAttrValue>() , 8usize);
|
||||
}
|
||||
extern "C" {
|
||||
#[link_name = "_ZN11nsAttrValue15sEnumTableArrayE"]
|
||||
pub static mut nsAttrValue_consts_sEnumTableArray:
|
||||
nsTArray<*const nsAttrValue_EnumTable>;
|
||||
}
|
||||
pub enum nsCSSSelector { }
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsChangeHint {
|
||||
nsChangeHint_RepaintFrame = 1,
|
||||
nsChangeHint_NeedReflow = 2,
|
||||
nsChangeHint_ClearAncestorIntrinsics = 4,
|
||||
nsChangeHint_ClearDescendantIntrinsics = 8,
|
||||
nsChangeHint_NeedDirtyReflow = 16,
|
||||
nsChangeHint_SyncFrameView = 32,
|
||||
nsChangeHint_UpdateCursor = 64,
|
||||
nsChangeHint_UpdateEffects = 128,
|
||||
nsChangeHint_UpdateOpacityLayer = 256,
|
||||
nsChangeHint_UpdateTransformLayer = 512,
|
||||
nsChangeHint_ReconstructFrame = 1024,
|
||||
nsChangeHint_UpdateOverflow = 2048,
|
||||
nsChangeHint_UpdateSubtreeOverflow = 4096,
|
||||
nsChangeHint_UpdatePostTransformOverflow = 8192,
|
||||
nsChangeHint_UpdateParentOverflow = 16384,
|
||||
nsChangeHint_ChildrenOnlyTransform = 32768,
|
||||
nsChangeHint_RecomputePosition = 65536,
|
||||
nsChangeHint_UpdateContainingBlock = 131072,
|
||||
nsChangeHint_BorderStyleNoneChange = 262144,
|
||||
nsChangeHint_UpdateTextPath = 524288,
|
||||
nsChangeHint_SchedulePaint = 1048576,
|
||||
nsChangeHint_NeutralChange = 2097152,
|
||||
nsChangeHint_InvalidateRenderingObservers = 4194304,
|
||||
nsChangeHint_ReflowChangesSizeOrPosition = 8388608,
|
||||
nsChangeHint_UpdateComputedBSize = 16777216,
|
||||
nsChangeHint_UpdateUsesOpacity = 33554432,
|
||||
nsChangeHint_UpdateBackgroundPosition = 67108864,
|
||||
}
|
||||
pub type nsChangeHint_size_t = ::std::os::raw::c_int;
|
||||
/**
|
||||
* |nsRestyleHint| is a bitfield for the result of
|
||||
* |HasStateDependentStyle| and |HasAttributeDependentStyle|. When no
|
||||
* restyling is necessary, use |nsRestyleHint(0)|.
|
||||
*
|
||||
* Without eRestyle_Force or eRestyle_ForceDescendants, the restyling process
|
||||
* can stop processing at a frame when it detects no style changes and it is
|
||||
* known that the styles of the subtree beneath it will not change, leaving
|
||||
* the old style context on the frame. eRestyle_Force can be used to skip this
|
||||
* optimization on a frame, and to force its new style context to be used.
|
||||
*
|
||||
* Similarly, eRestyle_ForceDescendants will cause the frame and all of its
|
||||
* descendants to be traversed and for the new style contexts that are created
|
||||
* to be set on the frames.
|
||||
*
|
||||
* NOTE: When adding new restyle hints, please also add them to
|
||||
* RestyleManager::RestyleHintToString.
|
||||
*/
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsRestyleHint {
|
||||
eRestyle_Self = 1,
|
||||
eRestyle_SomeDescendants = 2,
|
||||
eRestyle_Subtree = 4,
|
||||
eRestyle_LaterSiblings = 8,
|
||||
eRestyle_CSSTransitions = 16,
|
||||
eRestyle_CSSAnimations = 32,
|
||||
eRestyle_SVGAttrAnimations = 64,
|
||||
eRestyle_StyleAttribute = 128,
|
||||
eRestyle_StyleAttribute_Animations = 256,
|
||||
eRestyle_Force = 512,
|
||||
eRestyle_ForceDescendants = 1024,
|
||||
eRestyle_AllHintsWithAnimations = 368,
|
||||
}
|
||||
pub type nsRestyleHint_size_t = ::std::os::raw::c_int;
|
||||
/**
|
||||
* Additional data used in conjunction with an nsRestyleHint to control the
|
||||
* restyle process.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct RestyleHintData {
|
||||
pub mSelectorsForDescendants: nsTArray<*mut nsCSSSelector>,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_RestyleHintData() {
|
||||
assert_eq!(::std::mem::size_of::<RestyleHintData>() , 8usize);
|
||||
assert_eq!(::std::mem::align_of::<RestyleHintData>() , 8usize);
|
||||
}
|
||||
/**
|
||||
* A structure representing a single attribute name and value.
|
||||
*
|
||||
* This is pretty similar to the private nsAttrAndChildArray::InternalAttr.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct ServoAttrSnapshot {
|
||||
pub mName: nsAttrName,
|
||||
pub mValue: nsAttrValue,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_ServoAttrSnapshot() {
|
||||
assert_eq!(::std::mem::size_of::<ServoAttrSnapshot>() , 16usize);
|
||||
assert_eq!(::std::mem::align_of::<ServoAttrSnapshot>() , 8usize);
|
||||
}
|
||||
/**
|
||||
* A bitflags enum class used to determine what data does a ServoElementSnapshot
|
||||
* contains.
|
||||
*/
|
||||
#[repr(i8)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum ServoElementSnapshotFlags {
|
||||
State = 1,
|
||||
Attributes = 2,
|
||||
HTMLElementInHTMLDocument = 4,
|
||||
All = 7,
|
||||
}
|
||||
/**
|
||||
* This class holds all non-tree-structural state of an element that might be
|
||||
* used for selector matching eventually.
|
||||
*
|
||||
* This means the attributes, and the element state, such as :hover, :active,
|
||||
* etc...
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct ServoElementSnapshot {
|
||||
pub mContains: ServoElementSnapshotFlags,
|
||||
pub mAttrs: nsTArray<ServoAttrSnapshot>,
|
||||
pub mState: ::std::os::raw::c_uchar,
|
||||
pub mExplicitRestyleHint: nsRestyleHint,
|
||||
pub mExplicitChangeHint: nsChangeHint,
|
||||
pub mIsHTMLElementInHTMLDocument: bool,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_ServoElementSnapshot() {
|
||||
assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 32usize);
|
||||
assert_eq!(::std::mem::align_of::<ServoElementSnapshot>() , 8usize);
|
||||
}
|
||||
pub enum ErrorReporter { }
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
|
@ -4136,10 +4425,6 @@ pub enum nsCSSPropertyLogicalGroup {
|
|||
eCSSPropertyLogicalGroup_Size = 8,
|
||||
eCSSPropertyLogicalGroup_COUNT = 9,
|
||||
}
|
||||
pub type nscolor = u32;
|
||||
#[repr(i8)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
|
||||
/**
|
||||
* Class to safely handle main-thread-only pointers off the main thread.
|
||||
*
|
||||
|
|
|
@ -188,10 +188,20 @@ pub const NS_ERROR_MODULE_BASE_OFFSET: ::std::os::raw::c_uint = 69;
|
|||
pub const MOZ_STRING_WITH_OBSOLETE_API: ::std::os::raw::c_uint = 1;
|
||||
pub const NSID_LENGTH: ::std::os::raw::c_uint = 39;
|
||||
pub const NS_NUMBER_OF_FLAGS_IN_REFCNT: ::std::os::raw::c_uint = 2;
|
||||
pub const _STL_PAIR_H: ::std::os::raw::c_uint = 1;
|
||||
pub const _GLIBCXX_UTILITY: ::std::os::raw::c_uint = 1;
|
||||
pub const __cpp_lib_tuple_element_t: ::std::os::raw::c_uint = 201402;
|
||||
pub const __cpp_lib_tuples_by_type: ::std::os::raw::c_uint = 201304;
|
||||
pub const __cpp_lib_exchange_function: ::std::os::raw::c_uint = 201304;
|
||||
pub const __cpp_lib_integer_sequence: ::std::os::raw::c_uint = 201304;
|
||||
pub const NS_EVENT_STATE_HIGHEST_SERVO_BIT: ::std::os::raw::c_uint = 6;
|
||||
pub const DOM_USER_DATA: ::std::os::raw::c_uint = 1;
|
||||
pub const SMIL_MAPPED_ATTR_ANIMVAL: ::std::os::raw::c_uint = 2;
|
||||
pub const TWIPS_PER_POINT_INT: ::std::os::raw::c_uint = 20;
|
||||
pub const POINTS_PER_INCH_INT: ::std::os::raw::c_uint = 72;
|
||||
pub const NS_ATTRNAME_NODEINFO_BIT: ::std::os::raw::c_uint = 1;
|
||||
pub const NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM: ::std::os::raw::c_uint = 12;
|
||||
pub const NS_ATTRVALUE_INTEGERTYPE_BITS: ::std::os::raw::c_uint = 4;
|
||||
pub const NS_FONT_VARIANT_NORMAL: ::std::os::raw::c_uint = 0;
|
||||
pub const NS_FONT_VARIANT_SMALL_CAPS: ::std::os::raw::c_uint = 1;
|
||||
pub const NS_CORNER_TOP_LEFT_X: ::std::os::raw::c_uint = 0;
|
||||
|
@ -2704,6 +2714,12 @@ impl ::std::clone::Clone for nsIExpandedPrincipal {
|
|||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _Make_integer_sequence<_Tp, _ISeq> {
|
||||
pub _phantom0: ::std::marker::PhantomData<_Tp>,
|
||||
pub _phantom1: ::std::marker::PhantomData<_ISeq>,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct nsIURI {
|
||||
pub _base: nsISupports,
|
||||
|
@ -2745,6 +2761,26 @@ pub enum nsIRequest_nsIRequest_h_unnamed_7 {
|
|||
impl ::std::clone::Clone for nsIRequest {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
/**
|
||||
* EventStates is the class used to represent the event states of nsIContent
|
||||
* instances. These states are calculated by IntrinsicState() and
|
||||
* ContentStatesChanged() has to be called when one of them changes thus
|
||||
* informing the layout/style engine of the change.
|
||||
* Event states are associated with pseudo-classes.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct EventStates {
|
||||
pub mStates: ::std::os::raw::c_ulong,
|
||||
}
|
||||
impl ::std::clone::Clone for EventStates {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_EventStates() {
|
||||
assert_eq!(::std::mem::size_of::<EventStates>() , 8usize);
|
||||
assert_eq!(::std::mem::align_of::<EventStates>() , 8usize);
|
||||
}
|
||||
/**
|
||||
* Enum defining the mode in which a sheet is to be parsed. This is
|
||||
* usually, but not always, the same as the cascade level at which the
|
||||
|
@ -2865,7 +2901,7 @@ fn bindgen_test_layout_nsMutationGuard() {
|
|||
extern "C" {
|
||||
#[link_name = "_ZN15nsMutationGuard11sGenerationE"]
|
||||
pub static mut nsMutationGuard_consts_sGeneration:
|
||||
::std::os::raw::c_ulonglong;
|
||||
::std::os::raw::c_ulong;
|
||||
}
|
||||
pub type Float = f32;
|
||||
#[repr(i8)]
|
||||
|
@ -3241,6 +3277,259 @@ pub enum PlaybackDirection {
|
|||
EndGuard_ = 4,
|
||||
}
|
||||
pub type NativeType = AnimationEffectReadOnly;
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct nsAttrName {
|
||||
pub mBits: usize,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsAttrName() {
|
||||
assert_eq!(::std::mem::size_of::<nsAttrName>() , 8usize);
|
||||
assert_eq!(::std::mem::align_of::<nsAttrName>() , 8usize);
|
||||
}
|
||||
pub type nscolor = u32;
|
||||
#[repr(i8)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
|
||||
pub enum nsStyledElementNotElementCSSInlineStyle { }
|
||||
pub enum MiscContainer { }
|
||||
pub enum ServoDeclarationBlock { }
|
||||
pub enum Declaration { }
|
||||
/**
|
||||
* A class used to construct a nsString from a nsStringBuffer (we might
|
||||
* want to move this to nsString at some point).
|
||||
*
|
||||
* WARNING: Note that nsCheapString doesn't take an explicit length -- it
|
||||
* assumes the string is maximally large, given the nsStringBuffer's storage
|
||||
* size. This means the given string buffer *must* be sized exactly correctly
|
||||
* for the string it contains (including one byte for a null terminator). If
|
||||
* it has any unused storage space, then that will result in bogus characters
|
||||
* at the end of our nsCheapString.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct nsCheapString {
|
||||
pub _base: nsString,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsCheapString() {
|
||||
assert_eq!(::std::mem::size_of::<nsCheapString>() , 16usize);
|
||||
assert_eq!(::std::mem::align_of::<nsCheapString>() , 8usize);
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct nsAttrValue {
|
||||
pub mBits: usize,
|
||||
}
|
||||
pub const eSVGTypesBegin: nsAttrValue_ValueType =
|
||||
nsAttrValue_ValueType::eSVGAngle;
|
||||
pub const eSVGTypesEnd: nsAttrValue_ValueType =
|
||||
nsAttrValue_ValueType::eSVGViewBox;
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsAttrValue_ValueType {
|
||||
eString = 0,
|
||||
eAtom = 2,
|
||||
eInteger = 3,
|
||||
eColor = 7,
|
||||
eEnum = 11,
|
||||
ePercent = 15,
|
||||
eGeckoCSSDeclaration = 16,
|
||||
eServoCSSDeclaration = 17,
|
||||
eURL = 18,
|
||||
eImage = 19,
|
||||
eAtomArray = 20,
|
||||
eDoubleValue = 21,
|
||||
eIntMarginValue = 22,
|
||||
eSVGAngle = 23,
|
||||
eSVGIntegerPair = 24,
|
||||
eSVGLength = 25,
|
||||
eSVGLengthList = 26,
|
||||
eSVGNumberList = 27,
|
||||
eSVGNumberPair = 28,
|
||||
eSVGPathData = 29,
|
||||
eSVGPointList = 30,
|
||||
eSVGPreserveAspectRatio = 31,
|
||||
eSVGStringList = 32,
|
||||
eSVGTransformList = 33,
|
||||
eSVGViewBox = 34,
|
||||
}
|
||||
/**
|
||||
* Structure for a mapping from int (enum) values to strings. When you use
|
||||
* it you generally create an array of them.
|
||||
* Instantiate like this:
|
||||
* EnumTable myTable[] = {
|
||||
* { "string1", 1 },
|
||||
* { "string2", 2 },
|
||||
* { 0 }
|
||||
* }
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct nsAttrValue_EnumTable {
|
||||
/** The string the value maps to */
|
||||
pub tag: *const ::std::os::raw::c_char,
|
||||
/** The enum value that maps to this string */
|
||||
pub value: i16,
|
||||
}
|
||||
impl ::std::clone::Clone for nsAttrValue_EnumTable {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsAttrValue_EnumTable() {
|
||||
assert_eq!(::std::mem::size_of::<nsAttrValue_EnumTable>() , 16usize);
|
||||
assert_eq!(::std::mem::align_of::<nsAttrValue_EnumTable>() , 8usize);
|
||||
}
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsAttrValue_ValueBaseType {
|
||||
eStringBase = 0,
|
||||
eOtherBase = 1,
|
||||
eAtomBase = 2,
|
||||
eIntegerBase = 3,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsAttrValue() {
|
||||
assert_eq!(::std::mem::size_of::<nsAttrValue>() , 8usize);
|
||||
assert_eq!(::std::mem::align_of::<nsAttrValue>() , 8usize);
|
||||
}
|
||||
extern "C" {
|
||||
#[link_name = "_ZN11nsAttrValue15sEnumTableArrayE"]
|
||||
pub static mut nsAttrValue_consts_sEnumTableArray:
|
||||
nsTArray<*const nsAttrValue_EnumTable>;
|
||||
}
|
||||
pub enum nsCSSSelector { }
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsChangeHint {
|
||||
nsChangeHint_RepaintFrame = 1,
|
||||
nsChangeHint_NeedReflow = 2,
|
||||
nsChangeHint_ClearAncestorIntrinsics = 4,
|
||||
nsChangeHint_ClearDescendantIntrinsics = 8,
|
||||
nsChangeHint_NeedDirtyReflow = 16,
|
||||
nsChangeHint_SyncFrameView = 32,
|
||||
nsChangeHint_UpdateCursor = 64,
|
||||
nsChangeHint_UpdateEffects = 128,
|
||||
nsChangeHint_UpdateOpacityLayer = 256,
|
||||
nsChangeHint_UpdateTransformLayer = 512,
|
||||
nsChangeHint_ReconstructFrame = 1024,
|
||||
nsChangeHint_UpdateOverflow = 2048,
|
||||
nsChangeHint_UpdateSubtreeOverflow = 4096,
|
||||
nsChangeHint_UpdatePostTransformOverflow = 8192,
|
||||
nsChangeHint_UpdateParentOverflow = 16384,
|
||||
nsChangeHint_ChildrenOnlyTransform = 32768,
|
||||
nsChangeHint_RecomputePosition = 65536,
|
||||
nsChangeHint_UpdateContainingBlock = 131072,
|
||||
nsChangeHint_BorderStyleNoneChange = 262144,
|
||||
nsChangeHint_UpdateTextPath = 524288,
|
||||
nsChangeHint_SchedulePaint = 1048576,
|
||||
nsChangeHint_NeutralChange = 2097152,
|
||||
nsChangeHint_InvalidateRenderingObservers = 4194304,
|
||||
nsChangeHint_ReflowChangesSizeOrPosition = 8388608,
|
||||
nsChangeHint_UpdateComputedBSize = 16777216,
|
||||
nsChangeHint_UpdateUsesOpacity = 33554432,
|
||||
nsChangeHint_UpdateBackgroundPosition = 67108864,
|
||||
}
|
||||
pub type nsChangeHint_size_t = ::std::os::raw::c_int;
|
||||
/**
|
||||
* |nsRestyleHint| is a bitfield for the result of
|
||||
* |HasStateDependentStyle| and |HasAttributeDependentStyle|. When no
|
||||
* restyling is necessary, use |nsRestyleHint(0)|.
|
||||
*
|
||||
* Without eRestyle_Force or eRestyle_ForceDescendants, the restyling process
|
||||
* can stop processing at a frame when it detects no style changes and it is
|
||||
* known that the styles of the subtree beneath it will not change, leaving
|
||||
* the old style context on the frame. eRestyle_Force can be used to skip this
|
||||
* optimization on a frame, and to force its new style context to be used.
|
||||
*
|
||||
* Similarly, eRestyle_ForceDescendants will cause the frame and all of its
|
||||
* descendants to be traversed and for the new style contexts that are created
|
||||
* to be set on the frames.
|
||||
*
|
||||
* NOTE: When adding new restyle hints, please also add them to
|
||||
* RestyleManager::RestyleHintToString.
|
||||
*/
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsRestyleHint {
|
||||
eRestyle_Self = 1,
|
||||
eRestyle_SomeDescendants = 2,
|
||||
eRestyle_Subtree = 4,
|
||||
eRestyle_LaterSiblings = 8,
|
||||
eRestyle_CSSTransitions = 16,
|
||||
eRestyle_CSSAnimations = 32,
|
||||
eRestyle_SVGAttrAnimations = 64,
|
||||
eRestyle_StyleAttribute = 128,
|
||||
eRestyle_StyleAttribute_Animations = 256,
|
||||
eRestyle_Force = 512,
|
||||
eRestyle_ForceDescendants = 1024,
|
||||
eRestyle_AllHintsWithAnimations = 368,
|
||||
}
|
||||
pub type nsRestyleHint_size_t = ::std::os::raw::c_int;
|
||||
/**
|
||||
* Additional data used in conjunction with an nsRestyleHint to control the
|
||||
* restyle process.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct RestyleHintData {
|
||||
pub mSelectorsForDescendants: nsTArray<*mut nsCSSSelector>,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_RestyleHintData() {
|
||||
assert_eq!(::std::mem::size_of::<RestyleHintData>() , 8usize);
|
||||
assert_eq!(::std::mem::align_of::<RestyleHintData>() , 8usize);
|
||||
}
|
||||
/**
|
||||
* A structure representing a single attribute name and value.
|
||||
*
|
||||
* This is pretty similar to the private nsAttrAndChildArray::InternalAttr.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct ServoAttrSnapshot {
|
||||
pub mName: nsAttrName,
|
||||
pub mValue: nsAttrValue,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_ServoAttrSnapshot() {
|
||||
assert_eq!(::std::mem::size_of::<ServoAttrSnapshot>() , 16usize);
|
||||
assert_eq!(::std::mem::align_of::<ServoAttrSnapshot>() , 8usize);
|
||||
}
|
||||
/**
|
||||
* A bitflags enum class used to determine what data does a ServoElementSnapshot
|
||||
* contains.
|
||||
*/
|
||||
#[repr(i8)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum ServoElementSnapshotFlags {
|
||||
State = 1,
|
||||
Attributes = 2,
|
||||
HTMLElementInHTMLDocument = 4,
|
||||
All = 7,
|
||||
}
|
||||
/**
|
||||
* This class holds all non-tree-structural state of an element that might be
|
||||
* used for selector matching eventually.
|
||||
*
|
||||
* This means the attributes, and the element state, such as :hover, :active,
|
||||
* etc...
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct ServoElementSnapshot {
|
||||
pub mContains: ServoElementSnapshotFlags,
|
||||
pub mAttrs: nsTArray<ServoAttrSnapshot>,
|
||||
pub mState: ::std::os::raw::c_uchar,
|
||||
pub mExplicitRestyleHint: nsRestyleHint,
|
||||
pub mExplicitChangeHint: nsChangeHint,
|
||||
pub mIsHTMLElementInHTMLDocument: bool,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_ServoElementSnapshot() {
|
||||
assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 32usize);
|
||||
assert_eq!(::std::mem::align_of::<ServoElementSnapshot>() , 8usize);
|
||||
}
|
||||
pub enum ErrorReporter { }
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
|
@ -4115,10 +4404,6 @@ pub enum nsCSSPropertyLogicalGroup {
|
|||
eCSSPropertyLogicalGroup_Size = 8,
|
||||
eCSSPropertyLogicalGroup_COUNT = 9,
|
||||
}
|
||||
pub type nscolor = u32;
|
||||
#[repr(i8)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
|
||||
/**
|
||||
* Class to safely handle main-thread-only pointers off the main thread.
|
||||
*
|
||||
|
|
|
@ -45,6 +45,7 @@ COMPILATION_TARGETS = {
|
|||
"includes": [
|
||||
"{}/dist/include/nsThemeConstants.h",
|
||||
"{}/dist/include/mozilla/dom/AnimationEffectReadOnlyBinding.h",
|
||||
"{}/dist/include/mozilla/ServoElementSnapshot.h",
|
||||
],
|
||||
"files": [
|
||||
"{}/dist/include/nsStyleStruct.h",
|
||||
|
@ -74,6 +75,8 @@ COMPILATION_TARGETS = {
|
|||
"nsDataHashtable.h", "nsCSSScanner.h", "nsTArray",
|
||||
"pair", "SheetParsingMode.h", "StaticPtr.h", "nsProxyRelease.h",
|
||||
"mozilla/dom/AnimationEffectReadOnlyBinding.h",
|
||||
"nsChangeHint.h", "ServoElementSnapshot.h",
|
||||
"EventStates.h", "nsAttrValue.h", "nsAttrName.h",
|
||||
"/Types.h", # <- Disallow UnionTypes.h
|
||||
"/utility", # <- Disallow xutility
|
||||
"nsINode.h", # <- For `NodeFlags`.
|
||||
|
@ -123,7 +126,7 @@ COMPILATION_TARGETS = {
|
|||
"nsStyleCoord", "nsStyleGradientStop", "nsStyleImageLayers",
|
||||
"nsStyleImageLayers::Layer", "nsStyleImageLayers::LayerType",
|
||||
"nsStyleUnit", "nsStyleUnion", "nsStyleCoord::CalcValue",
|
||||
"nsStyleCoord::Calc",
|
||||
"nsStyleCoord::Calc", "nsRestyleHint", "ServoElementSnapshot",
|
||||
|
||||
"SheetParsingMode", "nsMainThreadPtrHandle",
|
||||
"nsMainThreadPtrHolder", "nscolor", "nsFont", "FontFamilyList",
|
||||
|
|
|
@ -13,7 +13,10 @@ use gecko_bindings::bindings::{RawServoStyleSet, RawServoStyleSheet, ServoComput
|
|||
use gecko_bindings::bindings::{ServoDeclarationBlock, ServoNodeData, ThreadSafePrincipalHolder};
|
||||
use gecko_bindings::bindings::{ThreadSafeURIHolder, nsHTMLCSSStyleSheet};
|
||||
use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||
use gecko_bindings::structs::ServoElementSnapshot;
|
||||
use gecko_bindings::structs::nsRestyleHint;
|
||||
use gecko_bindings::structs::{SheetParsingMode, nsIAtom};
|
||||
use snapshot::GeckoElementSnapshot;
|
||||
use std::mem::transmute;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
@ -439,3 +442,22 @@ pub extern "C" fn Servo_CSSSupports(property: *const u8, property_length: u32,
|
|||
Err(()) => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_ComputeRestyleHint(element: *mut RawGeckoElement,
|
||||
snapshot: *mut ServoElementSnapshot,
|
||||
raw_data: *mut RawServoStyleSet) -> nsRestyleHint {
|
||||
let per_doc_data = unsafe { &mut *(raw_data as *mut PerDocumentStyleData) };
|
||||
let snapshot = unsafe { GeckoElementSnapshot::from_raw(snapshot) };
|
||||
let element = unsafe { GeckoElement::from_raw(element) };
|
||||
|
||||
// NB: This involves an FFI call, we can get rid of it easily if needed.
|
||||
let current_state = element.get_state();
|
||||
|
||||
let hint = per_doc_data.stylist
|
||||
.compute_restyle_hint(&element, &snapshot,
|
||||
current_state);
|
||||
|
||||
// NB: Binary representations match.
|
||||
unsafe { transmute(hint.bits() as u32) }
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ extern crate util;
|
|||
|
||||
mod context;
|
||||
mod data;
|
||||
mod snapshot;
|
||||
mod snapshot_helpers;
|
||||
#[allow(non_snake_case)]
|
||||
pub mod glue;
|
||||
mod traversal;
|
||||
|
|
149
ports/geckolib/snapshot.rs
Normal file
149
ports/geckolib/snapshot.rs
Normal file
|
@ -0,0 +1,149 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
use gecko_bindings::bindings;
|
||||
use gecko_bindings::structs::ServoElementSnapshot;
|
||||
use gecko_bindings::structs::ServoElementSnapshotFlags as Flags;
|
||||
use selectors::parser::AttrSelector;
|
||||
use snapshot_helpers;
|
||||
use string_cache::Atom;
|
||||
use style::element_state::ElementState;
|
||||
use style::restyle_hints::ElementSnapshot;
|
||||
use wrapper::AttrSelectorHelpers;
|
||||
|
||||
// NB: This is sound, in some sense, because during computation of restyle hints
|
||||
// the snapshot is kept alive by the modified elements table.
|
||||
#[derive(Debug)]
|
||||
pub struct GeckoElementSnapshot(*mut ServoElementSnapshot);
|
||||
|
||||
impl GeckoElementSnapshot {
|
||||
#[inline]
|
||||
pub unsafe fn from_raw(raw: *mut ServoElementSnapshot) -> Self {
|
||||
GeckoElementSnapshot(raw)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_html_element_in_html_document(&self) -> bool {
|
||||
unsafe { (*self.0).mIsHTMLElementInHTMLDocument }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_any(&self, flags: Flags) -> bool {
|
||||
unsafe { ((*self.0).mContains as u8 & flags as u8) != 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl ::selectors::MatchAttr for GeckoElementSnapshot {
|
||||
type AttrString = Atom;
|
||||
|
||||
fn match_attr_has(&self, attr: &AttrSelector) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotHasAttr(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()))
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_equals(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrEquals(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr(),
|
||||
/* ignoreCase = */ false)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrEquals(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr(),
|
||||
/* ignoreCase = */ true)
|
||||
}
|
||||
}
|
||||
fn match_attr_includes(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrIncludes(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_dash(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrDashEquals(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_prefix(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrHasPrefix(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_substring(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrHasSubstring(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_suffix(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrHasSuffix(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementSnapshot for GeckoElementSnapshot {
|
||||
fn state(&self) -> Option<ElementState> {
|
||||
if self.has_any(Flags::State) {
|
||||
Some(ElementState::from_bits_truncate(unsafe { (*self.0).mState as u16 }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_attrs(&self) -> bool {
|
||||
self.has_any(Flags::Attributes)
|
||||
}
|
||||
|
||||
fn id_attr(&self) -> Option<Atom> {
|
||||
let ptr = unsafe {
|
||||
bindings::Gecko_SnapshotAtomAttrValue(self.0,
|
||||
atom!("id").as_ptr())
|
||||
};
|
||||
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Atom::from(ptr))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: share logic with Element::{has_class, each_class}?
|
||||
fn has_class(&self, name: &Atom) -> bool {
|
||||
snapshot_helpers::has_class(self.0,
|
||||
name,
|
||||
bindings::Gecko_SnapshotClassOrClassList)
|
||||
}
|
||||
|
||||
fn each_class<F>(&self, callback: F)
|
||||
where F: FnMut(&Atom)
|
||||
{
|
||||
snapshot_helpers::each_class(self.0,
|
||||
callback,
|
||||
bindings::Gecko_SnapshotClassOrClassList)
|
||||
}
|
||||
}
|
53
ports/geckolib/snapshot_helpers.rs
Normal file
53
ports/geckolib/snapshot_helpers.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Element an snapshot common logic.
|
||||
|
||||
use gecko_bindings::structs::nsIAtom;
|
||||
use std::{ptr, slice};
|
||||
use string_cache::Atom;
|
||||
|
||||
pub type ClassOrClassList<T> = unsafe extern fn (T, *mut *mut nsIAtom, *mut *mut *mut nsIAtom) -> u32;
|
||||
|
||||
pub fn has_class<T>(item: T,
|
||||
name: &Atom,
|
||||
getter: ClassOrClassList<T>) -> bool
|
||||
{
|
||||
unsafe {
|
||||
let mut class: *mut nsIAtom = ptr::null_mut();
|
||||
let mut list: *mut *mut nsIAtom = ptr::null_mut();
|
||||
let length = getter(item, &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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn each_class<F, T>(item: T,
|
||||
mut callback: F,
|
||||
getter: ClassOrClassList<T>)
|
||||
where F: FnMut(&Atom)
|
||||
{
|
||||
unsafe {
|
||||
let mut class: *mut nsIAtom = ptr::null_mut();
|
||||
let mut list: *mut *mut nsIAtom = ptr::null_mut();
|
||||
let length = getter(item, &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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue